Merge pull request #7394 from Staars/nrf24_PR

BLE-bridge for certain Mijia-Bluetooth-sensors via NRF24L01
This commit is contained in:
Theo Arends 2020-01-02 16:28:22 +01:00 committed by GitHub
commit 5489c91172
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
146 changed files with 26822 additions and 4 deletions

26
lib/RF24/.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
*.bak
*.o
.*.swp
*.orig
.swp
docs/
output/
ojam/
out/
16000000/
8000000/
out_native/
version.h
Session.vim
*.so
*.so.*
*.dylib
*.dylib.*
.DS_Store
Makefile.inc
utility/includes.h
examples_linux/*
!examples_linux/**/
!examples_linux/*.*
.directory
.idea

1
lib/RF24/CONTRIBUTING.md Normal file
View File

@ -0,0 +1 @@
Try your best to follow the NASA C style http://homepages.inf.ed.ac.uk/dts/pm/Papers/nasa-c-style.pdf

2462
lib/RF24/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

339
lib/RF24/LICENSE Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

126
lib/RF24/Makefile Normal file
View File

@ -0,0 +1,126 @@
#############################################################################
#
# Makefile for librf24
#
# License: GPL (General Public License)
# Author: Charles-Henri Hallard
# Date: 2013/03/13
#
# Description:
# ------------
# use make all and make install to install the library
#
CONFIG_FILE=Makefile.inc
REMOTE_ERROR="[ERROR] Remote machine not configured. Run configure with respective arguments."
include $(CONFIG_FILE)
# Objects to compile
OBJECTS=RF24.o
ifeq ($(DRIVER), MRAA)
OBJECTS+=spi.o gpio.o compatibility.o
else ifeq ($(DRIVER), RPi)
OBJECTS+=spi.o bcm2835.o interrupt.o
else ifeq ($(DRIVER), SPIDEV)
OBJECTS+=spi.o gpio.o compatibility.o interrupt.o
else ifeq ($(DRIVER), wiringPi)
OBJECTS+=spi.o
endif
# make all
# reinstall the library after each recompilation
all: $(LIBNAME)
# Make the library
$(LIBNAME): $(OBJECTS)
@echo "[Linking]"
$(CC) $(SHARED_LINKER_FLAGS) $(CFLAGS) -o $(LIBNAME) $^ $(SHARED_LINKER_LIBS)
# Library parts
RF24.o: RF24.cpp
$(CXX) -fPIC $(CFLAGS) -c $^
bcm2835.o: $(DRIVER_DIR)/bcm2835.c
$(CC) -fPIC $(CFLAGS) -c $^
spi.o: $(DRIVER_DIR)/spi.cpp
$(CXX) -fPIC $(CFLAGS) -c $^
compatibility.o: $(DRIVER_DIR)/compatibility.c
$(CC) -fPIC $(CFLAGS) -c $(DRIVER_DIR)/compatibility.c
gpio.o: $(DRIVER_DIR)/gpio.cpp
$(CXX) -fPIC $(CFLAGS) -c $(DRIVER_DIR)/gpio.cpp
interrupt.o: $(DRIVER_DIR)/interrupt.c
$(CXX) -fPIC $(CFLAGS) -c $(DRIVER_DIR)/interrupt.c
# clear configuration files
cleanconfig:
@echo "[Cleaning configuration]"
rm -rf $(CONFIG_FILE) utility/includes.h
# clear build files
clean:
@echo "[Cleaning]"
rm -rf *.o $(LIBNAME)
$(CONFIG_FILE):
@echo "[Running configure]"
@./configure --no-clean
install: all install-libs install-headers
upload: all upload-libs upload-headers
# Install the library to LIBPATH
install-libs:
@echo "[Installing Libs to $(LIB_DIR)]"
@if ( test ! -d $(LIB_DIR) ); then mkdir -p $(LIB_DIR); fi
@install -m 0755 $(LIBNAME) $(LIB_DIR)
@orig=$(LIBNAME) && \
for sl in $(LIBSYMLINKS); do \
ln -sf $(LIB_DIR)/$${orig} $(LIB_DIR)/$${sl}; \
orig=$${sl}; \
done && \
if [ "$(LIBDEPRECATE)" ]; then ln -sf $(LIB_DIR)/$${orig} $(LIB_DIR)/$(LIBDEPRECATE); fi
ifneq ($(LDCONFIG),)
@$(LDCONFIG)
endif
upload-libs:
@echo "[Uploading Libs to $(REMOTE):$(REMOTE_LIB_DIR)]"
ifeq ($(REMOTE),)
@echo "$(REMOTE_ERROR)"
@exit 1
endif
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "mkdir -p $(REMOTE_LIB_DIR)"
@scp -q -P $(REMOTE_PORT) $(LIBNAME) $(REMOTE):/tmp
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "sudo install -m 0755 /tmp/$(LIBNAME) $(REMOTE_LIB_DIR) &&" \
" orig=$(LIBNAME) && for sl in $(LIBSYMLINKS); do sudo ln -sf $(REMOTE_LIB_DIR)/\$${orig} $(REMOTE_LIB_DIR)/\$${sl}; orig=\$${sl}; done &&" \
" if [ "$(LIBDEPRECATE)" ]; then sudo ln -sf $(REMOTE_LIB_DIR)/\$${orig} $(REMOTE_LIB_DIR)/$(LIBDEPRECATE); fi &&" \
" rm /tmp/$(LIBNAME)"
ifneq ($(REMOTE_LDCONFIG),)
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "sudo $(REMOTE_LDCONFIG)"
endif
install-headers:
@echo "[Installing Headers to $(HEADER_DIR)]"
@mkdir -p $(HEADER_DIR)/$(DRIVER_DIR)
@install -m 0644 *.h $(HEADER_DIR)
@install -m 0644 $(DRIVER_DIR)/*.h $(HEADER_DIR)/$(DRIVER_DIR)
@install -m 0644 $(ARCH_DIR)/*.h $(HEADER_DIR)/$(ARCH_DIR)
upload-headers:
@echo "[Uploading Headers to $(REMOTE):$(REMOTE_HEADER_DIR)]"
ifeq ($(REMOTE),)
@echo "$(REMOTE_ERROR)"
@exit 1
endif
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "sudo mkdir -p $(REMOTE_HEADER_DIR)/$(DRIVER_DIR)"
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "mkdir -p /tmp/RF24 && rm -rf /tmp/RF24/*"
@rsync -a --include="*.h" --include="*/" --exclude="*" -e "ssh -p $(REMOTE_PORT)" . $(REMOTE):/tmp/RF24
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "sudo install -m 0644 /tmp/RF24/*.h $(REMOTE_HEADER_DIR)"
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "sudo install -m 0644 /tmp/RF24/$(DRIVER_DIR)/*.h $(REMOTE_HEADER_DIR)/$(DRIVER_DIR)"
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "sudo install -m 0644 /tmp/RF24/$(ARCH_DIR)/*.h $(REMOTE_HEADER_DIR)/$(ARCH_DIR)"
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "rm -rf /tmp/RF24"

2
lib/RF24/README.md Normal file
View File

@ -0,0 +1,2 @@
**See http://tmrh20.github.io/RF24 for all documentation**

1638
lib/RF24/RF24.cpp Normal file

File diff suppressed because it is too large Load Diff

2030
lib/RF24/RF24.h Normal file

File diff suppressed because it is too large Load Diff

166
lib/RF24/RF24_config.h Normal file
View File

@ -0,0 +1,166 @@
/*
Copyright (C)
2011 J. Coliz <maniacbug@ymail.com>
2015-2019 TMRh20
2015 spaniakos <spaniakos@gmail.com>
2015 nerdralph
2015 zador-blood-stained
2016 akatran
2017-2019 Avamander <avamander@gmail.com>
2019 IkpeohaGodson
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.
*/
#ifndef __RF24_CONFIG_H__
#define __RF24_CONFIG_H__
/*** USER DEFINES: ***/
#define FAILURE_HANDLING
//#define SERIAL_DEBUG
//#define MINIMAL
//#define SPI_UART // Requires library from https://github.com/TMRh20/Sketches/tree/master/SPI_UART
//#define SOFTSPI // Requires library from https://github.com/greiman/DigitalIO
/**********************/
#define rf24_max(a,b) (a>b?a:b)
#define rf24_min(a,b) (a<b?a:b)
#if defined (SPI_HAS_TRANSACTION) && !defined (SPI_UART) && !defined (SOFTSPI)
#define RF24_SPI_TRANSACTIONS
#endif // defined (SPI_HAS_TRANSACTION) && !defined (SPI_UART) && !defined (SOFTSPI)
//ATXMega
#if defined (__AVR_ATxmega64D3__) || defined (__AVR_ATxmega128D3__) || defined (__AVR_ATxmega192D3__) || defined (__AVR_ATxmega256D3__) || defined (__AVR_ATxmega384D3__) // In order to be available both in Windows and Linux this should take presence here.
#define XMEGA
#define XMEGA_D3
#include "utility/ATXMegaD3/RF24_arch_config.h"
#elif ( !defined (ARDUINO) ) // Any non-arduino device is handled via configure/Makefile
// The configure script detects device and copies the correct includes.h file to /utility/includes.h
// This behavior can be overridden by calling configure with respective parameters
// The includes.h file defines either RF24_RPi, MRAA, LITTLEWIRE or RF24_SPIDEV and includes the correct RF24_arch_config.h file
#include "utility/includes.h"
//ATTiny
#elif defined (__AVR_ATtiny25__) || defined (__AVR_ATtiny45__) || defined (__AVR_ATtiny85__) || defined (__AVR_ATtiny24__) || defined (__AVR_ATtiny44__) || defined (__AVR_ATtiny84__) || defined (__AVR_ATtiny2313__) || defined (__AVR_ATtiny4313__) || defined (__AVR_ATtiny861__)
#define RF24_TINY
#include "utility/ATTiny/RF24_arch_config.h"
#elif defined (LITTLEWIRE) //LittleWire
#include "utility/LittleWire/RF24_arch_config.h"
#elif defined (TEENSYDUINO) //Teensy
#include "utility/Teensy/RF24_arch_config.h"
#else //Everything else
#include <Arduino.h>
// RF modules support 10 Mhz SPI bus speed
const uint32_t RF24_SPI_SPEED = 10000000;
#if defined (ARDUINO) && !defined (__arm__) && !defined (__ARDUINO_X86__)
#if defined SPI_UART
#include <SPI_UART.h>
#define _SPI uspi
#elif defined (SOFTSPI)
// change these pins to your liking
//
#ifndef SOFT_SPI_MISO_PIN
#define SOFT_SPI_MISO_PIN 9
#endif // SOFT_SPI_MISO_PIN
#ifndef SOFT_SPI_MOSI_PIN
#define SOFT_SPI_MOSI_PIN 8
#endif // SOFT_SPI_MOSI_PIN
#ifndef SOFT_SPI_SCK_PIN
#define SOFT_SPI_SCK_PIN 7
#endif // SOFT_SPI_SCK_PIN
const uint8_t SPI_MODE = 0;
#define _SPI spi
#else // !defined (SPI_UART) && !defined (SOFTSPI)
#include <SPI.h>
#define _SPI SPI
#endif // !defined (SPI_UART) && !defined (SOFTSPI)
#else // defined (ARDUINO) && !defined (__arm__) && !defined (__ARDUINO_X86__)
// Define _BV for non-Arduino platforms and for Arduino DUE
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#if defined(__arm__) || defined (__ARDUINO_X86__)
#if defined (__arm__) && defined (SPI_UART)
#include <SPI_UART.h>
#define _SPI uspi
#else // !defined (__arm__) || !defined (SPI_UART)
#include <SPI.h>
#define _SPI SPI
#endif // !defined (__arm__) || !defined (SPI_UART)
#elif !defined(__arm__) && !defined (__ARDUINO_X86__)
extern HardwareSPI SPI;
#endif // !defined(__arm__) && !defined (__ARDUINO_X86__)
#define _BV(x) (1<<(x))
#endif // defined (ARDUINO) && !defined (__arm__) && !defined (__ARDUINO_X86__)
#ifdef SERIAL_DEBUG
#define IF_SERIAL_DEBUG(x) ({x;})
#else
#define IF_SERIAL_DEBUG(x)
#if defined(RF24_TINY)
#define printf_P(...)
#endif // defined(RF24_TINY)
#endif // SERIAL_DEBUG
#if defined (__ARDUINO_X86__)
#define printf_P printf
#define _BV(bit) (1<<(bit))
#endif // defined (__ARDUINO_X86__)
// Progmem is Arduino-specific
// Arduino DUE is arm and does not include avr/pgmspace
#if defined (ARDUINO_ARCH_ESP8266) || defined (ESP32)
#include <pgmspace.h>
#define PRIPSTR "%s"
#elif defined (ESP32)
#include <pgmspace.h>
#define PRIPSTR "%s"
#elif defined (ARDUINO) && !defined (ESP_PLATFORM) && ! defined (__arm__) && !defined (__ARDUINO_X86__) || defined (XMEGA)
#include <avr/pgmspace.h>
#define PRIPSTR "%S"
#else // !defined (ARDUINO) || defined (ESP_PLATFORM) || defined (__arm__) || defined (__ARDUINO_X86__) && !defined (XMEGA)
#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 // !defined (ARDUINO)
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 pgm_read_ptr(p) (*(p))
#define PRIPSTR "%s"
#endif // !defined (ARDUINO) || defined (ESP_PLATFORM) || defined (__arm__) || defined (__ARDUINO_X86__) && !defined (XMEGA)
#endif //Everything else
#endif // __RF24_CONFIG_H__

473
lib/RF24/configure vendored Executable file
View File

@ -0,0 +1,473 @@
#!/bin/bash
CROSS_CC=arm-linux-gnueabihf-gcc
CROSS_CXX=arm-linux-gnueabihf-g++
function help {
cat <<EOF
configure script for RF24 library.
Options:
Help:
-h, --help print this message
Driver options:
--driver=[wiringPi|SPIDEV|MRAA|RPi|LittleWire]
Driver for RF24 library. [configure autodetected]
Building options:
--os=[LINUX|DARWIN] Operating system. [configure autodetected]
--soc=[BCM2835|BCM2836|AM33XX|A10|A13|A20|H3]
SoC type to be used. [configure autodetected]
--cpu-flags=<CFLAGS> CPU defining/optimizing flags to be used. [configure autodetected]
--extra-cflags=<CFLAGS> Extra C flags passed to C/C++ compilation. []
--extra-ldflags=<LDFLAGS> Extra C flags passed to linking. []
--libname=<LIBNAME> Library name. [rf24]
--c_compiler=<CC> C compiler. [arm-linux-gnueabihf-gcc][gcc]
--cxx_compiler=<CXX> C++ compiler [arm-linux-gnueabihf-g++][g++]
--no-clean Don't clean previous build artifacts
Installation options:
--prefix=<PREFIX> Installation prefix path. [/usr/local]
--lib-dir=<DIR> Library target installation directory. [PREFIX/lib]
--header-dir=<DIR> Header files target installation directory. [PREFIX/include]
--examples-dir=<DIR> Example files installation directory. [PREFIX/bin]
--ldconfig=<LDCONFIG> Ldconfig binary. Can be set to '' to skip ldconfig step. [ldconfig]
Cross-compilation options:
--remote-host=<REMOTE_HOST> Remote hostname for installation.
--remote-user=<REMOTE_USER> Remote username for installation. [current user]
--remote-port=<REMOTE_PORT> Ssh port of remote machine. [22]
--remote=<USER@HOST> Remote ssh host identification for installation [REMOTE_USER@REMOTE_HOST]
--remote-prefix=<RPREFIX> Remote host installation prefix path. [/usr/local]
--remote-lib-dir=<DIR> Remote library target installation directory [RPREFIX/lib]
--remote-header-dir=<DIR> Remote header files target installation directory. [RPREFIX/include]
--remote-ldconfig=<RLDCON> Remote ldconfig binary filename. Can be set to '' to skip ldconfig call. [ldconfig]
--remote-examples-dir=<DIR> Example files remote installation directory. Default: [REMOTE_PREFIX/bin]
EOF
}
function execute_check {
if [ "${REMOTE}" ]; then
ssh -o 'PasswordAuthentication=no' -o 'PreferredAuthentications=publickey' -o 'ConnectTimeout=30' -o 'BatchMode=yes' -o 'StrictHostKeyChecking=no' -p ${REMOTE_PORT} ${REMOTE} $1
else
eval $1
fi
}
function die {
echo "[ERROR] $1"
exit $2
}
function detect_machine {
local cpu=$(execute_check "uname -m 2>/dev/null")
local machine=$(execute_check "cat /sys/firmware/devicetree/base/model 2>/dev/null")
local hardware=$(execute_check "grep sunxi_platform /sys/class/sunxi_info/sys_info 2>/dev/null | sed 's/^.*: \(.*\)$/\1/'")
if [ -z "$hardware" ]; then
local hardware=$(execute_check "grep Hardware /proc/cpuinfo 2>/dev/null | sed 's/^.*: \(.*\)$/\1/'")
fi
local soc="unknown"
local tp="unknown"
if [ -z "$cpu" ]; then
cpu="unknown"
fi
case $hardware in
BCM2708|BCM2835)
soc="BCM2835"
if [[ $machine == "Raspberry"* ]]; then
tp="RPi"
fi
;;
BCM2709)
soc="BCM2836"
if [[ $machine == "Raspberry"* ]]; then
tp="RPi2"
fi
;;
sun4i|Sun4iw1p1)
soc="A10"
;;
sun5i|Sun4iw2p1)
soc="A13"
;;
Sun4iw2p2)
soc="A12"
;;
Sun4iw2p3)
soc="A10s"
;;
sun6i|Sun8iw1p1)
soc="A31"
;;
Sun8iw1p2)
soc="A31s"
;;
sun7i|Sun8iw2p1)
soc="A20"
if [[ $machine == "Banana Pi"* ]]; then
tp="BananaPi"
elif [[ $machine == "Banana Pro"* ]]; then
tp="BananaPro"
fi
;;
sun8i|Sun8iw7p1)
soc="H3"
;;
Sun8iw3p1)
soc="A23"
;;
Sun8iw5p1)
soc="A33"
;;
Sun8iw6p1)
soc="A83t"
;;
sun9i|Sun9iw1p1)
soc="A80"
;;
Sun9iw1p2)
soc="A80t"
;;
sun50i|Sun50iw1p1)
soc="A64"
;;
'Generic AM33XX'*)
soc="AM33XX"
;;
*)
soc="unknown"
esac
echo "${soc} ${tp} ${cpu}"
}
function gcc_cpu_flags {
local soc=$1
case $soc in
BCM2835)
flags="-march=armv6zk -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard"
;;
BCM2836)
flags="-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard"
;;
AM33XX)
flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard"
;;
A10)
flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard"
;;
A13)
flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard"
;;
A20)
flags="-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard"
;;
H3)
flags="-march=armv8-a -mtune=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard"
;;
*)
flags=""
esac
echo ${flags}
}
function detect_driver {
if [[ $(execute_check "cat /proc/cpuinfo | grep Hardware | grep 'BCM2708\|BCM2709\|BCM2835'") ]]; then
result=RPi
elif [[ $(execute_check 'ls /dev/spidev* 2>/dev/null') ]]; then
result=SPIDEV
elif [[ $(execute_check "file /usr/lib/libwiringPi.so*") ]]; then
result=wiringPi
elif [[ $(execute_check "${REMOTE_LDCONFIG} -p | grep libmraa") ]]; then
result=MRAA
elif [[ $(execute_check "${REMOTE_LDCONFIG} -p | grep liblittlewire-spi") ]]; then
result=LittleWire
else
result=""
fi
echo $result
}
function gen_symlink_names {
base_name="$1"
version="$2"
IFS='.' read -r -a ver <<< "$version"
versions=""
for index in "${!ver[@]}" ; do
verstr=""
for ind in `seq 0 $(expr $index - 1)` ; do
verstr="${verstr}.${ver[$ind]}"
done
versions="${base_name}${verstr} $versions"
done
echo ${versions}
}
params="OS SOC DRIVER CPUFLAGS CFLAGS PREFIX REMOTE_PREFIX LIB LIBNAME LIB_VERSION LIBSYMLINKS LIBDEPRECATE CC CXX LIB_DIR REMOTE_LIB_DIR HEADER_DIR REMOTE_HEADER_DIR DRIVER_DIR ARCH_DIR REMOTE REMOTE_HOST REMOTE_USER REMOTE_PORT SHARED_LINKER_FLAGS SHARED_LINKER_LIBS LDCONFIG REMOTE_LDCONFIG EXAMPLES_DIR REMOTE_EXAMPLES_DIR"
for opt do
if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then
help
exit 0
fi
optarg="${opt#*=}"
case "$opt" in
--os=*)
OS="$optarg"
;;
--soc=*)
SOC="$optarg"
;;
--cpu-flags=*)
CPUFLAGS="$optarg"
;;
--extra-cflags=*)
CFLAGS="$optarg"
;;
--extra-ldflags=*)
LDFLAGS="$optarg"
;;
--libname=*)
LIB="$optarg"
;;
--c_compiler=*)
CC="$optarg"
;;
--cxx_compiler=*)
CXX="$optarg"
;;
--no-clean*)
NO_CLEAN="1"
;;
--prefix=*)
PREFIX="$optarg"
;;
--lib-dir=*)
LIB_DIR="$optarg"
;;
--header-dir=*)
HEADER_DIR="$optarg"
;;
--examples-dir=*)
EXAMPLES_DIR="$optarg"
;;
--ldconfig=*)
LDCONFIG="$optarg"
;;
--driver=*)
DRIVER="$optarg"
;;
--remote-host=*)
REMOTE_HOST="$optarg"
;;
--remote-user=*)
REMOTE_USER="$optarg"
;;
--remote-port=*)
REMOTE_PORT="$optarg"
;;
--remote=*)
REMOTE="$optarg"
;;
--remote-prefix=*)
REMOTE_PREFIX="$optarg"
;;
--remote-lib-dir=*)
REMOTE_LIB_DIR="$optarg"
;;
--remote-header-dir=*)
REMOTE_HEADER_DIR="$optarg"
;;
--remote-ldconfig=*)
REMOTE_LDCONFIG="$optarg"
;;
--remote-examples-dir=*)
REMOTE_EXAMPLES_DIR="$optarg"
;;
*)
echo "[WARNING] Unknown option detected:$opt, ignored"
;;
esac
done
#*******************************************
# remote machine verification
if [ "${REMOTE_HOST}" ]; then
if [ "${REMOTE_USER}" ]; then
REMOTE=${REMOTE_USER}@${REMOTE_HOST}
else
REMOTE=${REMOTE_HOST}
fi
fi
if [ "${REMOTE}" ]; then
echo "[SECTION] Checking remote host."
if [ -z "${REMOTE_HOST}" ]; then
REMOTE_HOST=${REMOTE/*@/}
fi
if [ -z "${REMOTE_PORT}" ]; then
REMOTE_PORT=22
fi
if [ "$(nmap ${REMOTE_HOST} -Pn --host-timeout 30s -p ${REMOTE_PORT} 2>/dev/null | grep open)" ]; then
echo " [OK] ssh daemon on ${REMOTE_HOST} port ${REMOTE_PORT} seems to be listening."
else
echo " [WARNING] ssh on ${REMOTE_HOST} port ${REMOTE_PORT} seems not to be listening or nmap not installed."
fi
if [[ "$(execute_check 'echo ok 2>/dev/null' 2>/dev/null)" ]]; then
echo " [OK] Remote machine ssh passwordless login configured fine."
else
die "Remote machine ssh and/or passwordless login check failed." 4
fi
if [[ $(execute_check "sudo echo ok 2>/dev/null") ]]; then
echo " [OK] Remote machine sudo configured fine."
else
die "Remote machine sudo test failed." 5
fi
fi
if [ -z "${CC}" ]; then
echo "[SECTION] Detecting arm compilation environment."
if [[ $(command -v ${CROSS_CC} 2>/dev/null) ]]; then
echo " [OK] ${CROSS_CC} detected."
CC=${CROSS_CC}
CROSS_SYSROOT="$(${CC} --print-sysroot)"
if [ "${CROSS_SYSROOT}" = "/" ]; then
CROSS_SYSROOT=""
fi
else
echo " [INFO] ${CROSS_CC} not found."
fi
if [[ $(command -v ${CROSS_CXX} 2>/dev/null) ]]; then
echo " [OK] ${CROSS_CXX} detected."
CXX=${CROSS_CXX}
else
echo " [INFO] ${CROSS_CXX} not found."
fi
fi
if [ "${CROSS_SYSROOT}" ]; then
PREFIX="${CROSS_SYSROOT}/usr/local"
fi
PREFIX=${PREFIX:-/usr/local}
REMOTE_PREFIX=${REMOTE_PREFIX:-/usr/local}
LIB_DIR=${LIB_DIR:-${PREFIX}/lib}
REMOTE_LIB_DIR=${REMOTE_LIB_DIR:-${REMOTE_PREFIX}/lib}
HEADER_DIR=${HEADER_DIR:-${PREFIX}/include/RF24}
REMOTE_HEADER_DIR=${REMOTE_HEADER_DIR:-${REMOTE_PREFIX}/include/RF24}
EXAMPLES_DIR=${EXAMPLES_DIR:-${PREFIX}/bin}
REMOTE_EXAMPLES_DIR=${REMOTE_EXAMPLES_DIR:-${REMOTE_PREFIX}/bin}
LDCONFIG=${LDCONFIG-ldconfig}
REMOTE_LDCONFIG=${REMOTE_LDCONFIG-/sbin/ldconfig}
LIB=${LIB:-rf24}
LIB_VERSION=${LIB_VERSION:-$(awk -F "=" '/version/ {print $2}' library.properties)}
LIB_DEPRECATE_NAME=${LIB_DEPRECATE_NAME:-"rf24-bcm"}
LIB_DEPRECATE_VERSION=${LIB_DEPRECATE_VERSION:-""}
CC=${CC:-gcc}
CXX=${CXX:-g++}
ARCH_DIR=${ARCH_DIR:-utility}
if [ -z "${SOC}" ]; then
echo "[SECTION] Detecting target machine."
info=($(detect_machine))
SOC=${info[0]}
TYPE=${info[1]}
CPU=${info[2]}
echo "[OK] machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}."
fi
if [ -z "${CPUFLAGS}" ]; then
CPUFLAGS=$(gcc_cpu_flags $SOC)
fi
#*******************************************
# DRIVER detection
if [ -z "${DRIVER}" ]; then
echo "[SECTION] Detecting DRIVER"
DRIVER=$(detect_driver)
if [ -z "${DRIVER}" ]; then
die "No supported driver detected. Run configure with --driver=<driver> to set a driver explicitly." 1
fi
echo " [OK] DRIVER detected:${DRIVER}."
fi
case ${DRIVER} in
wiringPi)
SHARED_LINKER_LIBS+=" -pthread -lwiringPi"
CFLAGS+=" -lwiringPi"
;;
SPIDEV)
SHARED_LINKER_LIBS+=" -pthread"
;;
RPi)
SHARED_LINKER_LIBS+=" -pthread"
;;
MRAA)
SHARED_LINKER_LIBS+=" -lmraa"
;;
LittleWire)
SHARED_LINKER_LIBS+=" -llittlewire-spi"
;;
*)
die "Unsupported DRIVER: ${DRIVER}." 2
;;
esac
#*******************************************
# OS detection
if [ -z "${OS}" ]; then
echo "[SECTION] Detecting OS."
OS=$(execute_check "uname")
OS=${OS^^}
echo " [INFO] OS detected:${OS}."
fi
case ${OS} in
LINUX)
DYN_SUFFIX=so
SHARED_LINKER_FLAGS+=" -shared -Wl,-soname,lib${LIB}.${DYN_SUFFIX}.${LIB_VERSION%%.*}"
;;
DARWIN)
DYN_SUFFIX=dylib
SHARED_LINKER_FLAGS+=" -dynamiclib -install_name ${LIB_DIR}/lib${LIB}.${DYN_SUFFIX}.${LIB_VERSION%%.*}"
;;
*)
die "Unsupported OS: ${OS}." 3
;;
esac
LIBNAME=${LIBNAME:-lib${LIB}.${DYN_SUFFIX}.${LIB_VERSION}}
LIBSYMLINKS="${LIBSYMLINKS:-$(gen_symlink_names lib${LIB}.${DYN_SUFFIX} ${LIB_VERSION})}"
if [ "${LIB_DEPRECATE_NAME}" ]; then
LIBDEPRECATE="${LIBDEPRECATE:-lib${LIB_DEPRECATE_NAME}.${DYN_SUFFIX}}"
if [ "${LIB_DEPRECATE_VERSION}" ]; then
LIBDEPRECATE="${LIBDEPRECATE}.${LIB_DEPRECATE_VERSION}"
fi
fi
DRIVER_DIR=${DRIVER_DIR:-${ARCH_DIR}/${DRIVER}}
CFLAGS="$CPUFLAGS -Ofast -Wall -pthread $CFLAGS"
echo "[SECTION] Preparing configuration."
cp ${DRIVER_DIR}/includes.h ${ARCH_DIR}/includes.h
echo "[SECTION] Saving configuration."
echo -n "" > Makefile.inc
for param in ${params}; do
if [[ ${!param} ]]; then
echo "${param}=${!param}" >> Makefile.inc
fi
done
if [ -z "${NO_CLEAN}" ]; then
echo "[SECTION] Cleaning previous builds."
make clean >/dev/null
fi
echo "[OK] Finished."

835
lib/RF24/doxygen-custom.css Normal file
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: 110%;
}
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;
}

View File

@ -0,0 +1,142 @@
/*
* Getting Started example sketch for nRF24L01+ radios
* This is a very basic example of how to send data from one node to another
* Updated: Dec 2014 by TMRh20
*/
#include <SPI.h>
#include "RF24.h"
/****************** User Config ***************************/
/*** Set this radio as radio number 0 or 1 ***/
bool radioNumber = 0;
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7,8);
/**********************************************************/
byte addresses[][6] = {"1Node","2Node"};
// Used to control whether this node is sending or receiving
bool role = 0;
void setup() {
Serial.begin(115200);
Serial.println(F("RF24/examples/GettingStarted"));
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
radio.begin();
// Set the PA Level low to prevent power supply related issues since this is a
// getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default.
radio.setPALevel(RF24_PA_LOW);
// Open a writing and reading pipe on each radio, with opposite addresses
if(radioNumber){
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
}else{
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
}
// Start the radio listening for data
radio.startListening();
}
void loop() {
/****************** Ping Out Role ***************************/
if (role == 1) {
radio.stopListening(); // First, stop listening so we can talk.
Serial.println(F("Now sending"));
unsigned long start_time = micros(); // Take the time, and send it. This will block until complete
if (!radio.write( &start_time, sizeof(unsigned long) )){
Serial.println(F("failed"));
}
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
Serial.println(F("Failed, response timed out."));
}else{
unsigned long got_time; // Grab the response, compare, and send to debugging spew
radio.read( &got_time, sizeof(unsigned long) );
unsigned long end_time = micros();
// Spew it
Serial.print(F("Sent "));
Serial.print(start_time);
Serial.print(F(", Got response "));
Serial.print(got_time);
Serial.print(F(", Round-trip delay "));
Serial.print(end_time-start_time);
Serial.println(F(" microseconds"));
}
// Try again 1s later
delay(1000);
}
/****************** Pong Back Role ***************************/
if ( role == 0 )
{
unsigned long got_time;
if( radio.available()){
// 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.
Serial.print(F("Sent response "));
Serial.println(got_time);
}
}
/****************** Change Roles via Serial Commands ***************************/
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == 0 ){
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
role = 1; // Become the primary transmitter (ping out)
}else
if ( c == 'R' && role == 1 ){
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
role = 0; // Become the primary receiver (pong back)
radio.startListening();
}
}
} // Loop

View File

@ -0,0 +1,138 @@
/*
Dec 2014 - TMRh20 - Updated
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 "RF24.h"
/****************** User Config ***************************/
/*** Set this radio as radio number 0 or 1 ***/
bool radioNumber = 0;
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7,8);
/**********************************************************/
// Topology
byte addresses[][6] = {"1Node","2Node"}; // 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(115200);
Serial.println(F("RF24/examples/GettingStarted_CallResponse"));
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
// Setup and configure radio
radio.begin();
radio.enableAckPayload(); // Allow optional ack payloads
radio.enableDynamicPayloads(); // Ack payloads are dynamic payloads
if(radioNumber){
radio.openWritingPipe(addresses[1]); // Both radios listen on the same pipes by default, but opposite addresses
radio.openReadingPipe(1,addresses[0]); // Open a reading pipe on address 0, pipe 1
}else{
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
}
radio.startListening(); // Start listening
radio.writeAckPayload(1,&counter,1); // Pre-load an ack-paylod into the FIFO buffer for pipe 1
//radio.printDetails();
}
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.
Serial.print(F("Now sending ")); // Use a simple byte counter as payload
Serial.println(counter);
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
Serial.print(F("Got blank response. round-trip delay: "));
Serial.print(micros()-time);
Serial.println(F(" microseconds"));
}else{
while(radio.available() ){ // If an ack with payload was received
radio.read( &gotByte, 1 ); // Read it, and display the response time
unsigned long timer = micros();
Serial.print(F("Got response "));
Serial.print(gotByte);
Serial.print(F(" round-trip delay: "));
Serial.print(timer-time);
Serial.println(F(" microseconds"));
counter++; // Increment the counter variable
}
}
}else{ Serial.println(F("Sending failed.")); } // 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.
gotByte += 1; // 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.
Serial.print(F("Loaded next response "));
Serial.println(gotByte);
}
}
/****************** Change Roles via Serial Commands ***************************/
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == role_pong_back ){
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
role = role_ping_out; // Become the primary transmitter (ping out)
counter = 1;
}else
if ( c == 'R' && role == role_ping_out ){
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
role = role_pong_back; // Become the primary receiver (pong back)
radio.startListening();
counter = 1;
radio.writeAckPayload(1,&counter,1);
}
}
}

View File

@ -0,0 +1,161 @@
/*
* Getting Started example sketch for nRF24L01+ radios
* This is an example of how to send data from one node to another using data structures
* Updated: Dec 2014 by TMRh20
*/
#include <SPI.h>
#include "RF24.h"
byte addresses[][6] = {"1Node","2Node"};
/****************** User Config ***************************/
/*** Set this radio as radio number 0 or 1 ***/
bool radioNumber = 1;
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7,8);
/**********************************************************/
// Used to control whether this node is sending or receiving
bool role = 0;
/**
* Create a data structure for transmitting and receiving data
* This allows many variables to be easily sent and received in a single transmission
* See http://www.cplusplus.com/doc/tutorial/structures/
*/
struct dataStruct{
unsigned long _micros;
float value;
}myData;
void setup() {
Serial.begin(115200);
Serial.println(F("RF24/examples/GettingStarted_HandlingData"));
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
radio.begin();
// Set the PA Level low to prevent power supply related issues since this is a
// getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default.
radio.setPALevel(RF24_PA_LOW);
// Open a writing and reading pipe on each radio, with opposite addresses
if(radioNumber){
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
}else{
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
}
myData.value = 1.22;
// Start the radio listening for data
radio.startListening();
}
void loop() {
/****************** Ping Out Role ***************************/
if (role == 1) {
radio.stopListening(); // First, stop listening so we can talk.
Serial.println(F("Now sending"));
myData._micros = micros();
if (!radio.write( &myData, sizeof(myData) )){
Serial.println(F("failed"));
}
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
Serial.println(F("Failed, response timed out."));
}else{
// Grab the response, compare, and send to debugging spew
radio.read( &myData, sizeof(myData) );
unsigned long time = micros();
// Spew it
Serial.print(F("Sent "));
Serial.print(time);
Serial.print(F(", Got response "));
Serial.print(myData._micros);
Serial.print(F(", Round-trip delay "));
Serial.print(time-myData._micros);
Serial.print(F(" microseconds Value "));
Serial.println(myData.value);
}
// Try again 1s later
delay(1000);
}
/****************** Pong Back Role ***************************/
if ( role == 0 )
{
if( radio.available()){
// Variable for the received timestamp
while (radio.available()) { // While there is data ready
radio.read( &myData, sizeof(myData) ); // Get the payload
}
radio.stopListening(); // First, stop listening so we can talk
myData.value += 0.01; // Increment the float value
radio.write( &myData, sizeof(myData) ); // Send the final one back.
radio.startListening(); // Now, resume listening so we catch the next packets.
Serial.print(F("Sent response "));
Serial.print(myData._micros);
Serial.print(F(" : "));
Serial.println(myData.value);
}
}
/****************** Change Roles via Serial Commands ***************************/
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == 0 ){
Serial.print(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
role = 1; // Become the primary transmitter (ping out)
}else
if ( c == 'R' && role == 1 ){
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
role = 0; // Become the primary receiver (pong back)
radio.startListening();
}
}
} // Loop

View File

@ -0,0 +1,218 @@
/*
* Getting Started example sketch for nRF24L01+ radios
* This is a very basic example of how to send data from one node to another
* but modified to include failure handling.
*
* The nrf24l01+ radios are fairly reliable devices, but on breadboards etc, with inconsistent wiring, failures may
* occur randomly after many hours to days or weeks. This sketch demonstrates how to handle the various failures and
* keep the radio operational.
*
* The three main failure modes of the radio include:
* Writing to radio: Radio unresponsive - Fixed internally by adding a timeout to the internal write functions in RF24 (failure handling)
* Reading from radio: Available returns true always - Fixed by adding a timeout to available functions by the user. This is implemented internally in RF24Network.
* Radio configuration settings are lost - Fixed by monitoring a value that is different from the default, and re-configuring the radio if this setting reverts to the default.
*
* The printDetails output should appear as follows for radio #0:
*
* STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
* RX_ADDR_P0-1 = 0x65646f4e31 0x65646f4e32
* RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6
* TX_ADDR = 0x65646f4e31
* RX_PW_P0-6 = 0x20 0x20 0x00 0x00 0x00 0x00
* EN_AA = 0x3f
* EN_RXADDR = 0x02
* RF_CH = 0x4c
* RF_SETUP = 0x03
* CONFIG = 0x0f
* DYNPD/FEATURE = 0x00 0x00
* Data Rate = 1MBPS
* Model = nRF24L01+
* CRC Length = 16 bits
* PA Power = PA_LOW
*
*Users can use this sketch to troubleshoot radio module wiring etc. as it makes the radios hot-swapable
*
* Updated: 2019 by TMRh20
*/
#include <SPI.h>
#include "RF24.h"
#include "printf.h"
/****************** User Config ***************************/
/*** Set this radio as radio number 0 or 1 ***/
bool radioNumber = 0;
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7,8);
/**********************************************************/
byte addresses[][6] = {"1Node","2Node"};
// Used to control whether this node is sending or receiving
bool role = 0;
/**********************************************************/
//Function to configure the radio
void configureRadio(){
radio.begin();
// Set the PA Level low to prevent power supply related issues since this is a
// getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default.
radio.setPALevel(RF24_PA_LOW);
// Open a writing and reading pipe on each radio, with opposite addresses
if(radioNumber){
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
}else{
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
}
// Start the radio listening for data
radio.startListening();
radio.printDetails();
}
/**********************************************************/
void setup() {
Serial.begin(115200);
Serial.println(F("RF24/examples/GettingStarted"));
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
printf_begin();
configureRadio();
}
uint32_t configTimer = millis();
void loop() {
if(radio.failureDetected){
radio.failureDetected = false;
delay(250);
Serial.println("Radio failure detected, restarting radio");
configureRadio();
}
//Every 5 seconds, verify the configuration of the radio. This can be done using any
//setting that is different from the radio defaults.
if(millis() - configTimer > 5000){
configTimer = millis();
if(radio.getDataRate() != RF24_1MBPS){
radio.failureDetected = true;
Serial.print("Radio configuration error detected");
}
}
/****************** Ping Out Role ***************************/
if (role == 1) {
radio.stopListening(); // First, stop listening so we can talk.
Serial.println(F("Now sending"));
unsigned long start_time = micros(); // Take the time, and send it. This will block until complete
if (!radio.write( &start_time, sizeof(unsigned long) )){
Serial.println(F("failed"));
}
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
Serial.println(F("Failed, response timed out."));
}else{
unsigned long got_time; // Grab the response, compare, and send to debugging spew
//Failure Handling:
uint32_t failTimer = millis();
while(radio.available()){ //If available always returns true, there is a problem
if(millis() - failTimer > 250){
radio.failureDetected = true;
Serial.println("Radio available failure detected");
break;
}
radio.read( &got_time, sizeof(unsigned long) );
}
unsigned long end_time = micros();
// Spew it
Serial.print(F("Sent "));
Serial.print(start_time);
Serial.print(F(", Got response "));
Serial.print(got_time);
Serial.print(F(", Round-trip delay "));
Serial.print(end_time-start_time);
Serial.println(F(" microseconds"));
}
// Try again 1s later
delay(1000);
}
/****************** Pong Back Role ***************************/
if ( role == 0 )
{
unsigned long got_time;
if( radio.available()){
uint32_t failTimer = millis(); // Variable for the received timestamp
while (radio.available()) { // While there is data ready
if(millis()-failTimer > 500){
Serial.println("Radio available failure detected");
radio.failureDetected = true;
break;
}
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.
Serial.print(F("Sent response "));
Serial.println(got_time);
}
}
/****************** Change Roles via Serial Commands ***************************/
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == 0 ){
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
role = 1; // Become the primary transmitter (ping out)
}else
if ( c == 'R' && role == 1 ){
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
role = 0; // Become the primary receiver (pong back)
radio.startListening();
}
}
} // Loop

View File

@ -0,0 +1,149 @@
/*
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 "RF24.h"
/************* USER Configuration *****************************/
// Hardware configuration
RF24 radio(7,8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8
/***************************************************************/
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(115200);
radio.begin(); // Setup and configure rf radio
radio.setChannel(1);
radio.setPALevel(RF24_PA_MAX); // If you want to save power use "RF24_PA_MIN" but keep in mind that reduces the module's range
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); // Use 8-bit CRC for performance
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
radio.startListening(); // Start listening
radio.printDetails(); // Dump the configuration of the rf unit for debugging
Serial.println(F("\n\rRF24/examples/Transfer/"));
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
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);
Serial.println(F("Initiating Basic Data Transfer"));
unsigned long cycles = 10000; //Change this to a higher or lower number.
startTime = millis();
unsigned long pauseTime = 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
}
//This is only required when NO ACK ( enableAutoAck(0) ) payloads are used
// if(millis() - pauseTime > 3){
// pauseTime = millis();
// radio.txStandBy(); // Need to drop out of TX mode every 4ms if sending a steady stream of multicast data
// //delayMicroseconds(130); // This gives the PLL time to sync back up
// }
}
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);
Serial.print("Transfer complete at "); Serial.print(rate); Serial.println(" KB/s");
Serial.print(counter); Serial.print(" of "); Serial.print(cycles); Serial.println(" Packets Failed to Send");
counter = 0;
}
if(role == RX){
while(radio.available()){
radio.read(&data,32);
counter++;
}
if(millis() - rxTimer > 1000){
rxTimer = millis();
unsigned long numBytes = counter*32;
Serial.print(F("Rate: "));
//Prevent dividing into 0, which will cause issues over a period of time
Serial.println(numBytes > 0 ? numBytes/1000.0:0);
Serial.print(F("Payload Count: "));
Serial.println(counter);
counter = 0;
}
}
//
// Change roles
//
if ( Serial.available() )
{
char c = toupper(Serial.read());
if ( c == 'T' && role == RX )
{
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
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();
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
role = RX; // Become the primary receiver (pong back)
}
}
}

View File

@ -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(7,8); // 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(115200);
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)
}
}
}

View File

@ -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 ;

View File

@ -0,0 +1,254 @@
/*
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 (CE & CS)
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(115200);
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
while (radio.available())
{
// Fetch the payload, and see if this was the last one.
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

View File

@ -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 ] ;

View File

@ -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(115200);
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

View File

@ -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 ;

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
Note: These examples may have not been maintained with library updates, and are provided as-is for reference purposes.

View File

@ -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 optionally 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 7 & 8
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(115200);
printf_begin();
Serial.print(F("\n\rRF24/examples/pingpair_ack/\n\rROLE: "));
Serial.println(role_friendly_name[role]);
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
// 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 )){
Serial.println(F("failed."));
}else{
if(!radio.available()){
Serial.println(F("Blank Payload Received."));
}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 )
{
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
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 )
{
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
role = role_pong_back; // Become the primary receiver (pong back)
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
radio.startListening();
}
}
}

View File

@ -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 ;

View File

@ -0,0 +1,246 @@
/*
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"
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 7 & 8
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(115200);
Serial.println(F("RF24/examples/pingpair_dyn/"));
Serial.print(F("ROLE: "));
Serial.println(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
Serial.print(F("Now sending length "));
Serial.println(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 )
{
Serial.println(F("Failed, response timed out."));
}
else
{
// Grab the response, compare, and send to debugging spew
uint8_t len = radio.getDynamicPayloadSize();
// If a corrupt dynamic payload is received, it will be flushed
if(!len){
return;
}
radio.read( receive_payload, len );
// Put a zero at the end for easy printing
receive_payload[len] = 0;
// Spew it
Serial.print(F("Got response size="));
Serial.print(len);
Serial.print(F(" value="));
Serial.println(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
while ( radio.available() )
{
// Fetch the payload, and see if this was the last one.
uint8_t len = radio.getDynamicPayloadSize();
// If a corrupt dynamic payload is received, it will be flushed
if(!len){
continue;
}
radio.read( receive_payload, len );
// Put a zero at the end for easy printing
receive_payload[len] = 0;
// Spew it
Serial.print(F("Got response size="));
Serial.print(len);
Serial.print(F(" value="));
Serial.println(receive_payload);
// First, stop listening so we can talk
radio.stopListening();
// Send the final one back.
radio.write( receive_payload, len );
Serial.println(F("Sent response."));
// Now, resume listening so we catch the next packets.
radio.startListening();
}
}
}
// vim:cin:ai:sts=2 sw=2 ft=cpp

View File

@ -0,0 +1,143 @@
/*
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"
// Hardware configuration
RF24 radio(7,8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8
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
// Demonstrates another method of setting up the addresses
byte address[][5] = { 0xCC,0xCE,0xCC,0xCE,0xCC , 0xCE,0xCC,0xCE,0xCC,0xCE};
// 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
static uint32_t message_count = 0;
/********************** 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();
Serial.print(F("\n\rRF24/examples/pingpair_irq\n\rROLE: "));
Serial.println(role_friendly_name[role]);
// Setup and configure rf radio
radio.begin();
//radio.setPALevel(RF24_PA_LOW);
radio.enableAckPayload(); // We will be using the Ack Payload feature, so please enable it
radio.enableDynamicPayloads(); // Ack payloads are dynamic payloads
// 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.writeAckPayload( 1, &message_count, sizeof(message_count) ); // Add an ack packet for the next time around. This is a simple
++message_count;
}
radio.printDetails(); // Dump the configuration of the rf unit for debugging
delay(50);
attachInterrupt(0, check_radio, LOW); // Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver
}
/********************** 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.
Serial.print(F("Now sending "));
Serial.println(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 ){ Serial.println(F("Send:OK")); }
if ( role == role_receiver ){ Serial.println(F("Ack Payload:Sent")); }
}
if ( fail ) { // Have we failed to transmit?
if ( role == role_sender ){ Serial.println(F("Send:Failed")); }
if ( role == role_receiver ){ Serial.println(F("Ack Payload:Failed")); }
}
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));
Serial.print(F("Ack: "));
Serial.println(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) );
Serial.print(F("Got payload "));
Serial.println(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
}
}
}

View File

@ -0,0 +1,122 @@
/*
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.
Created Dec 2014 - TMRh20
*/
/**
* Example of using interrupts
*
* This is a very simple example of using two devices to communicate using interrupts.
* With multiple devices, each device would need to have a separate reading pipe
*/
#include <SPI.h>
#include "RF24.h"
#include <printf.h>
// Hardware configuration
// Set up nRF24L01 radio on SPI bus plus pins 7 & 8
RF24 radio(7,8);
// Use the same address for both devices
uint8_t address[] = { "radio" };
// Simple messages to represent a 'ping' and 'pong'
uint8_t ping = 111;
uint8_t pong = 222;
volatile uint32_t round_trip_timer = 0;
/********************** Setup *********************/
void setup(){
Serial.begin(115200);
Serial.println(F("Simple pingpair example"));
Serial.println(F("Send a 'T' via Serial to transmit a single 'ping' "));
//printf_begin();
// Setup and configure rf radio
radio.begin();
// Use dynamic payloads to improve response time
radio.enableDynamicPayloads();
radio.openWritingPipe(address); // communicate back and forth. One listens on it, the other talks to it.
radio.openReadingPipe(1,address);
radio.startListening();
//radio.printDetails(); // Dump the configuration of the rf unit for debugging
attachInterrupt(0, check_radio, LOW); // Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver
}
/********************** Main Loop *********************/
void loop() {
if(Serial.available()){
switch(toupper(Serial.read())){
case 'T':
// Only allow 1 transmission per 45ms to prevent overlapping IRQ/reads/writes
// Default retries = 5,15 = ~20ms per transmission max
while(micros() - round_trip_timer < 45000){
//delay between writes
}
Serial.print(F("Sending Ping"));
radio.stopListening();
round_trip_timer = micros();
radio.startWrite( &ping, sizeof(uint8_t),0 );
break;
}
}
}
/********************** 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 data is available, handle it accordingly
if ( rx ){
if(radio.getDynamicPayloadSize() < 1){
// Corrupt payload has been flushed
return;
}
// Read in the data
uint8_t received;
radio.read(&received,sizeof(received));
// If this is a ping, send back a pong
if(received == ping){
radio.stopListening();
// Normal delay will not work here, so cycle through some no-operations (16nops @16mhz = 1us delay)
for(uint32_t i=0; i<130;i++){
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
}
radio.startWrite(&pong,sizeof(pong),0);
Serial.print("pong");
}else
// If this is a pong, get the current micros()
if(received == pong){
round_trip_timer = micros() - round_trip_timer;
Serial.print(F("Received Pong, Round Trip Time: "));
Serial.println(round_trip_timer);
}
}
// Start listening if transmission is complete
if( tx || fail ){
radio.startListening();
Serial.println(tx ? F(":OK") : F(":Fail"));
}
}

View File

@ -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 ;

View File

@ -0,0 +1,263 @@
/*
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.
*/
/**
* Example using Dynamic Payloads
*
* This is an example of how to use payloads of a varying (dynamic) size.
*/
#include <SPI.h>
#include "RF24.h"
//
// Hardware configuration
//
// Set up nRF24L01 radio on SPI bus plus pins 8 & 9
RF24 radio(8,9);
// Use multicast?
// sets the multicast behavior this unit in hardware. Connect to GND to use unicast
// Leave open (default) to use multicast.
const int multicast_pin = 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 = 7;
bool multicast = true ;
//
// Topology
//
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xEEFAFDFDEELL, 0xEEFDFAF50DFLL };
//
// 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 = 1;
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)
{
//
// Multicast
//
pinMode(multicast_pin, INPUT);
digitalWrite(multicast_pin,HIGH);
delay( 20 ) ;
// read multicast role, LOW for unicast
if( digitalRead( multicast_pin ) )
multicast = true ;
else
multicast = false ;
//
// 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(115200);
Serial.println(F("RF24/examples/pingpair_multi_dyn/"));
Serial.print(F("ROLE: "));
Serial.println(role_friendly_name[role]);
Serial.print(F("MULTICAST: "));
Serial.println(multicast ? F("true (unreliable)") : F("false (reliable)"));
//
// Setup and configure rf radio
//
radio.begin();
// enable dynamic payloads
radio.enableDynamicPayloads();
radio.setCRCLength( RF24_CRC_16 ) ;
// optionally, increase the delay between retries & # of retries
radio.setRetries( 15, 5 ) ;
radio.setAutoAck( true ) ;
//radio.setPALevel( RF24_PA_LOW ) ;
//
// 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.powerUp() ;
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
Serial.print(F("Now sending length "));
Serial.println(next_payload_size);
radio.write( send_payload, next_payload_size, multicast );
// 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 )
{
Serial.println(F("Failed, response timed out."));
}
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
Serial.print(F("Got response size="));
Serial.print(len);
Serial.print(F(" value="));
Serial.println(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(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
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
Serial.print(F("Got response size="));
Serial.print(len);
Serial.print(F(" value="));
Serial.println(receive_payload);
}
// First, stop listening so we can talk
radio.stopListening();
// Send the final one back.
radio.write( receive_payload, len, multicast );
Serial.println(F("Sent response."));
// Now, resume listening so we catch the next packets.
radio.startListening();
}
}
}
// vim:cin:ai:sts=2 sw=2 ft=cpp

View File

@ -0,0 +1,226 @@
/*
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 7 & 8
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(115200);
printf_begin();
Serial.print(F("\n\rRF24/examples/pingpair_sleepy/\n\rROLE: "));
Serial.println(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.
Serial.print(F("Now sending... "));
Serial.println(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
Serial.println(F("Failed, response timed out."));
} 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.
Serial.println(F("Sent response."));
radio.startListening(); // Now, resume listening so we catch the next packets.
} else {
Serial.println(F("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(F("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);
}

View File

@ -0,0 +1,101 @@
/*
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.
rf24ping85.ino by tong67 ( https://github.com/tong67 )
This is an example of how to use the RF24 class to communicate with ATtiny85 and other node.
Write this sketch to an ATtiny85. It will act like the 'transmit' mode of GettingStarted.ino
Write GettingStarted.ino sketch to UNO (or other board or RPi) and put the node in 'receiver' mode.
The ATtiny85 will transmit a counting number every second starting from 1.
The ATtiny85 uses the tiny-core by CodingBadly (https://code.google.com/p/arduino-tiny/)
When direct use of 3v3 does not work (UNO boards have bad 3v3 line) use 5v with LED (1.8V ~ 2.2V drop)
For low power consumption solutions floating pins (SCK and MOSI) should be pulled high or low with eg. 10K
** Hardware configuration **
ATtiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 4
+-\/-+
NC PB5 1|o |8 Vcc --- nRF24L01 VCC, pin2 --- LED --- 5V
nRF24L01 CE, pin3 --- PB3 2| |7 PB2 --- nRF24L01 SCK, pin5
nRF24L01 CSN, pin4 --- PB4 3| |6 PB1 --- nRF24L01 MOSI, pin7
nRF24L01 GND, pin1 --- GND 4| |5 PB0 --- nRF24L01 MISO, pin6
+----+
ATtiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 3 => PB3 and PB4 are free to use for application
Circuit idea from http://nerdralph.blogspot.ca/2014/01/nrf24l01-control-with-3-attiny85-pins.html
Original RC combination was 1K/100nF. 22K/10nF combination worked better.
For best settletime delay value in RF24::csn() the timingSearch3pin.ino scatch can be used.
This configuration is enabled when CE_PIN and CSN_PIN are equal, e.g. both 3
Because CE is always high the power consumption is higher than for 5 pins solution
^^
+-\/-+ nRF24L01 CE, pin3 ------| //
PB5 1|o |8 Vcc --- nRF24L01 VCC, pin2 ------x----------x--|<|-- 5V
NC PB3 2| |7 PB2 --- nRF24L01 SCK, pin5 --|<|---x-[22k]--| LED
NC PB4 3| |6 PB1 --- nRF24L01 MOSI, pin6 1n4148 |
nRF24L01 GND, pin1 -x- GND 4| |5 PB0 --- nRF24L01 MISO, pin7 |
| +----+ |
|-----------------------------------------------||----x-- nRF24L01 CSN, pin4
10nF
ATtiny24/44/84 Pin map with CE_PIN 8 and CSN_PIN 7
Schematic provided and successfully tested by Carmine Pastore (https://github.com/Carminepz)
+-\/-+
nRF24L01 VCC, pin2 --- VCC 1|o |14 GND --- nRF24L01 GND, pin1
PB0 2| |13 AREF
PB1 3| |12 PA1
PB3 4| |11 PA2 --- nRF24L01 CE, pin3
PB2 5| |10 PA3 --- nRF24L01 CSN, pin4
PA7 6| |9 PA4 --- nRF24L01 SCK, pin5
nRF24L01 MOSI, pin7 --- PA6 7| |8 PA5 --- nRF24L01 MISO, pin6
+----+
*/
// CE and CSN are configurable, specified values for ATtiny85 as connected above
#define CE_PIN 3
#define CSN_PIN 4
//#define CSN_PIN 3 // uncomment for ATtiny85 3 pins solution
#include "RF24.h"
RF24 radio(CE_PIN, CSN_PIN);
byte addresses[][6] = {
"1Node","2Node"};
unsigned long payload = 0;
void setup() {
// 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]); // Write to device address '2Node'
radio.openReadingPipe(1,addresses[0]); // Read on pipe 1 for device address '1Node'
radio.startListening(); // Start listening
}
void loop(void){
radio.stopListening(); // First, stop listening so we can talk.
payload++;
radio.write( &payload, sizeof(unsigned long) );
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
unsigned long got_time; // Grab the response, compare, and send to debugging spew
radio.read( &got_time, sizeof(unsigned long) );
}
// Try again 1s later
delay(1000);
}

View File

@ -0,0 +1,396 @@
/*
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.
timingSearch3pin.ino by tong67 ( https://github.com/tong67 )
This sketch can be used to determine the best settleTime values to use in RF24::csn().
The used settleTimeValues are 100/20. Depend on used RC combiniation and voltage drop by LED.
It is setup to be completely selfcontained, copied defines and code from RF24 library.
The ATtiny85 uses the tiny-core by CodingBadly (https://code.google.com/p/arduino-tiny/)
(Intermediate) results are written to TX (PB3, pin 2). For schematic see rf24ping85.ino
*/
// nRF24L01.h copy
/* 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 RF24_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
/****************************************************************************/
//ATTiny support code pulled in from https://github.com/jscrane/RF24
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
// see http://gammon.com.au/spi
# define DI 0 // D0, pin 5 Data In
# define DO 1 // D1, pin 6 Data Out (this is *not* MOSI)
# define USCK 2 // D2, pin 7 Universal Serial Interface clock
# define SS 3 // D3, pin 2 Slave Select
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
// these depend on the core used (check pins_arduino.h)
// this is for jeelabs' one (based on google-code core)
# define DI 4 // PA6
# define DO 5 // PA5
# define USCK 6 // PA4
# define SS 3 // PA7
#endif
#if defined (ARDUINO) && !defined (__arm__)
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
#define RF24_TINY
#else
// #include <SPI.h>
#endif
#endif
#if defined(RF24_TINY)
#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 /* RF24_TINY */
#if defined(RF24_TINY)
void SPIClass::begin() {
digitalWrite(SS, HIGH);
pinMode(USCK, OUTPUT);
pinMode(DO, OUTPUT);
pinMode(SS, OUTPUT);
pinMode(DI, INPUT);
USICR = _BV(USIWM0);
}
byte SPIClass::transfer(byte b) {
USIDR = b;
USISR = _BV(USIOIF);
do
USICR = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC);
while ((USISR & _BV(USIOIF)) == 0);
return USIDR;
}
void SPIClass::end() {}
#endif /* RF24_TINY */
/****************************************************************************/
uint8_t ce_pin; /**< "Chip Enable" pin, activates the RX or TX role */
uint8_t csn_pin; /**< SPI Chip select */
uint8_t csnHighSettle = 255;
uint8_t csnLowSettle = 255;
/****************************************************************************/
void ce(bool level) {
if (ce_pin != csn_pin) digitalWrite(ce_pin,level);
}
/****************************************************************************/
void setCsnHighSettle(uint8_t level) {
csnHighSettle = level;
}
/****************************************************************************/
void setCsnLowSettle(uint8_t level) {
csnLowSettle = level;
}
/****************************************************************************/
void csn(bool mode) {
if (ce_pin != csn_pin) {
digitalWrite(csn_pin,mode);
} else {
if (mode == HIGH) {
PORTB |= (1<<PINB2); // SCK->CSN HIGH
delayMicroseconds(csnHighSettle); // allow csn to settle
} else {
PORTB &= ~(1<<PINB2); // SCK->CSN LOW
delayMicroseconds(csnLowSettle); // allow csn to settle
}
}
}
/****************************************************************************/
uint8_t read_register(uint8_t reg)
{
csn(LOW);
SPI.transfer( R_REGISTER | ( REGISTER_MASK & reg ) );
uint8_t result = SPI.transfer(0xff);
csn(HIGH);
return result;
}
/****************************************************************************/
uint8_t write_register2(uint8_t reg, uint8_t value)
{
uint8_t status;
csn(LOW);
status = SPI.transfer( W_REGISTER | ( REGISTER_MASK & reg ) );
SPI.transfer(value);
csn(HIGH);
return status;
}
/****************************************************************************/
#if defined(RF24_TINY)
#define CE_PIN 3
#define CSN_PIN 3
#else
#define CE_PIN 7
#define CSN_PIN 8
#endif
#define MAX_HIGH 100
#define MAX_LOW 100
#define MINIMAL 8
void setup(void) {
uint8_t status;
// start serial port and SPI
Serial.begin(9600);
SPI.begin();
// configure ce and scn as output when used
ce_pin = CE_PIN;
csn_pin = CSN_PIN;
setCsnHighSettle(MAX_HIGH);
setCsnLowSettle(MAX_LOW);
// csn is used in SPI transfers. Set to LOW at start and HIGH after transfer. Set to HIGH to reflect no transfer active
// SPI command are accepted in Power Down state.
// ce represent PRX (LOW) or PTX (HIGH) mode apart from register settings. Start in PRX mode.
ce(LOW);
csn(HIGH);
// nRF24L01 goes from to Power Down state 100ms after Power on Reset ( Vdd > 1.9V) or when PWR_UP is 0 in config register
// Goto Power Down state (Powerup or force) and set in transmit mode
write_register2(CONFIG, read_register(CONFIG) & ~_BV(PWR_UP) & ~_BV(PRIM_RX));
delay(100);
// Goto Standby-I
// Technically we require 4.5ms Tpd2stby+ 14us as a worst case. We'll just call it 5ms for good measure.
// WARNING: Delay is based on P-variant whereby non-P *may* require different timing.
write_register2(CONFIG, read_register(CONFIG) | _BV(PWR_UP));
delay(5) ;
// Goto Standby-II
ce(HIGH);
Serial.print("Scanning for optimal setting time for scn");
}
void loop(void) {
uint8_t status;
uint8_t i;
uint8_t j;
uint8_t k;
bool success = true;
uint8_t csnHigh = MAX_HIGH;
uint8_t csnLow = MAX_LOW;
uint8_t bottom_success;
bool bottom_found;
uint8_t value[] = {5,10};
uint8_t limit[] = {MAX_HIGH,MAX_LOW};
uint8_t advice[] = {MAX_HIGH,MAX_LOW};
// check max values give correct behavior
for (k=0;k<2;k++) {
bottom_found = false;
bottom_success = 0;
while(bottom_success < 255) {
setCsnHighSettle(limit[0]);
setCsnLowSettle(limit[1]);
// check current values
i = 0;
while(i<255 & success) {
for (j=0;j<2;j++) {
write_register2(EN_AA, value[j]);
status = read_register(EN_AA);
if (value[j] != status) {
success = false;
}
}
i++;
}
// process result of current values
if (!success) {
Serial.print("Settle NOK. csnHigh=");
Serial.print(limit[0],DEC);
Serial.print(" csnLow=");
Serial.println(limit[1],DEC);
limit[k]++;
bottom_found = true;
bottom_success = 0;
success = true;
} else {
Serial.print("Settle OK. csnHigh=");
Serial.print(limit[0],DEC);
Serial.print(" csnLow=");
Serial.println(limit[1],DEC);
if (!bottom_found) {
limit[k]--;
if (limit[k] == MINIMAL) {
bottom_found = true;
bottom_success = 0;
success = true;
}
} else {
bottom_success++;
}
}
}
Serial.print("Settle value found for ");
if (k == 0) {
Serial.print("csnHigh: ");
} else {
Serial.print("csnLow: ");
}
Serial.println(limit[k],DEC);
advice[k] = limit[k] + (limit[k] / 10);
limit[k] = 100;
}
Serial.print("Adviced Settle times are: csnHigh=");
Serial.print(advice[0],DEC);
Serial.print(" csnLow=");
Serial.println(advice[1],DEC);
while (true)
{
;
}
}

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 ;
}

View File

@ -0,0 +1,127 @@
/*
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 7 & 8
RF24 radio(7,8);
//
// Channel info
//
const uint8_t num_channels = 126;
uint8_t values[num_channels];
//
// Setup
//
void setup(void)
{
//
// Print preamble
//
Serial.begin(115200);
printf_begin();
Serial.println(F("\n\rRF24/examples/scanner/"));
//
// 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;
}
Serial.println();
i = 0;
while ( i < num_channels )
{
printf("%x",i&0xf);
++i;
}
Serial.println();
}
//
// 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(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]));
++i;
}
Serial.println();
}
// vim:ai:cin:sts=2 sw=2 ft=cpp

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 ;

View File

@ -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(115200);
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

View File

@ -0,0 +1,52 @@
#############################################################################
#
# Makefile for librf24 examples on Linux
#
# 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
#
BINARY_PREFIX = rf24
SOURCES = $(PROGRAMS:=.cpp)
LIBS=-l$(LIB)
ifeq ($(DRIVER), LittleWire)
LIBS+= -llittlewire-spi
endif
all: $(PROGRAMS)
$(PROGRAMS): $(SOURCES)
$(CXX) $(CFLAGS) -I$(HEADER_DIR)/.. -I.. -L$(LIB_DIR) $@.cpp $(LIBS) -o $@
clean:
@echo "[Cleaning]"
rm -rf $(PROGRAMS)
install: all
@echo "[Installing examples to $(EXAMPLES_DIR)]"
@mkdir -p $(EXAMPLES_DIR)
@for prog in $(PROGRAMS); do \
install -m 0755 $${prog} $(EXAMPLES_DIR)/$(BINARY_PREFIX)-$${prog}; \
done
upload: all
@echo "[Uploading examples to $(REMOTE):$(REMOTE_EXAMPLES_DIR)]"
ifeq ($(REMOTE),)
@echo "[ERROR] Remote machine not configured. Run configure with respective arguments."
@exit 1
endif
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "mkdir -p $(REMOTE_EXAMPLES_DIR)"
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "mkdir -p /tmp/RF24_examples"
@scp -q -P $(REMOTE_PORT) $(PROGRAMS) $(REMOTE):/tmp/RF24_examples
@for prog in $(PROGRAMS); do \
ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "sudo install -m 0755 /tmp/RF24_examples/$${prog} $(REMOTE_EXAMPLES_DIR)/$(BINARY_PREFIX)-$${prog}"; \
done
@ssh -q -t -p $(REMOTE_PORT) $(REMOTE) "rm -rf /tmp/RF24_examples"
.PHONY: install upload

View File

@ -0,0 +1,24 @@
#############################################################################
#
# 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
#
ifeq ($(wildcard ../../Makefile.inc), )
$(error Configuration not found. Run ./configure first)
endif
include ../../Makefile.inc
# define all programs
PROGRAMS = rpi-hub scanner
include ../Makefile.examples

View File

@ -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/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_24, 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;
}

View File

@ -0,0 +1,143 @@
/*
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/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_24, BCM2835_SPI_SPEED_8MHZ);
// Generic setup
RF24 radio(22, 0);
//
// Channel info
//
const uint8_t num_channels = 126;
uint8_t values[num_channels];
const int num_reps = 100;
int reset_array=0;
int main(int argc, char** argv)
{
//
// Print preamble
//
//Serial.begin(115200);
//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)
{
// 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(128);
radio.stopListening();
// Did we get a carrier?
if ( radio.testCarrier() ) ++values[i];
}
}
// 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

View File

@ -0,0 +1,216 @@
/*
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 <unistd.h>
#include <RF24/RF24.h>
using namespace std;
//
// Hardware configuration
// Configure the appropriate pins for your connections
/****************** Raspberry Pi ***********************/
// Radio CE Pin, CSN Pin, SPI Speed
// See http://www.airspayce.com/mikem/bcm2835/group__constants.html#ga63c029bd6500167152db4e57736d0939 and the related enumerations for pin information.
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// NEW: Setup for RPi B+
//RF24 radio(RPI_BPLUS_GPIO_J8_15,RPI_BPLUS_GPIO_J8_24, BCM2835_SPI_SPEED_8MHZ);
// Setup for GPIO 15 CE and CE0 CSN with SPI Speed @ 8Mhz
//RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
// RPi generic:
RF24 radio(22,0);
/*** RPi Alternate ***/
//Note: Specify SPI BUS 0 or 1 instead of CS pin number.
// See http://tmrh20.github.io/RF24/RPi.html for more information on usage
//RPi Alternate, with MRAA
//RF24 radio(15,0);
//RPi Alternate, with SPIDEV - Note: Edit RF24/arch/BBB/spi.cpp and set 'this->device = "/dev/spidev0.0";;' or as listed in /dev
//RF24 radio(22,0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://tmrh20.github.io/RF24/pages.html for more information on usage
// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// Setup for ARM(Linux) devices like BBB using spidev (default is "/dev/spidev1.0" )
//RF24 radio(115,0);
//BBB Alternate, with mraa
// CE pin = (Header P9, Pin 13) = 59 = 13 + 46
//Note: Specify SPI BUS 0 or 1 instead of CS pin number.
//RF24 radio(59,0);
/********** User Config *********/
// Assign a unique identifier for this node, 0 or 1
bool radioNumber = 1;
/********************************/
// Radio pipe addresses for the 2 nodes to communicate.
const uint8_t pipes[][6] = {"1Node","2Node"};
int main(int argc, char** argv){
bool role_ping_out = true, role_pong_back = false;
bool role = role_pong_back;
cout << "RF24/examples/GettingStarted/\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 ( !radioNumber ) {
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 ) {
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);
}
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
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.
while(radio.available()){
radio.read( &got_time, sizeof(unsigned long) );
}
radio.stopListening();
radio.write( &got_time, sizeof(unsigned long) );
// Now, resume listening so we catch the next packets.
radio.startListening();
// Spew it
printf("Got payload(%d) %lu...\n",sizeof(unsigned long), got_time);
delay(925); //Delay after payload responded to, minimize RPi CPU time
}
}
} // forever loop
return 0;
}

View File

@ -0,0 +1,169 @@
/*
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 <unistd.h>
#include <RF24/RF24.h>
using namespace std;
//
// Hardware configuration
// Configure the appropriate pins for your connections
/****************** Raspberry Pi ***********************/
// Radio CE Pin, CSN Pin, SPI Speed
// See http://www.airspayce.com/mikem/bcm2835/group__constants.html#ga63c029bd6500167152db4e57736d0939 and the related enumerations for pin information.
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// NEW: Setup for RPi B+
//RF24 radio(RPI_BPLUS_GPIO_J8_15,RPI_BPLUS_GPIO_J8_24, BCM2835_SPI_SPEED_8MHZ);
// Setup for GPIO 15 CE and CE0 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
/*** RPi Alternate ***/
//Note: Specify SPI BUS 0 or 1 instead of CS pin number.
// See http://tmrh20.github.io/RF24/RPi.html for more information on usage
//RPi Alternate, with MRAA
//RF24 radio(15,0);
//RPi Alternate, with SPIDEV - Note: Edit RF24/arch/BBB/spi.cpp and set 'this->device = "/dev/spidev0.0";;' or as listed in /dev
//RF24 radio(22,0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://tmrh20.github.io/RF24/pages.html for more information on usage
// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// Setup for ARM(Linux) devices like BBB using spidev (default is "/dev/spidev1.0" )
//RF24 radio(115,0);
//BBB Alternate, with mraa
// CE pin = (Header P9, Pin 13) = 59 = 13 + 46
//Note: Specify SPI BUS 0 or 1 instead of CS pin number.
//RF24 radio(59,0);
/********** User Config *********/
// Assign a unique identifier for this node, 0 or 1. Arduino example uses radioNumber 0 by default.
bool radioNumber = 1;
/********************************/
// Radio pipe addresses for the 2 nodes to communicate.
const uint8_t addresses[][6] = {"1Node","2Node"};
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){
cout << "RPi/RF24/examples/gettingstarted_call_response\n";
radio.begin();
radio.enableAckPayload(); // Allow optional ack payloads
radio.enableDynamicPayloads();
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 opens two pipes for these two nodes to communicate
// back and forth.
if ( !radioNumber ) {
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
}else{
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
}
radio.startListening();
radio.writeAckPayload(1,&counter,1);
// 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
if( radio.available(&pipeNo)){ // Read all available payloads
radio.read( &gotByte, 1 );
// Since this is a call-response. Respond directly with an ack payload.
gotByte += 1; // 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("Loaded next response %d \n\r", gotByte);
delay(900); //Delay after a response to minimize CPU usage on RPi
//Expects a payload every second
}
}
} //while 1
} //main

View File

@ -0,0 +1,24 @@
#############################################################################
#
# 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
#
ifeq ($(wildcard ../../Makefile.inc), )
$(error Configuration not found. Run ./configure first)
endif
include ../../Makefile.inc
# define all programs
PROGRAMS = gettingstarted_call_response_int gettingstarted_call_response_int2 transfer_interrupt pingpair_dyn_int
include ../Makefile.examples

View File

@ -0,0 +1,143 @@
/*
TMRh20 2014 - Updated to work with optimized RF24 Arduino library
*/
/**
* Example for efficient call-response using ack-payloads and interrupts
*
* 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 <unistd.h>
#include <RF24/RF24.h>
using namespace std;
//
// Hardware configuration
// Configure the appropriate pins for your connections
/****************** Raspberry Pi ***********************/
RF24 radio(22,0); //GPIO, SPI-BUS
/********** User Config *********/
// Assign a unique identifier for this node, 0 or 1. Arduino example uses radioNumber 0 by default.
bool radioNumber = 1;
int interruptPin = 23;
/********************************/
// Radio pipe addresses for the 2 nodes to communicate.
const uint8_t addresses[][6] = {"1Node","2Node"};
volatile 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
volatile bool gotResponse = false;
void intHandler(){
if ( role == role_pong_back ) {
uint8_t pipeNo, gotByte; // Declare variables for the pipe and the byte received
if( radio.available(&pipeNo)){ // Read all available payloads
radio.read( &gotByte, 1 );
// Since this is a call-response. Respond directly with an ack payload.
gotByte += 1; // 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("Loaded next response %d \n\r", gotByte);
}
}
}
int main(int argc, char** argv){
cout << "RPi/RF24/examples/gettingstarted_call_response_int\n";
radio.begin();
radio.enableAckPayload(); // Allow optional ack payloads
radio.enableDynamicPayloads();
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 opens two pipes for these two nodes to communicate
// back and forth.
if ( !radioNumber ) {
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
}else{
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
}
radio.startListening();
radio.writeAckPayload(1,&counter,1);
radio.maskIRQ(1,1,0); //Mask tx_ok & tx_fail interrupts
attachInterrupt(interruptPin, INT_EDGE_FALLING, intHandler); //Attach interrupt to bcm pin 23
// 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 ***************************/
} //while 1
} //main

View File

@ -0,0 +1,155 @@
/*
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 <unistd.h>
#include <RF24/RF24.h>
using namespace std;
//
// Hardware configuration
// Configure the appropriate pins for your connections
/****************** Raspberry Pi ***********************/
RF24 radio(22,0);
/********** User Config *********/
// Assign a unique identifier for this node, 0 or 1. Arduino example uses radioNumber 0 by default.
bool radioNumber = 1;
int interruptPin = 23;
/********************************/
// Radio pipe addresses for the 2 nodes to communicate.
const uint8_t addresses[][6] = {"1Node","2Node"};
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
uint32_t timer = 0;
void intHandler(){
bool tx_ok,tx_fail,rx;
radio.whatHappened(tx_ok,tx_fail,rx);
if(tx_fail){
printf("Sending failed.\n\r");
}
if(role == role_ping_out && tx_ok){
if(!radio.available()){
printf("Got blank response. round-trip delay: %u ms\n\r",millis()-timer);
}
}
if(role == role_ping_out ){
while(radio.available() ){
uint8_t gotByte;
radio.read( &gotByte, 1 );
printf("Got response %d, round-trip delay: %u ms\n\r",gotByte,millis()-timer);
counter++;
}
}
if ( role == role_pong_back){
if(tx_ok) {
printf("Ack Payload Sent\n");
}
uint8_t pipeNo, gotByte;
if( radio.available(&pipeNo)){
radio.read( &gotByte, 1 );
gotByte += 1;
radio.writeAckPayload(pipeNo,&gotByte, 1 );
printf("Loaded next response %d \n\r", gotByte);
}
}
}
int main(int argc, char** argv){
cout << "RPi/RF24/examples/gettingstarted_call_response\n";
radio.begin();
radio.enableAckPayload(); // Allow optional ack payloads
radio.enableDynamicPayloads();
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 opens two pipes for these two nodes to communicate
// back and forth.
if ( !radioNumber ) {
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
}else{
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
}
radio.startListening();
radio.writeAckPayload(1,&counter,1);
attachInterrupt(interruptPin, INT_EDGE_FALLING, intHandler); //Attach interrupt to bcm pin 23
// 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
timer = millis(); // Record the current microsecond count
radio.startWrite(&counter,1,false); // Send the counter variable to the other radio
sleep(1); // Try again later
}
/****************** Pong Back Role ***************************/
} //while 1
} //main

View File

@ -0,0 +1,183 @@
/*
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/RF24.h>
using namespace std;
//
// Hardware configuration
// Configure the appropriate pins for your connections
/****************** Raspberry Pi ***********************/
RF24 radio(22,0); // CE GPIO, CSN SPI-BUS
int interruptPin = 23; // GPIO pin for interrupts
/**************************************************************/
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
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
bool role_ping_out = 1, role_pong_back = 0;
bool role = 0;
void intHandler(){
//
// 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=0;
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();
}
}
}
int main(int argc, char** argv){
// Print preamble:
cout << "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();
}
attachInterrupt(interruptPin, INT_EDGE_FALLING, intHandler); //Attach interrupt to bcm pin 23
// 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);
}
}
}

View File

@ -0,0 +1,192 @@
/*
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/RF24.h>
#include <unistd.h>
using namespace std;
//
// Hardware configuration
//
/****************** Raspberry Pi ***********************/
// Radio CE Pin, CSN Pin, SPI Speed
// See http://www.airspayce.com/mikem/bcm2835/group__constants.html#ga63c029bd6500167152db4e57736d0939 and the related enumerations for pin information.
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// NEW: Setup for RPi B+
//RF24 radio(RPI_BPLUS_GPIO_J8_15,RPI_BPLUS_GPIO_J8_24, BCM2835_SPI_SPEED_8MHZ);
// Setup for GPIO 15 CE and CE0 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
/*** RPi Alternate ***/
//Note: Specify SPI BUS 0 or 1 instead of CS pin number.
// See http://tmrh20.github.io/RF24/RPi.html for more information on usage
//RPi Alternate, with MRAA
//RF24 radio(15,0);
//RPi Alternate, with SPIDEV - Note: Edit RF24/arch/BBB/spi.cpp and set 'this->device = "/dev/spidev0.0";;' or as listed in /dev
//RF24 radio(22,0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://tmrh20.github.io/RF24/pages.html for more information on usage
// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// Setup for ARM(Linux) devices like BBB using spidev (default is "/dev/spidev1.0" )
//RF24 radio(115,0);
//BBB Alternate, with mraa
// CE pin = (Header P9, Pin 13) = 59 = 13 + 46
//Note: Specify SPI BUS 0 or 1 instead of CS pin number.
//RF24 radio(59,0);
/**************************************************************/
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t addresses[2] = { 0xABCDABCD71LL, 0x544d52687CLL };
uint8_t data[32];
unsigned long startTime, stopTime, counter, rxTimer=0;
void intHandler()
{
//Read as long data is available
//Single interrupts may be lost if a lot of data comes in.
while(radio.available())
{
radio.read(&data,32);
counter++;
}
}
int main(int argc, char** argv){
bool role_ping_out = 1, role_pong_back = 0;
bool role = 0;
// Print preamble:
cout << "RF24/examples/Transfer/\n";
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); // Use 8-bit CRC for performance
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);
attachInterrupt(23, INT_EDGE_FALLING, intHandler); //Attach interrupt to bcm pin 23
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[1]);
radio.openReadingPipe(1,addresses[0]);
radio.stopListening();
} else {
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
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.
// unsigned long pauseTime = millis(); //Uncomment if autoAck == 1 ( NOACK )
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
}
//This is only required when NO ACK ( enableAutoAck(0) ) payloads are used
/* if(millis() - pauseTime > 3){ // Need to drop out of TX mode every 4ms if sending a steady stream of multicast data
pauseTime = millis();
radio.txStandBy(); // This gives the PLL time to sync back up
}
*/
}
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)
{
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;
}
delay(2);
}
} // loop
} // main

View File

@ -0,0 +1,211 @@
/*
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
// Configure the appropriate pins for your connections
/****************** Raspberry Pi ***********************/
// Radio CE Pin, CSN Pin, SPI Speed
// See http://www.airspayce.com/mikem/bcm2835/group__constants.html#ga63c029bd6500167152db4e57736d0939 and the related enumerations for pin information.
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// NEW: Setup for RPi B+
//RF24 radio(RPI_BPLUS_GPIO_J8_15,RPI_BPLUS_GPIO_J8_24, BCM2835_SPI_SPEED_8MHZ);
// Setup for GPIO 15 CE and CE0 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
/*** RPi Alternate ***/
//Note: Specify SPI BUS 0 or 1 instead of CS pin number.
// See http://tmrh20.github.io/RF24/RPi.html for more information on usage
//RPi Alternate, with MRAA
//RF24 radio(15,0);
//RPi Alternate, with SPIDEV - Note: Edit RF24/arch/BBB/spi.cpp and set 'this->device = "/dev/spidev0.0";;' or as listed in /dev
//RF24 radio(22,0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://tmrh20.github.io/RF24/pages.html for more information on usage
// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// Setup for ARM(Linux) devices like BBB using spidev (default is "/dev/spidev1.0" )
//RF24 radio(115,0);
//BBB Alternate, with mraa
// CE pin = (Header P9, Pin 13) = 59 = 13 + 46
//Note: Specify SPI BUS 0 or 1 instead of CS pin number.
//RF24 radio(59,0);
/**************************************************************/
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
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){
bool role_ping_out = 1, role_pong_back = 0;
bool role = 0;
// Print preamble:
cout << "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();
}
}
}
}

View File

@ -0,0 +1,141 @@
#!/usr/bin/env python
#
# Example using Dynamic Payloads
#
# This is an example of how to use payloads of a varying (dynamic) size.
#
from __future__ import print_function
import time
from RF24 import *
import RPi.GPIO as GPIO
irq_gpio_pin = None
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
# CE Pin, CSN Pin, SPI Speed
# Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 8Mhz
#radio = RF24(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ)
#RPi B
# Setup for GPIO 15 CE and CE1 CSN with SPI Speed @ 8Mhz
#radio = RF24(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ)
#RPi B+
# Setup for GPIO 22 CE and CE0 CSN for RPi B+ with SPI Speed @ 8Mhz
#radio = RF24(RPI_BPLUS_GPIO_J8_15, RPI_BPLUS_GPIO_J8_24, BCM2835_SPI_SPEED_8MHZ)
# RPi Alternate, with SPIDEV - Note: Edit RF24/arch/BBB/spi.cpp and set 'this->device = "/dev/spidev0.0";;' or as listed in /dev
radio = RF24(22, 0);
# Setup for connected IRQ pin, GPIO 24 on RPi B+; uncomment to activate
#irq_gpio_pin = RPI_BPLUS_GPIO_J8_18
#irq_gpio_pin = 24
##########################################
def try_read_data(channel=0):
if radio.available():
while radio.available():
len = radio.getDynamicPayloadSize()
receive_payload = radio.read(len)
print('Got payload size={} value="{}"'.format(len, receive_payload.decode('utf-8')))
# First, stop listening so we can talk
radio.stopListening()
# Send the final one back.
radio.write(receive_payload)
print('Sent response.')
# Now, resume listening so we catch the next packets.
radio.startListening()
pipes = [0xF0F0F0F0E1, 0xF0F0F0F0D2]
min_payload_size = 4
max_payload_size = 32
payload_size_increments_by = 1
next_payload_size = min_payload_size
inp_role = 'none'
send_payload = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ789012'
millis = lambda: int(round(time.time() * 1000))
print('pyRF24/examples/pingpair_dyn/')
radio.begin()
radio.enableDynamicPayloads()
radio.setRetries(5,15)
radio.printDetails()
print(' ************ Role Setup *********** ')
while (inp_role !='0') and (inp_role !='1'):
inp_role = str(input('Choose a role: Enter 0 for receiver, 1 for transmitter (CTRL+C to exit) '))
if inp_role == '0':
print('Role: Pong Back, awaiting transmission')
if irq_gpio_pin is not None:
# set up callback for irq pin
GPIO.setmode(GPIO.BCM)
GPIO.setup(irq_gpio_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(irq_gpio_pin, GPIO.FALLING, callback=try_read_data)
radio.openWritingPipe(pipes[1])
radio.openReadingPipe(1,pipes[0])
radio.startListening()
else:
print('Role: Ping Out, starting transmission')
radio.openWritingPipe(pipes[0])
radio.openReadingPipe(1,pipes[1])
# forever loop
while 1:
if inp_role == '1': # ping out
# The payload will always be the same, what will change is how much of it we send.
# First, stop listening so we can talk.
radio.stopListening()
# Take the time, and send it. This will block until complete
print('Now sending length {} ... '.format(next_payload_size), end="")
radio.write(send_payload[:next_payload_size])
# Now, continue listening
radio.startListening()
# Wait here until we get a response, or timeout
started_waiting_at = millis()
timeout = False
while (not radio.available()) and (not timeout):
if (millis() - started_waiting_at) > 500:
timeout = True
# Describe the results
if timeout:
print('failed, response timed out.')
else:
# Grab the response, compare, and send to debugging spew
len = radio.getDynamicPayloadSize()
receive_payload = radio.read(len)
# Spew it
print('got response size={} value="{}"'.format(len, receive_payload.decode('utf-8')))
# 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
time.sleep(0.1)
else:
# Pong back role. Receive each packet, dump it out, and send it back
# if there is data ready
if irq_gpio_pin is None:
# no irq pin is set up -> poll it
try_read_data()
else:
# callback routine set for irq pin takes care for reading -
# do nothing, just sleeps in order not to burn cpu by looping
time.sleep(1000)

View File

@ -0,0 +1,3 @@
Note: These examples were originally designed for RPi, but should work on any supported Linux platform, with the proper pin configuration.
See http://tmrh20.github.io/RF24 for more information

View File

@ -0,0 +1,187 @@
/*
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/RF24.h>
#include <unistd.h>
using namespace std;
//
// Hardware configuration
//
/****************** Raspberry Pi ***********************/
// Radio CE Pin, CSN Pin, SPI Speed
// See http://www.airspayce.com/mikem/bcm2835/group__constants.html#ga63c029bd6500167152db4e57736d0939 and the related enumerations for pin information.
// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);
// NEW: Setup for RPi B+
//RF24 radio(RPI_BPLUS_GPIO_J8_15,RPI_BPLUS_GPIO_J8_24, BCM2835_SPI_SPEED_8MHZ);
// Setup for GPIO 15 CE and CE0 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
/*** RPi Alternate ***/
//Note: Specify SPI BUS 0 or 1 instead of CS pin number.
// See http://tmrh20.github.io/RF24/RPi.html for more information on usage
//RPi Alternate, with MRAA
//RF24 radio(15,0);
//RPi Alternate, with SPIDEV - Note: Edit RF24/arch/BBB/spi.cpp and set 'this->device = "/dev/spidev0.0";;' or as listed in /dev
//RF24 radio(22,0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://tmrh20.github.io/RF24/pages.html for more information on usage
// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
// Setup for ARM(Linux) devices like BBB using spidev (default is "/dev/spidev1.0" )
//RF24 radio(115,0);
//BBB Alternate, with mraa
// CE pin = (Header P9, Pin 13) = 59 = 13 + 46
//Note: Specify SPI BUS 0 or 1 instead of CS pin number.
//RF24 radio(59,0);
/**************************************************************/
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t addresses[2] = { 0xABCDABCD71LL, 0x544d52687CLL };
uint8_t data[32];
unsigned long startTime, stopTime, counter, rxTimer=0;
int main(int argc, char** argv){
bool role_ping_out = 1, role_pong_back = 0;
bool role = 0;
// Print preamble:
cout << "RF24/examples/Transfer/\n";
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); // Use 8-bit CRC for performance
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[1]);
radio.openReadingPipe(1,addresses[0]);
radio.stopListening();
} else {
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
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.
// unsigned long pauseTime = millis(); //Uncomment if autoAck == 1 ( NOACK )
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
}
//This is only required when NO ACK ( enableAutoAck(0) ) payloads are used
/* if(millis() - pauseTime > 3){ // Need to drop out of TX mode every 4ms if sending a steady stream of multicast data
pauseTime = millis();
radio.txStandBy(); // This gives the PLL time to sync back up
}
*/
}
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

16
lib/RF24/keywords.txt Normal file
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

20
lib/RF24/library.json Normal file
View File

@ -0,0 +1,20 @@
{
"name": "RF24",
"keywords": "rf, radio, wireless, spi",
"description": "Optimized High Speed Driver for nRF24L01(+) 2.4GHz Wireless Transceiver",
"repository":
{
"type": "git",
"url": "https://github.com/nRF24/RF24.git"
},
"version": "1.3.3",
"frameworks": "arduino",
"platforms": [
"atmelavr",
"atmelsam",
"teensy",
"espressif32",
"espressif8266",
"linux_arm"
]
}

View File

@ -0,0 +1,9 @@
name=RF24
version=1.3.3
author=TMRh20
maintainer=TMRh20,Avamander
sentence=A library for NRF24L01(+) communication.
paragraph=Optimized library for nRF24L01(+) that is simple to use for beginners, but yet offers a lot for advanced users. It also has a lot of good examples how to use the library.
category=Communication
url=https://tmrh20.github.io/RF24/
architectures=avr,arm,x86,esp8266,esp32

127
lib/RF24/nRF24L01.h Normal file
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 NRF_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 NRF_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 RF24_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

44
lib/RF24/printf.h Normal file
View File

@ -0,0 +1,44 @@
/*
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.
*/
/* Galileo support from spaniakos <spaniakos@gmail.com> */
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#if defined (ARDUINO_ARCH_AVR) || defined(__ARDUINO_X86__)
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
#endif
void printf_begin(void)
{
#if defined (ARDUINO_ARCH_AVR)
fdevopen( &serial_putc, 0 );
#elif defined (__ARDUINO_X86__)
//JESUS - For reddirect stdout to /dev/ttyGS0 (Serial Monitor port)
stdout = freopen("/dev/ttyGS0","w",stdout);
delay(500);
printf("redirecting to Serial...");
#endif
}
#endif // __PRINTF_H__

View File

@ -0,0 +1,38 @@
import sys
from distutils import unixccompiler
from distutils import ccompiler
def register():
sys.modules['distutils.crossunixccompiler'] = sys.modules[__name__]
ccompiler.compiler_class['crossunix'] = (__name__,
'CrossUnixCCompiler',
'UNIX-style compiler for cross compilation')
def try_remove_all(lst, starts):
lst[:] = [x for x in lst if not x.startswith(starts)]
class CrossUnixCCompiler(unixccompiler.UnixCCompiler):
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
try_remove_all(self.compiler_so, ('-m64', '-fstack-protector-strong', '-mtune=generic'))
try_remove_all(cc_args, '-I/usr')
try_remove_all(pp_opts, '-I/usr')
return unixccompiler.UnixCCompiler._compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts)
def link(self, target_desc, objects,
output_filename, output_dir=None, libraries=None,
library_dirs=None, runtime_library_dirs=None,
export_symbols=None, debug=0, extra_preargs=None,
extra_postargs=None, build_temp=None, target_lang=None):
try_remove_all(self.library_dirs, ('/usr'))
return unixccompiler.UnixCCompiler.link(self, target_desc, objects, output_filename, output_dir, libraries,
library_dirs, runtime_library_dirs, export_symbols, debug,
extra_preargs, extra_postargs, build_temp, target_lang)
def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs):
self.__class__ = unixccompiler.UnixCCompiler
ret = unixccompiler.UnixCCompiler._fix_lib_args(self, libraries, library_dirs, runtime_library_dirs)
self.__class__ = CrossUnixCCompiler
return ret

330
lib/RF24/pyRF24/pyRF24.cpp Normal file
View File

@ -0,0 +1,330 @@
#include <RF24/RF24.h>
#include <boost/python.hpp>
namespace bp = boost::python;
// ******************** explicit wrappers **************************
// for methods which need it - mostly for buffer operations
//
void throw_ba_exception(void)
{
PyErr_SetString(PyExc_TypeError, "buf parameter must be bytes or bytearray");
bp::throw_error_already_set();
}
char *get_bytes_or_bytearray_str(bp::object buf)
{
PyObject *py_ba;
py_ba = buf.ptr();
if (PyByteArray_Check(py_ba))
return PyByteArray_AsString(py_ba);
else if (PyBytes_Check(py_ba))
return PyBytes_AsString(py_ba);
else
throw_ba_exception();
return NULL;
}
int get_bytes_or_bytearray_ln(bp::object buf)
{
PyObject *py_ba;
py_ba = buf.ptr();
if (PyByteArray_Check(py_ba))
return PyByteArray_Size(py_ba);
else if (PyBytes_Check(py_ba))
return PyBytes_Size(py_ba);
else
throw_ba_exception();
return 0;
}
bp::object read_wrap(RF24& ref, int maxlen)
{
char *buf = new char[maxlen+1];
ref.read(buf, maxlen);
bp::object py_ba(bp::handle<>(PyByteArray_FromStringAndSize(buf, maxlen<ref.getPayloadSize()?maxlen:ref.getPayloadSize())));
delete[] buf;
return py_ba;
}
bool write_wrap1(RF24& ref, bp::object buf)
{
return ref.write(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf));
}
bool write_wrap2(RF24& ref, bp::object buf, const bool multicast)
{
return ref.write(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), multicast);
}
void writeAckPayload_wrap(RF24& ref, uint8_t pipe, bp::object buf)
{
ref.writeAckPayload(pipe, get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf));
}
bool writeFast_wrap1(RF24& ref, bp::object buf)
{
return ref.writeFast(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf));
}
bool writeFast_wrap2(RF24& ref, bp::object buf, const bool multicast)
{
return ref.writeFast(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), multicast);
}
bool writeBlocking_wrap(RF24& ref, bp::object buf, uint32_t timeout)
{
return ref.writeBlocking(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), timeout);
}
void startFastWrite_wrap1(RF24& ref, bp::object buf, const bool multicast)
{
ref.startFastWrite(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), multicast);
}
void startFastWrite_wrap2(RF24& ref, bp::object buf, const bool multicast, bool startTx)
{
ref.startFastWrite(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), multicast, startTx);
}
void startWrite_wrap(RF24& ref, bp::object buf, const bool multicast)
{
ref.startWrite(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), multicast);
}
void openWritingPipe_wrap(RF24& ref, const bp::object address)
{
ref.openWritingPipe((const uint8_t *)(get_bytes_or_bytearray_str(address)));
}
void openReadingPipe_wrap(RF24& ref, uint8_t number, const bp::object address)
{
ref.openReadingPipe(number, (const uint8_t *)(get_bytes_or_bytearray_str(address)));
}
bp::tuple whatHappened_wrap(RF24& ref)
{
bool tx_ok;
bool tx_fail;
bool tx_ready;
ref.whatHappened(tx_ok, tx_fail, tx_ready);
return bp::make_tuple(tx_ok, tx_fail, tx_ready);
}
bp::tuple available_wrap(RF24& ref)
{
bool result;
uint8_t pipe;
result = ref.available(&pipe);
return bp::make_tuple(result, pipe);
}
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(txStandBy_wrap1, RF24::txStandBy, 0, 2)
//BOOST_PYTHON_FUNCTION_OVERLOADS(txStandBy_wrap2, RF24::txStandBy, 1, 2)
// ******************** enums **************************
// from both RF24 and bcm2835
//
BOOST_PYTHON_MODULE(RF24){
#ifdef BCM2835_H
bp::enum_< RPiGPIOPin>("RPiGPIOPin")
.value("RPI_GPIO_P1_03", RPI_GPIO_P1_03)
.value("RPI_GPIO_P1_05", RPI_GPIO_P1_05)
.value("RPI_GPIO_P1_07", RPI_GPIO_P1_07)
.value("RPI_GPIO_P1_08", RPI_GPIO_P1_08)
.value("RPI_GPIO_P1_10", RPI_GPIO_P1_10)
.value("RPI_GPIO_P1_11", RPI_GPIO_P1_11)
.value("RPI_GPIO_P1_12", RPI_GPIO_P1_12)
.value("RPI_GPIO_P1_13", RPI_GPIO_P1_13)
.value("RPI_GPIO_P1_15", RPI_GPIO_P1_15)
.value("RPI_GPIO_P1_16", RPI_GPIO_P1_16)
.value("RPI_GPIO_P1_18", RPI_GPIO_P1_18)
.value("RPI_GPIO_P1_19", RPI_GPIO_P1_19)
.value("RPI_GPIO_P1_21", RPI_GPIO_P1_21)
.value("RPI_GPIO_P1_22", RPI_GPIO_P1_22)
.value("RPI_GPIO_P1_23", RPI_GPIO_P1_23)
.value("RPI_GPIO_P1_24", RPI_GPIO_P1_24)
.value("RPI_GPIO_P1_26", RPI_GPIO_P1_26)
.value("RPI_V2_GPIO_P1_03", RPI_V2_GPIO_P1_03)
.value("RPI_V2_GPIO_P1_05", RPI_V2_GPIO_P1_05)
.value("RPI_V2_GPIO_P1_07", RPI_V2_GPIO_P1_07)
.value("RPI_V2_GPIO_P1_08", RPI_V2_GPIO_P1_08)
.value("RPI_V2_GPIO_P1_10", RPI_V2_GPIO_P1_10)
.value("RPI_V2_GPIO_P1_11", RPI_V2_GPIO_P1_11)
.value("RPI_V2_GPIO_P1_12", RPI_V2_GPIO_P1_12)
.value("RPI_V2_GPIO_P1_13", RPI_V2_GPIO_P1_13)
.value("RPI_V2_GPIO_P1_15", RPI_V2_GPIO_P1_15)
.value("RPI_V2_GPIO_P1_16", RPI_V2_GPIO_P1_16)
.value("RPI_V2_GPIO_P1_18", RPI_V2_GPIO_P1_18)
.value("RPI_V2_GPIO_P1_19", RPI_V2_GPIO_P1_19)
.value("RPI_V2_GPIO_P1_21", RPI_V2_GPIO_P1_21)
.value("RPI_V2_GPIO_P1_22", RPI_V2_GPIO_P1_22)
.value("RPI_V2_GPIO_P1_23", RPI_V2_GPIO_P1_23)
.value("RPI_V2_GPIO_P1_24", RPI_V2_GPIO_P1_24)
.value("RPI_V2_GPIO_P1_26", RPI_V2_GPIO_P1_26)
.value("RPI_V2_GPIO_P5_03", RPI_V2_GPIO_P5_03)
.value("RPI_V2_GPIO_P5_04", RPI_V2_GPIO_P5_04)
.value("RPI_V2_GPIO_P5_05", RPI_V2_GPIO_P5_05)
.value("RPI_V2_GPIO_P5_06", RPI_V2_GPIO_P5_06)
.value("RPI_BPLUS_GPIO_J8_03", RPI_BPLUS_GPIO_J8_03)
.value("RPI_BPLUS_GPIO_J8_05", RPI_BPLUS_GPIO_J8_05)
.value("RPI_BPLUS_GPIO_J8_07", RPI_BPLUS_GPIO_J8_07)
.value("RPI_BPLUS_GPIO_J8_08", RPI_BPLUS_GPIO_J8_08)
.value("RPI_BPLUS_GPIO_J8_10", RPI_BPLUS_GPIO_J8_10)
.value("RPI_BPLUS_GPIO_J8_11", RPI_BPLUS_GPIO_J8_11)
.value("RPI_BPLUS_GPIO_J8_12", RPI_BPLUS_GPIO_J8_12)
.value("RPI_BPLUS_GPIO_J8_13", RPI_BPLUS_GPIO_J8_13)
.value("RPI_BPLUS_GPIO_J8_15", RPI_BPLUS_GPIO_J8_15)
.value("RPI_BPLUS_GPIO_J8_16", RPI_BPLUS_GPIO_J8_16)
.value("RPI_BPLUS_GPIO_J8_18", RPI_BPLUS_GPIO_J8_18)
.value("RPI_BPLUS_GPIO_J8_19", RPI_BPLUS_GPIO_J8_19)
.value("RPI_BPLUS_GPIO_J8_21", RPI_BPLUS_GPIO_J8_21)
.value("RPI_BPLUS_GPIO_J8_22", RPI_BPLUS_GPIO_J8_22)
.value("RPI_BPLUS_GPIO_J8_23", RPI_BPLUS_GPIO_J8_23)
.value("RPI_BPLUS_GPIO_J8_24", RPI_BPLUS_GPIO_J8_24)
.value("RPI_BPLUS_GPIO_J8_26", RPI_BPLUS_GPIO_J8_26)
.value("RPI_BPLUS_GPIO_J8_29", RPI_BPLUS_GPIO_J8_29)
.value("RPI_BPLUS_GPIO_J8_31", RPI_BPLUS_GPIO_J8_31)
.value("RPI_BPLUS_GPIO_J8_32", RPI_BPLUS_GPIO_J8_32)
.value("RPI_BPLUS_GPIO_J8_33", RPI_BPLUS_GPIO_J8_33)
.value("RPI_BPLUS_GPIO_J8_35", RPI_BPLUS_GPIO_J8_35)
.value("RPI_BPLUS_GPIO_J8_36", RPI_BPLUS_GPIO_J8_36)
.value("RPI_BPLUS_GPIO_J8_37", RPI_BPLUS_GPIO_J8_37)
.value("RPI_BPLUS_GPIO_J8_38", RPI_BPLUS_GPIO_J8_38)
.value("RPI_BPLUS_GPIO_J8_40", RPI_BPLUS_GPIO_J8_40)
.export_values()
;
bp::enum_< bcm2835SPIClockDivider>("bcm2835SPIClockDivider")
.value("BCM2835_SPI_CLOCK_DIVIDER_65536", BCM2835_SPI_CLOCK_DIVIDER_65536)
.value("BCM2835_SPI_CLOCK_DIVIDER_32768", BCM2835_SPI_CLOCK_DIVIDER_32768)
.value("BCM2835_SPI_CLOCK_DIVIDER_16384", BCM2835_SPI_CLOCK_DIVIDER_16384)
.value("BCM2835_SPI_CLOCK_DIVIDER_8192", BCM2835_SPI_CLOCK_DIVIDER_8192)
.value("BCM2835_SPI_CLOCK_DIVIDER_4096", BCM2835_SPI_CLOCK_DIVIDER_4096)
.value("BCM2835_SPI_CLOCK_DIVIDER_2048", BCM2835_SPI_CLOCK_DIVIDER_2048)
.value("BCM2835_SPI_CLOCK_DIVIDER_1024", BCM2835_SPI_CLOCK_DIVIDER_1024)
.value("BCM2835_SPI_CLOCK_DIVIDER_512", BCM2835_SPI_CLOCK_DIVIDER_512)
.value("BCM2835_SPI_CLOCK_DIVIDER_256", BCM2835_SPI_CLOCK_DIVIDER_256)
.value("BCM2835_SPI_CLOCK_DIVIDER_128", BCM2835_SPI_CLOCK_DIVIDER_128)
.value("BCM2835_SPI_CLOCK_DIVIDER_64", BCM2835_SPI_CLOCK_DIVIDER_64)
.value("BCM2835_SPI_CLOCK_DIVIDER_32", BCM2835_SPI_CLOCK_DIVIDER_32)
.value("BCM2835_SPI_CLOCK_DIVIDER_16", BCM2835_SPI_CLOCK_DIVIDER_16)
.value("BCM2835_SPI_CLOCK_DIVIDER_8", BCM2835_SPI_CLOCK_DIVIDER_8)
.value("BCM2835_SPI_CLOCK_DIVIDER_4", BCM2835_SPI_CLOCK_DIVIDER_4)
.value("BCM2835_SPI_CLOCK_DIVIDER_2", BCM2835_SPI_CLOCK_DIVIDER_2)
.value("BCM2835_SPI_CLOCK_DIVIDER_1", BCM2835_SPI_CLOCK_DIVIDER_1)
.export_values();
bp::enum_< bcm2835SPIChipSelect>("bcm2835SPIChipSelect")
.value("BCM2835_SPI_CS0", BCM2835_SPI_CS0)
.value("BCM2835_SPI_CS1", BCM2835_SPI_CS1)
.value("BCM2835_SPI_CS2", BCM2835_SPI_CS2)
.value("BCM2835_SPI_CS_NONE", BCM2835_SPI_CS_NONE)
.export_values();
// exposing '#define's for SPI speed as this is needed for RF24 constructor
bp::scope().attr("BCM2835_SPI_SPEED_64MHZ") = BCM2835_SPI_SPEED_64MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_32MHZ") = BCM2835_SPI_SPEED_32MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_16MHZ") = BCM2835_SPI_SPEED_16MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_8MHZ") = BCM2835_SPI_SPEED_8MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_4MHZ") = BCM2835_SPI_SPEED_4MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_2MHZ") = BCM2835_SPI_SPEED_2MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_1MHZ") = BCM2835_SPI_SPEED_1MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_512KHZ") = BCM2835_SPI_SPEED_512KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_256KHZ") = BCM2835_SPI_SPEED_256KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_128KHZ") = BCM2835_SPI_SPEED_128KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_64KHZ") = BCM2835_SPI_SPEED_64KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_32KHZ") = BCM2835_SPI_SPEED_32KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_16KHZ") = BCM2835_SPI_SPEED_16KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_8KHZ") = BCM2835_SPI_SPEED_8KHZ;
#endif // BCM2835_H
bp::enum_< rf24_crclength_e>("rf24_crclength_e")
.value("RF24_CRC_DISABLED", RF24_CRC_DISABLED)
.value("RF24_CRC_8", RF24_CRC_8)
.value("RF24_CRC_16", RF24_CRC_16)
.export_values()
;
bp::enum_< rf24_datarate_e>("rf24_datarate_e")
.value("RF24_1MBPS", RF24_1MBPS)
.value("RF24_2MBPS", RF24_2MBPS)
.value("RF24_250KBPS", RF24_250KBPS)
.export_values()
;
bp::enum_< rf24_pa_dbm_e>("rf24_pa_dbm_e")
.value("RF24_PA_MIN", RF24_PA_MIN)
.value("RF24_PA_LOW", RF24_PA_LOW)
.value("RF24_PA_HIGH", RF24_PA_HIGH)
.value("RF24_PA_MAX", RF24_PA_MAX)
.value("RF24_PA_ERROR", RF24_PA_ERROR)
.export_values()
;
// ******************** RF24 class **************************
//
bp::class_< RF24 >( "RF24", bp::init< uint8_t, uint8_t >(( bp::arg("_cepin"), bp::arg("_cspin") )) )
#if defined (RF24_LINUX) && !defined (MRAA)
.def( bp::init< uint8_t, uint8_t, uint32_t >(( bp::arg("_cepin"), bp::arg("_cspin"), bp::arg("spispeed") )) )
#endif
.def("available", (bool ( ::RF24::* )( ) )( &::RF24::available ) )
.def("available_pipe", &available_wrap ) // needed to rename this method as python does not allow such overloading
.def("begin", &RF24::begin)
.def("closeReadingPipe", &RF24::closeReadingPipe)
.def("disableCRC", &RF24::disableCRC)
.def("enableAckPayload", &RF24::enableAckPayload)
.def("enableDynamicAck", &RF24::enableDynamicAck)
.def("enableDynamicPayloads", &RF24::enableDynamicPayloads)
.def("flush_tx", &RF24::flush_tx)
.def("getCRCLength", &RF24::getCRCLength)
.def("getDataRate", &RF24::getDataRate)
.def("getDynamicPayloadSize", &RF24::getDynamicPayloadSize)
.def("getPALevel", &RF24::getPALevel)
.def("isAckPayloadAvailable", &RF24::isAckPayloadAvailable)
.def("isPVariant", &RF24::isPVariant)
.def("isValid", &RF24::isValid)
.def("maskIRQ", &RF24::maskIRQ, ( bp::arg("tx_ok"), bp::arg("tx_fail"), bp::arg("rx_ready")))
.def("openReadingPipe", &openReadingPipe_wrap, (bp::arg("number"), bp::arg("address")))
.def("openReadingPipe", (void ( ::RF24::* )( ::uint8_t,::uint64_t ) )( &::RF24::openReadingPipe), (bp::arg("number"), bp::arg("address")))
.def("openWritingPipe", &openWritingPipe_wrap, (bp::arg("address")))
.def("openWritingPipe", (void ( ::RF24::* )( ::uint64_t ) )( &::RF24::openWritingPipe), ( bp::arg("address") ) )
.def("powerDown", &RF24::powerDown)
.def("powerUp", &RF24::powerUp)
.def("printDetails", &RF24::printDetails)
.def("reUseTX", &RF24::reUseTX)
.def("read", &read_wrap, (bp::arg("maxlen")))
.def("rxFifoFull", &RF24::rxFifoFull)
.def("setAddressWidth", &RF24::setAddressWidth)
.def("setAutoAck", (void ( ::RF24::* )( bool ) )( &::RF24::setAutoAck ), ( bp::arg("enable") ) )
.def("setAutoAck", (void ( ::RF24::* )( ::uint8_t,bool ) )( &::RF24::setAutoAck ), ( bp::arg("pipe"), bp::arg("enable") ) )
.def("setCRCLength", &RF24::setCRCLength, ( bp::arg("length") ) )
.def("setChannel", &RF24::setChannel, ( bp::arg("channel") ) )
.def("setDataRate", &RF24::setDataRate, ( bp::arg("speed") ) )
.def("setPALevel", &RF24::setPALevel, ( bp::arg("level") ) )
.def("setRetries", &RF24::setRetries , (bp::arg("delay"), bp::arg("count")))
.def("startFastWrite", &startFastWrite_wrap1, ( bp::arg("buf"), bp::arg("len"), bp::arg("multicast") ) )
.def("startFastWrite", &startFastWrite_wrap2, ( bp::arg("buf"), bp::arg("len"), bp::arg("multicast"), bp::arg("startTx") ) )
.def("startListening", &RF24::startListening)
.def("startWrite", &startWrite_wrap, ( bp::arg("buf"), bp::arg("len"), bp::arg("multicast") ) )
.def("stopListening", &RF24::stopListening)
.def("testCarrier", &RF24::testCarrier)
.def("testRPD", &RF24::testRPD)
.def("txStandBy", (bool ( ::RF24::* )( ::uint32_t,bool))(&RF24::txStandBy), txStandBy_wrap1( bp::args("timeout", "startTx") ) )
.def("whatHappened", &whatHappened_wrap)
.def("write", &write_wrap1, ( bp::arg("buf") ) )
.def("write", &write_wrap2, ( bp::arg("buf"), bp::arg("multicast") ) )
.def("writeAckPayload", writeAckPayload_wrap, ( bp::arg("pipe"), bp::arg("buf") ) )
.def("writeBlocking", &writeBlocking_wrap, ( bp::arg("buf"), bp::arg("timeout") ) )
.def("writeFast", &writeFast_wrap1, ( bp::arg("buf") ) )
.def("writeFast", &writeFast_wrap2, ( bp::arg("buf"), bp::arg("multicast") ) )
.add_property("payloadSize", &RF24::getPayloadSize, &RF24::setPayloadSize)
.def_readwrite( "failureDetected", &RF24::failureDetected );
}

View File

@ -0,0 +1,38 @@
import sys
from distutils import unixccompiler
from distutils import ccompiler
def register():
sys.modules['distutils.crossunixccompiler'] = sys.modules[__name__]
ccompiler.compiler_class['crossunix'] = (__name__,
'CrossUnixCCompiler',
'UNIX-style compiler for cross compilation')
def try_remove_all(lst, starts):
lst[:] = [x for x in lst if not x.startswith(starts)]
class CrossUnixCCompiler(unixccompiler.UnixCCompiler):
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
try_remove_all(self.compiler_so, ('-m64', '-fstack-protector-strong', '-mtune=generic'))
try_remove_all(cc_args, '-I/usr')
try_remove_all(pp_opts, '-I/usr')
return unixccompiler.UnixCCompiler._compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts)
def link(self, target_desc, objects,
output_filename, output_dir=None, libraries=None,
library_dirs=None, runtime_library_dirs=None,
export_symbols=None, debug=0, extra_preargs=None,
extra_postargs=None, build_temp=None, target_lang=None):
try_remove_all(self.library_dirs, ('/usr'))
return unixccompiler.UnixCCompiler.link(self, target_desc, objects, output_filename, output_dir, libraries,
library_dirs, runtime_library_dirs, export_symbols, debug,
extra_preargs, extra_postargs, build_temp, target_lang)
def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs):
self.__class__ = unixccompiler.UnixCCompiler
ret = unixccompiler.UnixCCompiler._fix_lib_args(self, libraries, library_dirs, runtime_library_dirs)
self.__class__ = CrossUnixCCompiler
return ret

View File

@ -0,0 +1,328 @@
#include <RF24/RF24.h>
#include <boost/python.hpp>
namespace bp = boost::python;
// ******************** explicit wrappers **************************
// for methods which need it - mostly for buffer operations
//
void throw_ba_exception(void)
{
PyErr_SetString(PyExc_TypeError, "buf parameter must be bytes or bytearray");
bp::throw_error_already_set();
}
char *get_bytes_or_bytearray_str(bp::object buf)
{
PyObject *py_ba;
py_ba = buf.ptr();
if (PyByteArray_Check(py_ba))
return PyByteArray_AsString(py_ba);
else if (PyBytes_Check(py_ba))
return PyBytes_AsString(py_ba);
else
throw_ba_exception();
return NULL;
}
int get_bytes_or_bytearray_ln(bp::object buf)
{
PyObject *py_ba;
py_ba = buf.ptr();
if (PyByteArray_Check(py_ba))
return PyByteArray_Size(py_ba);
else if (PyBytes_Check(py_ba))
return PyBytes_Size(py_ba);
else
throw_ba_exception();
return 0;
}
bp::object read_wrap(RF24& ref, int maxlen)
{
char *buf = new char[maxlen+1];
ref.read(buf, maxlen);
bp::object py_ba(bp::handle<>(PyByteArray_FromStringAndSize(buf, maxlen<ref.getPayloadSize()?maxlen:ref.getPayloadSize())));
delete[] buf;
return py_ba;
}
bool write_wrap1(RF24& ref, bp::object buf)
{
return ref.write(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf));
}
bool write_wrap2(RF24& ref, bp::object buf, const bool multicast)
{
return ref.write(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), multicast);
}
void writeAckPayload_wrap(RF24& ref, uint8_t pipe, bp::object buf)
{
ref.writeAckPayload(pipe, get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf));
}
bool writeFast_wrap1(RF24& ref, bp::object buf)
{
return ref.writeFast(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf));
}
bool writeFast_wrap2(RF24& ref, bp::object buf, const bool multicast)
{
return ref.writeFast(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), multicast);
}
bool writeBlocking_wrap(RF24& ref, bp::object buf, uint32_t timeout)
{
return ref.writeBlocking(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), timeout);
}
void startFastWrite_wrap1(RF24& ref, bp::object buf, const bool multicast)
{
ref.startFastWrite(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), multicast);
}
void startFastWrite_wrap2(RF24& ref, bp::object buf, const bool multicast, bool startTx)
{
ref.startFastWrite(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), multicast, startTx);
}
void startWrite_wrap(RF24& ref, bp::object buf, const bool multicast)
{
ref.startWrite(get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), multicast);
}
void openWritingPipe_wrap(RF24& ref, const bp::object address)
{
ref.openWritingPipe((const uint8_t *)(get_bytes_or_bytearray_str(address)));
}
void openReadingPipe_wrap(RF24& ref, uint8_t number, const bp::object address)
{
ref.openReadingPipe(number, (const uint8_t *)(get_bytes_or_bytearray_str(address)));
}
bp::tuple whatHappened_wrap(RF24& ref)
{
bool tx_ok;
bool tx_fail;
bool tx_ready;
ref.whatHappened(tx_ok, tx_fail, tx_ready);
return bp::make_tuple(tx_ok, tx_fail, tx_ready);
}
bp::tuple available_wrap(RF24& ref)
{
bool result;
uint8_t pipe;
result = ref.available(&pipe);
return bp::make_tuple(result, pipe);
}
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(txStandBy_wrap1, RF24::txStandBy, 0, 2)
//BOOST_PYTHON_FUNCTION_OVERLOADS(txStandBy_wrap2, RF24::txStandBy, 1, 2)
// ******************** enums **************************
// from both RF24 and bcm2835
//
BOOST_PYTHON_MODULE(RF24){
#ifdef BCM2835_H
bp::enum_< RPiGPIOPin>("RPiGPIOPin")
.value("RPI_GPIO_P1_03", RPI_GPIO_P1_03)
.value("RPI_GPIO_P1_05", RPI_GPIO_P1_05)
.value("RPI_GPIO_P1_07", RPI_GPIO_P1_07)
.value("RPI_GPIO_P1_08", RPI_GPIO_P1_08)
.value("RPI_GPIO_P1_10", RPI_GPIO_P1_10)
.value("RPI_GPIO_P1_11", RPI_GPIO_P1_11)
.value("RPI_GPIO_P1_12", RPI_GPIO_P1_12)
.value("RPI_GPIO_P1_13", RPI_GPIO_P1_13)
.value("RPI_GPIO_P1_15", RPI_GPIO_P1_15)
.value("RPI_GPIO_P1_16", RPI_GPIO_P1_16)
.value("RPI_GPIO_P1_18", RPI_GPIO_P1_18)
.value("RPI_GPIO_P1_19", RPI_GPIO_P1_19)
.value("RPI_GPIO_P1_21", RPI_GPIO_P1_21)
.value("RPI_GPIO_P1_22", RPI_GPIO_P1_22)
.value("RPI_GPIO_P1_23", RPI_GPIO_P1_23)
.value("RPI_GPIO_P1_24", RPI_GPIO_P1_24)
.value("RPI_GPIO_P1_26", RPI_GPIO_P1_26)
.value("RPI_V2_GPIO_P1_03", RPI_V2_GPIO_P1_03)
.value("RPI_V2_GPIO_P1_05", RPI_V2_GPIO_P1_05)
.value("RPI_V2_GPIO_P1_07", RPI_V2_GPIO_P1_07)
.value("RPI_V2_GPIO_P1_08", RPI_V2_GPIO_P1_08)
.value("RPI_V2_GPIO_P1_10", RPI_V2_GPIO_P1_10)
.value("RPI_V2_GPIO_P1_11", RPI_V2_GPIO_P1_11)
.value("RPI_V2_GPIO_P1_12", RPI_V2_GPIO_P1_12)
.value("RPI_V2_GPIO_P1_13", RPI_V2_GPIO_P1_13)
.value("RPI_V2_GPIO_P1_15", RPI_V2_GPIO_P1_15)
.value("RPI_V2_GPIO_P1_16", RPI_V2_GPIO_P1_16)
.value("RPI_V2_GPIO_P1_18", RPI_V2_GPIO_P1_18)
.value("RPI_V2_GPIO_P1_19", RPI_V2_GPIO_P1_19)
.value("RPI_V2_GPIO_P1_21", RPI_V2_GPIO_P1_21)
.value("RPI_V2_GPIO_P1_22", RPI_V2_GPIO_P1_22)
.value("RPI_V2_GPIO_P1_23", RPI_V2_GPIO_P1_23)
.value("RPI_V2_GPIO_P1_24", RPI_V2_GPIO_P1_24)
.value("RPI_V2_GPIO_P1_26", RPI_V2_GPIO_P1_26)
.value("RPI_V2_GPIO_P5_03", RPI_V2_GPIO_P5_03)
.value("RPI_V2_GPIO_P5_04", RPI_V2_GPIO_P5_04)
.value("RPI_V2_GPIO_P5_05", RPI_V2_GPIO_P5_05)
.value("RPI_V2_GPIO_P5_06", RPI_V2_GPIO_P5_06)
.value("RPI_BPLUS_GPIO_J8_03", RPI_BPLUS_GPIO_J8_03)
.value("RPI_BPLUS_GPIO_J8_05", RPI_BPLUS_GPIO_J8_05)
.value("RPI_BPLUS_GPIO_J8_07", RPI_BPLUS_GPIO_J8_07)
.value("RPI_BPLUS_GPIO_J8_08", RPI_BPLUS_GPIO_J8_08)
.value("RPI_BPLUS_GPIO_J8_10", RPI_BPLUS_GPIO_J8_10)
.value("RPI_BPLUS_GPIO_J8_11", RPI_BPLUS_GPIO_J8_11)
.value("RPI_BPLUS_GPIO_J8_12", RPI_BPLUS_GPIO_J8_12)
.value("RPI_BPLUS_GPIO_J8_13", RPI_BPLUS_GPIO_J8_13)
.value("RPI_BPLUS_GPIO_J8_15", RPI_BPLUS_GPIO_J8_15)
.value("RPI_BPLUS_GPIO_J8_16", RPI_BPLUS_GPIO_J8_16)
.value("RPI_BPLUS_GPIO_J8_18", RPI_BPLUS_GPIO_J8_18)
.value("RPI_BPLUS_GPIO_J8_19", RPI_BPLUS_GPIO_J8_19)
.value("RPI_BPLUS_GPIO_J8_21", RPI_BPLUS_GPIO_J8_21)
.value("RPI_BPLUS_GPIO_J8_22", RPI_BPLUS_GPIO_J8_22)
.value("RPI_BPLUS_GPIO_J8_23", RPI_BPLUS_GPIO_J8_23)
.value("RPI_BPLUS_GPIO_J8_24", RPI_BPLUS_GPIO_J8_24)
.value("RPI_BPLUS_GPIO_J8_26", RPI_BPLUS_GPIO_J8_26)
.value("RPI_BPLUS_GPIO_J8_29", RPI_BPLUS_GPIO_J8_29)
.value("RPI_BPLUS_GPIO_J8_31", RPI_BPLUS_GPIO_J8_31)
.value("RPI_BPLUS_GPIO_J8_32", RPI_BPLUS_GPIO_J8_32)
.value("RPI_BPLUS_GPIO_J8_33", RPI_BPLUS_GPIO_J8_33)
.value("RPI_BPLUS_GPIO_J8_35", RPI_BPLUS_GPIO_J8_35)
.value("RPI_BPLUS_GPIO_J8_36", RPI_BPLUS_GPIO_J8_36)
.value("RPI_BPLUS_GPIO_J8_37", RPI_BPLUS_GPIO_J8_37)
.value("RPI_BPLUS_GPIO_J8_38", RPI_BPLUS_GPIO_J8_38)
.value("RPI_BPLUS_GPIO_J8_40", RPI_BPLUS_GPIO_J8_40)
.export_values()
;
bp::enum_< bcm2835SPIClockDivider>("bcm2835SPIClockDivider")
.value("BCM2835_SPI_CLOCK_DIVIDER_65536", BCM2835_SPI_CLOCK_DIVIDER_65536)
.value("BCM2835_SPI_CLOCK_DIVIDER_32768", BCM2835_SPI_CLOCK_DIVIDER_32768)
.value("BCM2835_SPI_CLOCK_DIVIDER_16384", BCM2835_SPI_CLOCK_DIVIDER_16384)
.value("BCM2835_SPI_CLOCK_DIVIDER_8192", BCM2835_SPI_CLOCK_DIVIDER_8192)
.value("BCM2835_SPI_CLOCK_DIVIDER_4096", BCM2835_SPI_CLOCK_DIVIDER_4096)
.value("BCM2835_SPI_CLOCK_DIVIDER_2048", BCM2835_SPI_CLOCK_DIVIDER_2048)
.value("BCM2835_SPI_CLOCK_DIVIDER_1024", BCM2835_SPI_CLOCK_DIVIDER_1024)
.value("BCM2835_SPI_CLOCK_DIVIDER_512", BCM2835_SPI_CLOCK_DIVIDER_512)
.value("BCM2835_SPI_CLOCK_DIVIDER_256", BCM2835_SPI_CLOCK_DIVIDER_256)
.value("BCM2835_SPI_CLOCK_DIVIDER_128", BCM2835_SPI_CLOCK_DIVIDER_128)
.value("BCM2835_SPI_CLOCK_DIVIDER_64", BCM2835_SPI_CLOCK_DIVIDER_64)
.value("BCM2835_SPI_CLOCK_DIVIDER_32", BCM2835_SPI_CLOCK_DIVIDER_32)
.value("BCM2835_SPI_CLOCK_DIVIDER_16", BCM2835_SPI_CLOCK_DIVIDER_16)
.value("BCM2835_SPI_CLOCK_DIVIDER_8", BCM2835_SPI_CLOCK_DIVIDER_8)
.value("BCM2835_SPI_CLOCK_DIVIDER_4", BCM2835_SPI_CLOCK_DIVIDER_4)
.value("BCM2835_SPI_CLOCK_DIVIDER_2", BCM2835_SPI_CLOCK_DIVIDER_2)
.value("BCM2835_SPI_CLOCK_DIVIDER_1", BCM2835_SPI_CLOCK_DIVIDER_1)
.export_values();
bp::enum_< bcm2835SPIChipSelect>("bcm2835SPIChipSelect")
.value("BCM2835_SPI_CS0", BCM2835_SPI_CS0)
.value("BCM2835_SPI_CS1", BCM2835_SPI_CS1)
.value("BCM2835_SPI_CS2", BCM2835_SPI_CS2)
.value("BCM2835_SPI_CS_NONE", BCM2835_SPI_CS_NONE)
.export_values();
// exposing '#define's for SPI speed as this is needed for RF24 constructor
bp::scope().attr("BCM2835_SPI_SPEED_64MHZ") = BCM2835_SPI_SPEED_64MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_32MHZ") = BCM2835_SPI_SPEED_32MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_16MHZ") = BCM2835_SPI_SPEED_16MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_8MHZ") = BCM2835_SPI_SPEED_8MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_4MHZ") = BCM2835_SPI_SPEED_4MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_2MHZ") = BCM2835_SPI_SPEED_2MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_1MHZ") = BCM2835_SPI_SPEED_1MHZ;
bp::scope().attr("BCM2835_SPI_SPEED_512KHZ") = BCM2835_SPI_SPEED_512KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_256KHZ") = BCM2835_SPI_SPEED_256KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_128KHZ") = BCM2835_SPI_SPEED_128KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_64KHZ") = BCM2835_SPI_SPEED_64KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_32KHZ") = BCM2835_SPI_SPEED_32KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_16KHZ") = BCM2835_SPI_SPEED_16KHZ;
bp::scope().attr("BCM2835_SPI_SPEED_8KHZ") = BCM2835_SPI_SPEED_8KHZ;
#endif // BCM2835_H
bp::enum_< rf24_crclength_e>("rf24_crclength_e")
.value("RF24_CRC_DISABLED", RF24_CRC_DISABLED)
.value("RF24_CRC_8", RF24_CRC_8)
.value("RF24_CRC_16", RF24_CRC_16)
.export_values()
;
bp::enum_< rf24_datarate_e>("rf24_datarate_e")
.value("RF24_1MBPS", RF24_1MBPS)
.value("RF24_2MBPS", RF24_2MBPS)
.value("RF24_250KBPS", RF24_250KBPS)
.export_values()
;
bp::enum_< rf24_pa_dbm_e>("rf24_pa_dbm_e")
.value("RF24_PA_MIN", RF24_PA_MIN)
.value("RF24_PA_LOW", RF24_PA_LOW)
.value("RF24_PA_HIGH", RF24_PA_HIGH)
.value("RF24_PA_MAX", RF24_PA_MAX)
.value("RF24_PA_ERROR", RF24_PA_ERROR)
.export_values()
;
// ******************** RF24 class **************************
//
bp::class_< RF24 >( "RF24", bp::init< uint8_t, uint8_t >(( bp::arg("_cepin"), bp::arg("_cspin") )) )
.def( bp::init< uint8_t, uint8_t, uint32_t >(( bp::arg("_cepin"), bp::arg("_cspin"), bp::arg("spispeed") )) )
.def("available", (bool ( ::RF24::* )( ) )( &::RF24::available ) )
.def("available_pipe", &available_wrap ) // needed to rename this method as python does not allow such overloading
.def("begin", &RF24::begin)
.def("closeReadingPipe", &RF24::closeReadingPipe)
.def("disableCRC", &RF24::disableCRC)
.def("enableAckPayload", &RF24::enableAckPayload)
.def("enableDynamicAck", &RF24::enableDynamicAck)
.def("enableDynamicPayloads", &RF24::enableDynamicPayloads)
.def("flush_tx", &RF24::flush_tx)
.def("getCRCLength", &RF24::getCRCLength)
.def("getDataRate", &RF24::getDataRate)
.def("getDynamicPayloadSize", &RF24::getDynamicPayloadSize)
.def("getPALevel", &RF24::getPALevel)
.def("isAckPayloadAvailable", &RF24::isAckPayloadAvailable)
.def("isPVariant", &RF24::isPVariant)
.def("isValid", &RF24::isValid)
.def("maskIRQ", &RF24::maskIRQ, ( bp::arg("tx_ok"), bp::arg("tx_fail"), bp::arg("rx_ready")))
.def("openReadingPipe", &openReadingPipe_wrap, (bp::arg("number"), bp::arg("address")))
.def("openReadingPipe", (void ( ::RF24::* )( ::uint8_t,::uint64_t ) )( &::RF24::openReadingPipe), (bp::arg("number"), bp::arg("address")))
.def("openWritingPipe", &openWritingPipe_wrap, (bp::arg("address")))
.def("openWritingPipe", (void ( ::RF24::* )( ::uint64_t ) )( &::RF24::openWritingPipe), ( bp::arg("address") ) )
.def("powerDown", &RF24::powerDown)
.def("powerUp", &RF24::powerUp)
.def("printDetails", &RF24::printDetails)
.def("reUseTX", &RF24::reUseTX)
.def("read", &read_wrap, (bp::arg("maxlen")))
.def("rxFifoFull", &RF24::rxFifoFull)
.def("setAddressWidth", &RF24::setAddressWidth)
.def("setAutoAck", (void ( ::RF24::* )( bool ) )( &::RF24::setAutoAck ), ( bp::arg("enable") ) )
.def("setAutoAck", (void ( ::RF24::* )( ::uint8_t,bool ) )( &::RF24::setAutoAck ), ( bp::arg("pipe"), bp::arg("enable") ) )
.def("setCRCLength", &RF24::setCRCLength, ( bp::arg("length") ) )
.def("setChannel", &RF24::setChannel, ( bp::arg("channel") ) )
.def("setDataRate", &RF24::setDataRate, ( bp::arg("speed") ) )
.def("setPALevel", &RF24::setPALevel, ( bp::arg("level") ) )
.def("setRetries", &RF24::setRetries , (bp::arg("delay"), bp::arg("count")))
.def("startFastWrite", &startFastWrite_wrap1, ( bp::arg("buf"), bp::arg("len"), bp::arg("multicast") ) )
.def("startFastWrite", &startFastWrite_wrap2, ( bp::arg("buf"), bp::arg("len"), bp::arg("multicast"), bp::arg("startTx") ) )
.def("startListening", &RF24::startListening)
.def("startWrite", &startWrite_wrap, ( bp::arg("buf"), bp::arg("len"), bp::arg("multicast") ) )
.def("stopListening", &RF24::stopListening)
.def("testCarrier", &RF24::testCarrier)
.def("testRPD", &RF24::testRPD)
.def("txStandBy", (bool ( ::RF24::* )( ::uint32_t,bool))(&RF24::txStandBy), txStandBy_wrap1( bp::args("timeout", "startTx") ) )
.def("whatHappened", &whatHappened_wrap)
.def("write", &write_wrap1, ( bp::arg("buf") ) )
.def("write", &write_wrap2, ( bp::arg("buf"), bp::arg("multicast") ) )
.def("writeAckPayload", writeAckPayload_wrap, ( bp::arg("pipe"), bp::arg("buf") ) )
.def("writeBlocking", &writeBlocking_wrap, ( bp::arg("buf"), bp::arg("timeout") ) )
.def("writeFast", &writeFast_wrap1, ( bp::arg("buf") ) )
.def("writeFast", &writeFast_wrap2, ( bp::arg("buf"), bp::arg("multicast") ) )
.add_property("payloadSize", &RF24::getPayloadSize, &RF24::setPayloadSize)
.def_readwrite( "failureDetected", &RF24::failureDetected );
}

View File

@ -0,0 +1,2 @@
Python Wrapper for RF24
See http://tmrh20.github.io/RF24 for more information

View File

@ -0,0 +1,48 @@
#!/usr/bin/env python
import os
import sys
import setuptools
import crossunixccompiler
version = ''
def process_configparams():
global version
with open('../Makefile.inc') as f:
config_lines = f.read().splitlines()
cflags = os.getenv("CFLAGS", "")
for line in config_lines:
identifier, value = line.split('=', 1)
if identifier == "CPUFLAGS":
cflags += " " + value
elif identifier == "HEADER_DIR":
cflags += " -I" + os.path.dirname(value)
elif identifier == "LIB_DIR":
cflags += " -L" + value
elif identifier == "LIB_VERSION":
version = value
elif identifier in ("CC", "CXX"):
os.environ[identifier] = value
os.environ["CFLAGS"] = cflags
if sys.version_info >= (3,):
BOOST_LIB = 'boost_python3'
else:
BOOST_LIB = 'boost_python'
process_configparams()
crossunixccompiler.register()
module_RF24 = setuptools.Extension('RF24',
libraries=['rf24', BOOST_LIB],
sources=['pyRF24.cpp'])
setuptools.setup(name='RF24',
version=version,
ext_modules=[module_RF24])

View File

@ -0,0 +1,22 @@
from RF24 import *
from RF24Network import *
from RF24Mesh import *
# radio setup for RPi B Rev2: CS0=Pin 24
radio = RF24(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ)
network = RF24Network(radio)
mesh = RF24Mesh(radio, network)
mesh.setNodeID(0)
mesh.begin(108, RF24_250KBPS)
radio.setPALevel(RF24_PA_MAX) # Power Amplifier
radio.printDetails()
while 1:
mesh.update()
mesh.DHCP()
while network.available():
print("Received message")
header, payload = network.read(10)

View File

@ -0,0 +1,105 @@
#include "boost/python.hpp"
#include "RF24/RF24.h"
#include "RF24Network/RF24Network.h"
#include "RF24Mesh/RF24Mesh.h"
namespace bp = boost::python;
// ******************** explicit wrappers **************************
// where needed, especially where buffer is involved
void throw_ba_exception(void)
{
PyErr_SetString(PyExc_TypeError, "buf parameter must be bytes or bytearray");
bp::throw_error_already_set();
}
char *get_bytes_or_bytearray_str(bp::object buf)
{
PyObject *py_ba;
py_ba = buf.ptr();
if (PyByteArray_Check(py_ba))
return PyByteArray_AsString(py_ba);
else if (PyBytes_Check(py_ba))
return PyBytes_AsString(py_ba);
else
throw_ba_exception();
return NULL;
}
int get_bytes_or_bytearray_ln(bp::object buf)
{
PyObject *py_ba;
py_ba = buf.ptr();
if (PyByteArray_Check(py_ba))
return PyByteArray_Size(py_ba);
else if (PyBytes_Check(py_ba))
return PyBytes_Size(py_ba);
else
throw_ba_exception();
return 0;
}
bool write_wrap1(RF24Mesh& ref, bp::object buf, uint8_t msg_type)
{
return ref.write(get_bytes_or_bytearray_str(buf), msg_type, get_bytes_or_bytearray_ln(buf));
}
bool write_wrap2(RF24Mesh& ref, bp::object buf, uint8_t msg_type, uint8_t nodeID)
{
return ref.write(get_bytes_or_bytearray_str(buf), msg_type, get_bytes_or_bytearray_ln(buf), nodeID);
}
bool write_to_node_wrap(RF24Mesh& ref, uint16_t to_node, bp::object buf, uint8_t msg_type)
{
return ref.write(to_node, get_bytes_or_bytearray_str(buf), msg_type, get_bytes_or_bytearray_ln(buf));
}
// ******************** overload wrappers **************************
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(begin_overload, RF24Mesh::begin, 0, 3)
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(getNodeID_overload, RF24Mesh::getNodeID, 0, 1)
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(renewAddress_overload, RF24Mesh::renewAddress, 0, 1)
// ******************** RF24Mesh exposed **************************
BOOST_PYTHON_MODULE(RF24Mesh)
{
{ //::RF24Mesh
bp::class_<RF24Mesh>("RF24Mesh", bp::init<RF24&, RF24Network&>((bp::arg("_radio"), bp::arg("_network"))))
//bool begin(uint8_t channel = MESH_DEFAULT_CHANNEL, rf24_datarate_e data_rate = RF24_1MBPS, uint32_t timeout=MESH_RENEWAL_TIMEOUT );
.def("begin", &RF24Mesh::begin, begin_overload(bp::args("channel", "data_rate", "timeout")))
//uint8_t update();
.def("update", &RF24Mesh::update)
//bool write(const void* data, uint8_t msg_type, size_t size, uint8_t nodeID=0);
.def("write", &write_wrap1, (bp::arg("data"), bp::arg("msg_type")))
.def("write", &write_wrap2, (bp::arg("data"), bp::arg("msg_type"), bp::arg("nodeID")))
//bool write(uint16_t to_node, const void* data, uint8_t msg_type, size_t size );
.def("write", &write_to_node_wrap, (bp::arg("to_node"), bp::arg("data"), bp::arg("msg_type"), bp::arg("size")))
//void setNodeID(uint8_t nodeID);
.def("setNodeID", &RF24Mesh::setNodeID, (bp::arg("nodeID")))
//void DHCP();
.def("DHCP", &RF24Mesh::DHCP)
//int16_t getNodeID(uint16_t address=MESH_BLANK_ID);
.def("getNodeID", &RF24Mesh::getNodeID, getNodeID_overload(bp::args("address")))
//bool checkConnection();
.def("checkConnection", &RF24Mesh::checkConnection)
//uint16_t renewAddress(uint32_t timeout=MESH_RENEWAL_TIMEOUT);
.def("renewAddress", &RF24Mesh::renewAddress, getNodeID_overload(bp::args("timeout")))
//bool releaseAddress();
.def("releaseAddress", &RF24Mesh::releaseAddress)
//int16_t getAddress(uint8_t nodeID);
.def("getAddress", &RF24Mesh::getAddress, (bp::arg("nodeID")))
//void setChannel(uint8_t _channel);
.def("setChannel", &RF24Mesh::setChannel, (bp::arg("_channel")))
//void setChild(bool allow);
.def("setChild", &RF24Mesh::setChild, (bp::arg("allow")))
//void setAddress(uint8_t nodeID, uint16_t address);
.def("setAddress", &RF24Mesh::setAddress, (bp::arg("nodeID"), bp::arg("address")))
//void saveDHCP();
.def("saveDHCP", &RF24Mesh::saveDHCP)
//void loadDHCP();
.def("loadDHCP", &RF24Mesh::loadDHCP)
//void setStaticAddress(uint8_t nodeID, uint16_t address);
.def("setStaticAddress", &RF24Mesh::setStaticAddress, (bp::arg("nodeID"), bp::arg("address")));
}
}

View File

@ -0,0 +1,17 @@
#!/usr/bin/env python
from distutils.core import setup, Extension
import sys
if sys.version_info >= (3,):
BOOST_LIB = 'boost_python3'
else:
BOOST_LIB = 'boost_python'
module_RF24Mesh = Extension('RF24Mesh',
libraries = ['rf24mesh', 'rf24network', BOOST_LIB],
sources = ['pyRF24Mesh.cpp'])
setup(name='RF24Mesh',
version='1.0',
ext_modules=[module_RF24Mesh])

View File

@ -0,0 +1,56 @@
#!/usr/bin/env python
#
# Simplest possible example of using RF24Network,
#
# RECEIVER NODE
# Listens for messages from the transmitter and prints them out.
#
from __future__ import print_function
import time
from struct import *
from RF24 import *
from RF24Network import *
# CE Pin, CSN Pin, SPI Speed
# Setup for GPIO 22 CE and GPIO 25 CSN with SPI Speed @ 1Mhz
#radio = 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
#radio = RF24(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ)
# Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 8Mhz
#radio = RF24(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ)
# Setup for GPIO 22 CE and CE0 CSN for RPi B+ with SPI Speed @ 8Mhz
#radio = RF24(RPI_BPLUS_GPIO_J8_22, RPI_BPLUS_GPIO_J8_24, BCM2835_SPI_SPEED_8MHZ)
radio = RF24(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ)
network = RF24Network(radio)
millis = lambda: int(round(time.time() * 1000))
octlit = lambda n:int(n, 8)
# Address of our node in Octal format (01, 021, etc)
this_node = octlit("00")
# Address of the other node
other_node = octlit("01")
radio.begin()
time.sleep(0.1)
network.begin(90, this_node) # channel 90
radio.printDetails()
packets_sent = 0
last_sent = 0
while 1:
network.update()
while network.available():
header, payload = network.read(8)
print("payload length ", len(payload))
ms, number = unpack('<LL', bytes(payload))
print('Received payload ', number, ' at ', ms, ' from ', oct(header.from_node))
time.sleep(1)

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python
#
# Simplest possible example of using RF24Network,
#
# TRANSMITTER NODE
# Sends messages from to receiver.
#
from __future__ import print_function
import time
from struct import *
from RF24 import *
from RF24Network import *
# CE Pin, CSN Pin, SPI Speed
# Setup for GPIO 22 CE and GPIO 25 CSN with SPI Speed @ 1Mhz
#radio = 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
#radio = RF24(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ)
# Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 8Mhz
#radio = RF24(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ)
# Setup for GPIO 22 CE and CE0 CSN for RPi B+ with SPI Speed @ 8Mhz
#radio = RF24(RPI_BPLUS_GPIO_J8_22, RPI_BPLUS_GPIO_J8_24, BCM2835_SPI_SPEED_8MHZ)
radio = RF24(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ)
network = RF24Network(radio)
millis = lambda: int(round(time.time() * 1000)) & 0xffffffff
octlit = lambda n:int(n, 8)
# Address of our node in Octal format (01,021, etc)
this_node = octlit("01")
# Address of the other node
other_node = octlit("00")
#ms - How long to wait before sending the next message
interval = 2000
radio.begin()
time.sleep(0.1);
network.begin(90, this_node) # channel 90
radio.printDetails()
packets_sent = 0
last_sent = 0
while 1:
network.update()
now = millis()
# If it's time to send a message, send it!
if ( now - last_sent >= interval ):
last_sent = now
print('Sending ..')
payload = pack('<LL', millis(), packets_sent )
packets_sent += 1
ok = network.write(RF24NetworkHeader(other_node), payload)
if ok:
print('ok.')
else:
print('failed.')

View File

@ -0,0 +1,143 @@
#include "boost/python.hpp"
#include "RF24/RF24.h"
#include "RF24Network/RF24Network.h"
namespace bp = boost::python;
// **************** expicit wrappers *****************
// where needed, especially where buffer is involved
//
void throw_ba_exception(void)
{
PyErr_SetString(PyExc_TypeError, "buf parameter must be bytes or bytearray");
bp::throw_error_already_set();
}
char *get_bytes_or_bytearray_str(bp::object buf)
{
PyObject *py_ba;
py_ba = buf.ptr();
if (PyByteArray_Check(py_ba))
return PyByteArray_AsString(py_ba);
else if (PyBytes_Check(py_ba))
return PyBytes_AsString(py_ba);
else
throw_ba_exception();
return NULL;
}
int get_bytes_or_bytearray_ln(bp::object buf)
{
PyObject *py_ba;
py_ba = buf.ptr();
if (PyByteArray_Check(py_ba))
return PyByteArray_Size(py_ba);
else if (PyBytes_Check(py_ba))
return PyBytes_Size(py_ba);
else
throw_ba_exception();
return 0;
}
bp::tuple read_wrap(RF24Network& ref, size_t maxlen)
{
char *buf = new char[maxlen+1];
RF24NetworkHeader header;
uint16_t len = ref.read(header, buf, maxlen);
bp::object py_ba(bp::handle<>(PyByteArray_FromStringAndSize(buf, len)));
delete[] buf;
return bp::make_tuple(header, py_ba);
}
bool write_wrap(RF24Network& ref, RF24NetworkHeader& header, bp::object buf)
{
return ref.write(header, get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf));
}
std::string toString_wrap(RF24NetworkHeader& ref)
{
return std::string(ref.toString());
}
// **************** RF24Network exposed *****************
//
BOOST_PYTHON_MODULE(RF24Network){
{ //::RF24Network
typedef bp::class_< RF24Network > RF24Network_exposer_t;
RF24Network_exposer_t RF24Network_exposer = RF24Network_exposer_t( "RF24Network", bp::init< RF24 & >(( bp::arg("_radio") )) );
bp::scope RF24Network_scope( RF24Network_exposer );
bp::implicitly_convertible< RF24 &, RF24Network >();
{ //::RF24Network::available
typedef bool ( ::RF24Network::*available_function_type )( ) ;
RF24Network_exposer.def(
"available"
, available_function_type( &::RF24Network::available ) );
}
{ //::RF24Network::begin
typedef void ( ::RF24Network::*begin_function_type )( ::uint8_t,::uint16_t ) ;
RF24Network_exposer.def(
"begin"
, begin_function_type( &::RF24Network::begin )
, ( bp::arg("_channel"), bp::arg("_node_address") ) );
}
{ //::RF24Network::parent
typedef ::uint16_t ( ::RF24Network::*parent_function_type )( ) const;
RF24Network_exposer.def(
"parent"
, parent_function_type( &::RF24Network::parent ) );
}
{ //::RF24Network::read
typedef bp::tuple ( *read_function_type )(::RF24Network&, size_t ) ;
RF24Network_exposer.def(
"read"
//, read_function_type( &::RF24Network::read )
, read_function_type( &read_wrap )
, ( bp::arg("maxlen") ) );
}
{ //::RF24Network::update
typedef void ( ::RF24Network::*update_function_type )( ) ;
RF24Network_exposer.def(
"update"
, update_function_type( &::RF24Network::update ) );
}
{ //::RF24Network::write
typedef bool ( *write_function_type )( ::RF24Network&, ::RF24NetworkHeader&, bp::object ) ;
RF24Network_exposer.def("write", write_function_type( &write_wrap ), ( bp::arg("header"), bp::arg("buf") ) );
}
RF24Network_exposer.def_readwrite( "txTimeout", &RF24Network::txTimeout );
}
// **************** RF24NetworkHeader exposed *****************
//
bp::class_< RF24NetworkHeader >( "RF24NetworkHeader", bp::init< >() )
.def( bp::init< uint16_t, bp::optional< unsigned char > >(( bp::arg("_to"), bp::arg("_type")=(unsigned char)(0) )) )
.def("toString", &toString_wrap )
.def_readwrite( "from_node", &RF24NetworkHeader::from_node )
.def_readwrite( "id", &RF24NetworkHeader::id )
.def_readwrite( "next_id", RF24NetworkHeader::next_id )
.def_readwrite( "reserved", &RF24NetworkHeader::reserved )
.def_readwrite( "to_node", &RF24NetworkHeader::to_node )
.def_readwrite( "type", &RF24NetworkHeader::type );
}

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python
from distutils.core import setup, Extension
import sys
if sys.version_info >= (3,):
BOOST_LIB = 'boost_python3'
else:
BOOST_LIB = 'boost_python'
module_RF24Network = Extension('RF24Network',
libraries = ['rf24network', BOOST_LIB],
sources = ['pyRF24Network.cpp'])
setup(name='RF24Network',
version='1.0',
ext_modules=[module_RF24Network]
)

View File

@ -0,0 +1,2 @@
Python Wrapper for RF24
See http://tmrh20.github.io/RF24 for more information

48
lib/RF24/pyRF24/setup.py Normal file
View File

@ -0,0 +1,48 @@
#!/usr/bin/env python
import os
import sys
import setuptools
import crossunixccompiler
version = ''
def process_configparams():
global version
with open('../Makefile.inc') as f:
config_lines = f.read().splitlines()
cflags = os.getenv("CFLAGS", "")
for line in config_lines:
identifier, value = line.split('=', 1)
if identifier == "CPUFLAGS":
cflags += " " + value
elif identifier == "HEADER_DIR":
cflags += " -I" + os.path.dirname(value)
elif identifier == "LIB_DIR":
cflags += " -L" + value
elif identifier == "LIB_VERSION":
version = value
elif identifier in ("CC", "CXX"):
os.environ[identifier] = value
os.environ["CFLAGS"] = cflags
if sys.version_info >= (3,):
BOOST_LIB = 'boost_python3'
else:
BOOST_LIB = 'boost_python'
process_configparams()
crossunixccompiler.register()
module_RF24 = setuptools.Extension('RF24',
libraries=['rf24', BOOST_LIB],
sources=['pyRF24.cpp'])
setuptools.setup(name='RF24',
version=version,
ext_modules=[module_RF24])

7
lib/RF24/tests/README Normal file
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

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) ;

View File

@ -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(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();
// 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

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__

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 ] ;

View File

@ -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(115200);
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

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__

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)

View File

@ -0,0 +1,5 @@
#!/bin/sh
# Connect u0 to receiver, u1 to sender
jam u0 u1 && expect test.ex

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"

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 ] ;

View File

@ -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(115200);
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;
}
}
}

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__

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)

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

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"

View File

@ -0,0 +1,47 @@
/*
TMRh20 2015
ATTiny Configuration File
*/
#ifndef __RF24_ARCH_CONFIG_H__
#define __RF24_ARCH_CONFIG_H__
/*** USER DEFINES: ***/
//#define FAILURE_HANDLING
//#define MINIMAL
/**********************/
#define rf24_max(a,b) (a>b?a:b)
#define rf24_min(a,b) (a<b?a:b)
#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif
#include <stddef.h>
// Include the header file for SPI functions ( Main SPI code is contained in RF24.cpp for simplicity )
#include "spi.h"
#define _SPI SPI
#ifdef SERIAL_DEBUG
#define IF_SERIAL_DEBUG(x) ({x;})
#else
#define IF_SERIAL_DEBUG(x)
#if defined(RF24_TINY)
#define printf_P(...)
#endif
#endif
#include <avr/pgmspace.h>
#define PRIPSTR "%S"
#endif // __RF24_ARCH_CONFIG_H__

View File

@ -0,0 +1,53 @@
// ATTiny support code is from https://github.com/jscrane/RF24
/**
* @file spi.h
* \cond HIDDEN_SYMBOLS
* Class declaration for SPI helper files
*/
#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;
/**
* \endcond
*/

View File

@ -0,0 +1,54 @@
This is a fork from **http://tmrh20.github.io/RF24** which can be build as a static library for Atmel Studio 7.
Not all files are needed.
Just copy the following structure into a GCC Static Library project in AS7:
```
utility\
ATXMega256D3\
compatibility.c
compatibility.h
gpio.cpp
gpio.h
gpio_helper.c
gpio_helper.h
includes.h
RF24_arch_config.h
spi.cpp
spi.h
nRF24L01.h
printf.h
RF24.cpp
RF24.h
RF24_config.h
```
Only ATXMega256D3 is supported right now!
## Notes
The millisecond functionality is based on the TCE0 so don't use these pins as IO.
The operating frequency of the uC is 32MHz. If else change the TCE0 registers appropriatly in function **__start_timer()** in **compatibility.c** file for your frequency.
## Usage
Add the library to your project!
In the file where the **main()** is put the following in order to update the millisecond functionality:
```
ISR(TCE0_OVF_vect)
{
update_milisec();
}
```
Declare the rf24 radio with **RF24 radio(XMEGA_PORTC_PIN3, XMEGA_SPI_PORT_C);**
First parameter is the CE pin which can be any available pin on the uC.
Second parameter is the CS which can be on port C (**XMEGA_SPI_PORT_C**) or on port D (**XMEGA_SPI_PORT_D**).
Call the **__start_timer()** to start the millisecond timer.
** For further information please see http://tmrh20.github.io/RF24 for all documentation**

View File

@ -0,0 +1,85 @@
/*
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 RF24_arch_config.h
* General defines and includes for RF24/Linux
*/
/**
* Example of RF24_arch_config.h for RF24 portability
*
* @defgroup Porting_General Porting: General
*
*
* @{
*/
#ifndef __RF24_ARCH_CONFIG_H__
#define __RF24_ARCH_CONFIG_H__
#include <stddef.h>
#include <avr/pgmspace.h>
#include "spi.h"
#include "gpio.h"
#include "compatibility.h"
#include <stdint.h>
#include <stdio.h>
//#include <time.h>
#include <string.h>
//#include <sys/time.h>
//#define _BV(x) (1<<(x))
#define _SPI spi
#undef SERIAL_DEBUG
#ifdef SERIAL_DEBUG
#define IF_SERIAL_DEBUG(x) ({x;})
#else
#define IF_SERIAL_DEBUG(x)
#endif
// Use the avr pgmspace commands
//// Avoid spurious warnings
//#if 1
//#if ! defined( NATIVE ) && defined( ARDUINO )
//#undef PROGMEM
//#define PROGMEM __attribute__(( section(".progmem.data") ))
//#undef PSTR
//#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))
//#endif
//#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"
//#define pgm_read_byte(p) (*(p))
// Function, constant map as a result of migrating from Arduino
#define LOW GPIO::OUTPUT_LOW
#define HIGH GPIO::OUTPUT_HIGH
#define INPUT GPIO::DIRECTION_IN
#define OUTPUT GPIO::DIRECTION_OUT
#define digitalWrite(pin, value) GPIO::write(pin, value)
#define pinMode(pin, direction) GPIO::open(pin, direction)
#define delay(milisec) __msleep(milisec)
#define delayMicroseconds(usec) __usleep(usec)
#define millis() __millis()
#endif // __RF24_ARCH_CONFIG_H__
/*@}*/

View File

@ -0,0 +1,67 @@
/*
* compatibility.c
*
* Created: 19/1/2016 15:31:35
* Author: akatran
*/
#include <avr/io.h>
#include <stdint.h>
#include <util/delay.h>
volatile uint32_t _millis;
void __msleep(int milisec)
{
while(milisec-- >0)
{
_delay_ms(1);
}
}
void __usleep(int usec)
{
while(usec-- >0)
{
_delay_us(1);
}
}
void __start_timer()
{
// Timer details : Clock is 32MHz, Timer resolution is 8bit, Prescaler is 256, Period is 124, Real Time is 0.001s
/* Set the timer to run at the fastest rate. */
TCE0.CTRLA = TC_CLKSEL_DIV256_gc;
/* Configure the timer for normal counting. */
TCE0.CTRLB = TC_WGMODE_NORMAL_gc;
/* At 2 MHz, one tick is 0.5 us. Set period to 8 us. */
TCE0.PER = 124;
//TCC0.PER = 2;
/* Configure timer to generate an interrupt on overflow. */
TCE0.INTCTRLA = TC_OVFINTLVL_HI_gc;
/* Enable this interrupt level. */
PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm;
_millis=0;
}
long __millis()
{
return _millis;
}
void update_milisec()
{
_millis++;
}

View File

@ -0,0 +1,45 @@
/*
* File: compatiblity.h
* Author: purinda
*
* Created on 24 June 2012, 3:08 PM
*/
/**
* @file compatibility.h
* Class declaration for SPI helper files
*/
/**
* Example of compatibility.h class declaration for timing functions portability
*
* @defgroup Porting_Timing Porting: Timing
*
*
* @{
*/
#ifndef COMPATIBLITY_H
#define COMPATIBLITY_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
//#include <time.h>
//#include <sys/time.h>
void __msleep(int milisec);
void __usleep(int usec);
void __start_timer();
long __millis();
void update_milisec();
#ifdef __cplusplus
}
#endif
#endif /* COMPATIBLITY_H */
/*@}*/

View File

@ -0,0 +1,50 @@
/*
* gpio.cpp
*
* Created: 20/1/2016 11:57:21
* Author: akatran
*/
//#include "gpio_helper.h"
#include "gpio.h"
#include <stdlib.h>
void GPIO::open(int port, int DDR)
{
uint8_t pin;
PORT_t * p = GPIO_getPort(port,&pin);
if (DDR==0)
{
p->DIRCLR=pin;
}else if (DDR==1)
{
p->DIRSET = pin;
}
}
void GPIO::close(int port)
{
// Nothing to do with close;
}
int read(int port)
{
uint8_t pin;
PORT_t * p = GPIO_getPort(port,&pin);
return p->IN;
}
void GPIO::write(int port,int value)
{
uint8_t pin;
PORT_t * p = GPIO_getPort(port,&pin);
if (value==0)
{
p->OUTCLR=pin;
}else if (value==1)
{
p->OUTSET = pin;
}
}

View File

@ -0,0 +1,63 @@
/**
* @file gpio.h
* Class declaration for SPI helper files
*/
/**
* Example of gpio.h class declaration for GPIO portability
*
* @defgroup Porting_GPIO Porting: GPIO
*
*
* @{
*/
#ifndef GPIO_H
#define GPIO_H
#include <avr/io.h>
#include "gpio_helper.h"
class GPIO {
public:
/* Constants */
static const int DIRECTION_OUT = 1;
static const int DIRECTION_IN = 0;
static const int OUTPUT_HIGH = 1;
static const int OUTPUT_LOW = 0;
GPIO();
/**
* Similar to Arduino pinMode(pin,mode);
* @param port
* @param DDR
*/
static void open(int port, int DDR);
/**
*
* @param port
*/
static void close(int port);
/**
* Similar to Arduino digitalRead(pin);
* @param port
* @param value
*/
static int read(int port);
/**
* Similar to Arduino digitalWrite(pin,state);
* @param port
* @param value
*/
static void write(int port,int value);
virtual ~GPIO();
};
#endif /* GPIO_H */
/*@}*/

View File

@ -0,0 +1,45 @@
/*
* gpio_helper.c
*
* Created: 22/1/2016 15:28:48
* Author: akatran
*/
#include "gpio_helper.h"
/**
* Get the port corresponding in portnum. Default is PORTC.
*/
PORT_t * GPIO_getPort(int pinnum, uint8_t * pin_bm)
//PORT_t * GPIO_getPort(int portnum)
{
PORT_t * port = &PORTC;
if ( (pinnum >= XMEGA_PORTA_PIN0) && (pinnum<= XMEGA_PORTA_PIN7) )
{
port = &PORTA;
*pin_bm = (1<<pinnum);
}else if ( (pinnum >= XMEGA_PORTB_PIN0) && (pinnum<= XMEGA_PORTB_PIN7) )
{
port = &PORTB;
*pin_bm = (1<<(pinnum-8));
}else if ( (pinnum >= XMEGA_PORTC_PIN0) && (pinnum<= XMEGA_PORTC_PIN7) )
{
port = &PORTC;
*pin_bm = (1<<(pinnum-16));
}else if ( (pinnum >= XMEGA_PORTD_PIN0) && (pinnum<= XMEGA_PORTD_PIN7) )
{
port = &PORTD;
*pin_bm = (1<<(pinnum-24));
}else if ( (pinnum >= XMEGA_PORTE_PIN0) && (pinnum<= XMEGA_PORTE_PIN7) )
{
port = &PORTE;
*pin_bm = (1<<(pinnum-32));
}else if ( (pinnum >= XMEGA_PORTF_PIN0) && (pinnum<= XMEGA_PORTF_PIN7) )
{
port = &PORTF;
*pin_bm = (1<<(pinnum-40));
}
return port;
}

View File

@ -0,0 +1,89 @@
/*
* gpio_helper.h
*
* Created: 22/1/2016 15:29:12
* Author: akatran
*/
#ifndef GPIO_HELPER_H_
#define GPIO_HELPER_H_
#include <avr/io.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Defines */
#define XMEGA_PORTA_PIN0 0
#define XMEGA_PORTA_PIN1 1
#define XMEGA_PORTA_PIN2 2
#define XMEGA_PORTA_PIN3 3
#define XMEGA_PORTA_PIN4 4
#define XMEGA_PORTA_PIN5 5
#define XMEGA_PORTA_PIN6 6
#define XMEGA_PORTA_PIN7 7
#define XMEGA_PORTB_PIN0 8
#define XMEGA_PORTB_PIN1 9
#define XMEGA_PORTB_PIN2 10
#define XMEGA_PORTB_PIN3 11
#define XMEGA_PORTB_PIN4 12
#define XMEGA_PORTB_PIN5 13
#define XMEGA_PORTB_PIN6 14
#define XMEGA_PORTB_PIN7 15
#define XMEGA_PORTC_PIN0 16
#define XMEGA_PORTC_PIN1 17
#define XMEGA_PORTC_PIN2 18
#define XMEGA_PORTC_PIN3 19
#define XMEGA_PORTC_PIN4 20
#define XMEGA_PORTC_PIN5 21
#define XMEGA_PORTC_PIN6 22
#define XMEGA_PORTC_PIN7 23
#define XMEGA_PORTD_PIN0 24
#define XMEGA_PORTD_PIN1 25
#define XMEGA_PORTD_PIN2 26
#define XMEGA_PORTD_PIN3 27
#define XMEGA_PORTD_PIN4 28
#define XMEGA_PORTD_PIN5 29
#define XMEGA_PORTD_PIN6 30
#define XMEGA_PORTD_PIN7 31
#define XMEGA_PORTE_PIN0 32
#define XMEGA_PORTE_PIN1 33
#define XMEGA_PORTE_PIN2 34
#define XMEGA_PORTE_PIN3 35
#define XMEGA_PORTE_PIN4 36
#define XMEGA_PORTE_PIN5 37
#define XMEGA_PORTE_PIN6 38
#define XMEGA_PORTE_PIN7 39
#define XMEGA_PORTF_PIN0 40
#define XMEGA_PORTF_PIN1 41
#define XMEGA_PORTF_PIN2 42
#define XMEGA_PORTF_PIN3 43
#define XMEGA_PORTF_PIN4 44
#define XMEGA_PORTF_PIN5 45
#define XMEGA_PORTF_PIN6 46
#define XMEGA_PORTF_PIN7 47
#define XMEGA_SPI_PORT_C 20
#define XMEGA_SPI_PORT_D 28
//void GPIO_getPort(int pinnum, PORT_t * port, uint8_t pin);
//void GPIO_getPort(int pinnum, PORT_t * port, uint8_t * pin_bm);
PORT_t * GPIO_getPort(int pinnum, uint8_t * pin_bm);
#ifdef __cplusplus
}
#endif
#endif /* GPIO_HELPER_H_ */

Some files were not shown because too many files have changed in this diff Show More