Added needed third parties libraries

This commit is contained in:
Th3maz1ng 2022-10-02 13:02:45 +02:00
parent fdf0e88a43
commit 88d236bd45
149 changed files with 28298 additions and 0 deletions

View File

@ -0,0 +1,36 @@
// **** INCLUDES *****
#include "LowPower.h"
void setup()
{
// No setup is required for this library
}
void loop()
{
// Enter idle state for 8 s with the rest of peripherals turned off
// Each microcontroller comes with different number of peripherals
// Comment off line of code where necessary
// ATmega328P, ATmega168
LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF,
SPI_OFF, USART0_OFF, TWI_OFF);
// ATmega32U4
//LowPower.idle(SLEEP_8S, ADC_OFF, TIMER4_OFF, TIMER3_OFF, TIMER1_OFF,
// TIMER0_OFF, SPI_OFF, USART1_OFF, TWI_OFF, USB_OFF);
// ATmega2560
//LowPower.idle(SLEEP_8S, ADC_OFF, TIMER5_OFF, TIMER4_OFF, TIMER3_OFF,
// TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART3_OFF,
// USART2_OFF, USART1_OFF, USART0_OFF, TWI_OFF);
// ATmega256RFR2
//LowPower.idle(SLEEP_8S, ADC_OFF, TIMER5_OFF, TIMER4_OFF, TIMER3_OFF,
// TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF,
// USART1_OFF, USART0_OFF, TWI_OFF);
// Do something here
// Example: Read sensor, data logging, data transmission.
}

View File

@ -0,0 +1,33 @@
// **** INCLUDES *****
#include "LowPower.h"
// Use pin 2 as wake up pin
const int wakeUpPin = 2;
void wakeUp()
{
// Just a handler for the pin interrupt.
}
void setup()
{
// Configure wake up pin as input.
// This will consumes few uA of current.
pinMode(wakeUpPin, INPUT);
}
void loop()
{
// Allow wake up pin to trigger interrupt on low.
attachInterrupt(0, wakeUp, LOW);
// Enter power down state with ADC and BOD module disabled.
// Wake up when wake up pin is low.
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
// Disable external pin interrupt on wake up pin.
detachInterrupt(0);
// Do something here
// Example: Read sensor, data logging, data transmission.
}

View File

@ -0,0 +1,16 @@
// **** INCLUDES *****
#include "LowPower.h"
void setup()
{
// No setup is required for this library
}
void loop()
{
// Enter power down state for 8 s with ADC and BOD module disabled
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
// Do something here
// Example: Read sensor, data logging, data transmission.
}

View File

@ -0,0 +1,59 @@
// **** INCLUDES *****
#include "LowPower.h"
// External interrupt on pin 0 (use pin 0 to 24, except pin 4 on Arduino Zero)
const int pin = 0;
unsigned char count = 10;
void setup()
{
// Wait for serial USB port to open
while(!SerialUSB);
SerialUSB.println("***** ATSAMD21 Standby Mode Example *****");
// ***** IMPORTANT *****
// Delay is required to allow the USB interface to be active during
// sketch upload process
SerialUSB.println("Entering standby mode in:");
for (count; count > 0; count--)
{
SerialUSB.print(count);
SerialUSB.println(" s");
delay(1000);
}
// *********************
// External interrupt on pin (example: press of an active low button)
// A pullup resistor is used to hold the signal high when no button press
attachInterrupt(pin, blink, LOW);
}
void loop()
{
SerialUSB.println("Entering standby mode.");
SerialUSB.println("Apply low signal to wake the processor.");
SerialUSB.println("Zzzz...");
// Detach USB interface
USBDevice.detach();
// Enter standby mode
LowPower.standby();
// Attach USB interface
USBDevice.attach();
// Wait for serial USB port to open
while(!SerialUSB);
// Serial USB is blazing fast, you might miss the messages
delay(1000);
SerialUSB.println("Awake!");
SerialUSB.println("Send any character to enter standby mode again");
// Wait for user response
while(!SerialUSB.available());
while(SerialUSB.available() > 0)
{
SerialUSB.read();
}
}
void blink(void)
{
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,173 @@
#ifndef LowPower_h
#define LowPower_h
#include "Arduino.h"
enum period_t
{
SLEEP_15MS,
SLEEP_30MS,
SLEEP_60MS,
SLEEP_120MS,
SLEEP_250MS,
SLEEP_500MS,
SLEEP_1S,
SLEEP_2S,
SLEEP_4S,
SLEEP_8S,
SLEEP_FOREVER
};
enum bod_t
{
BOD_OFF,
BOD_ON
};
enum adc_t
{
ADC_OFF,
ADC_ON
};
enum timer5_t
{
TIMER5_OFF,
TIMER5_ON
};
enum timer4_t
{
TIMER4_OFF,
TIMER4_ON
};
enum timer3_t
{
TIMER3_OFF,
TIMER3_ON
};
enum timer2_t
{
TIMER2_OFF,
TIMER2_ON
};
enum timer1_t
{
TIMER1_OFF,
TIMER1_ON
};
enum timer0_t
{
TIMER0_OFF,
TIMER0_ON
};
enum spi_t
{
SPI_OFF,
SPI_ON
};
enum usart0_t
{
USART0_OFF,
USART0_ON
};
enum usart1_t
{
USART1_OFF,
USART1_ON
};
enum usart2_t
{
USART2_OFF,
USART2_ON
};
enum usart3_t
{
USART3_OFF,
USART3_ON
};
enum twi_t
{
TWI_OFF,
TWI_ON
};
enum usb_t
{
USB_OFF,
USB_ON
};
enum idle_t
{
IDLE_0,
IDLE_1,
IDLE_2
};
class LowPowerClass
{
public:
#if defined (__AVR__)
#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__) || defined (__AVR_ATmega88__)
void idle(period_t period, adc_t adc, timer2_t timer2,
timer1_t timer1, timer0_t timer0, spi_t spi,
usart0_t usart0, twi_t twi);
#elif defined __AVR_ATmega644P__ || defined (__AVR_ATmega1284P__)
void idle(period_t period, adc_t adc, timer2_t timer2,
timer1_t timer1, timer0_t timer0, spi_t spi,
usart1_t usart1, usart0_t usart0, twi_t twi);
#elif defined __AVR_ATmega2560__
void idle(period_t period, adc_t adc, timer5_t timer5,
timer4_t timer4, timer3_t timer3, timer2_t timer2,
timer1_t timer1, timer0_t timer0, spi_t spi,
usart3_t usart3, usart2_t usart2, usart1_t usart1,
usart0_t usart0, twi_t twi);
#elif defined __AVR_ATmega256RFR2__
void idle(period_t period, adc_t adc, timer5_t timer5,
timer4_t timer4, timer3_t timer3, timer2_t timer2,
timer1_t timer1, timer0_t timer0, spi_t spi,
usart1_t usart1,
usart0_t usart0, twi_t twi);
#elif defined __AVR_ATmega32U4__
void idle(period_t period, adc_t adc, timer4_t timer4,
timer3_t timer3, timer1_t timer1, timer0_t timer0,
spi_t spi, usart1_t usart1, twi_t twi, usb_t usb);
#else
#error "Please ensure chosen MCU is either 88, 168, 168P, 328P, 32U4, 2560 or 256RFR2."
#endif
void adcNoiseReduction(period_t period, adc_t adc, timer2_t timer2) __attribute__((optimize("-O1")));
void powerDown(period_t period, adc_t adc, bod_t bod) __attribute__((optimize("-O1")));
void powerSave(period_t period, adc_t adc, bod_t bod, timer2_t timer2) __attribute__((optimize("-O1")));
void powerStandby(period_t period, adc_t adc, bod_t bod) __attribute__((optimize("-O1")));
void powerExtStandby(period_t period, adc_t adc, bod_t bod, timer2_t timer2) __attribute__((optimize("-O1")));
#elif defined (__arm__)
#if defined (__SAMD21G18A__)
void idle(idle_t idleMode);
void standby();
#else
#error "Please ensure chosen MCU is ATSAMD21G18A."
#endif
#else
#error "Processor architecture is not supported."
#endif
};
extern LowPowerClass LowPower;
#endif

View File

@ -0,0 +1,21 @@
### Low-Power
Lightweight low power library for Arduino.
Version: 1.80
Date: 04-10-2018
Devices Supported:
* ATMega88
* ATMega168
* ATMega168P
* ATMega328P
* ATMega32U4
* ATMega644P
* ATMega1284P
* ATMega2560
* ATMega256RFR2
* ATSAMD21G18A
####Notes:
External interrupt during standby on ATSAMD21G18A requires a patch to the <a href="https://github.com/arduino/ArduinoCore-samd">Arduino SAMD Core</a> in order for it to work. Fix is provided by this particular <a href="https://github.com/arduino/ArduinoCore-samd/pull/90">pull request</a>.

View File

@ -0,0 +1,72 @@
#######################################
# Syntax Coloring Map LowPower
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
#######################################
# Methods and Functions (KEYWORD2)
#######################################
idle KEYWORD2
adcNoiseReduction KEYWORD2
powerDown KEYWORD2
powerSave KEYWORD2
powerStandby KEYWORD2
powerExtStandby KEYWORD2
standby KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
LowPower KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
SLEEP_15MS LITERAL1
SLEEP_30MS LITERAL1
SLEEP_60MS LITERAL1
SLEEP_120MS LITERAL1
SLEEP_250MS LITERAL1
SLEEP_500MS LITERAL1
SLEEP_1S LITERAL1
SLEEP_2S LITERAL1
SLEEP_4S LITERAL1
SLEEP_8S LITERAL1
SLEEP_FOREVER LITERAL1
ADC_OFF LITERAL1
ADC_ON LITERAL1
BOD_OFF LITERAL1
BOD_ON LITERAL1
TIMER4_OFF LITERAL1
TIMER4_ON LITERAL1
TIMER3_OFF LITERAL1
TIMER3_ON LITERAL1
TIMER2_OFF LITERAL1
TIMER2_ON LITERAL1
TIMER1_OFF LITERAL1
TIMER1_ON LITERAL1
TIMER0_OFF LITERAL1
TIMER0_ON LITERAL1
USART3_OFF LITERAL1
USART3_ON LITERAL1
USART2_OFF LITERAL1
USART2_ON LITERAL1
USART1_OFF LITERAL1
USART1_ON LITERAL1
USART0_OFF LITERAL1
USART0_ON LITERAL1
SPI_OFF LITERAL1
SPI_ON LITERAL1
TWI_OFF LITERAL1
TWI_ON LITERAL1
USB_OFF LITERAL1
USB_ON LITERAL1
IDLE_0 LITERAL1
IDLE_1 LITERAL1
IDLE_2 LITERAL1

View File

@ -0,0 +1,9 @@
name=Low-Power
version=1.6
author=Rocket Scream Electronics
maintainer=Rocket Scream Electronics
sentence=Lightweight power management library
paragraph=Lightweight power management library
category=Other
url=https://github.com/rocketscream/Low-Power
architectures=avr,samd

View File

@ -0,0 +1,21 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
Having issues with ACK not working correctly? Please see [common issues](https://github.com/nRF24/RF24/blob/master/COMMON_ISSUES.md).
**Describe the bug**
A clear and concise description of what the bug is.
Please include:
1. Code to reproduce
2. Expected behaviour
3. What device(es) are you using? Please specify make and model.
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -0,0 +1,10 @@
---
name: Question
about: Have a question?
title: "[Question]"
labels: question
assignees: ''
---

View File

@ -0,0 +1,157 @@
name: Arduino CLI build
on:
pull_request:
paths:
- ".github/workflows/build_arduino.yml"
- "examples/**"
- "!examples/old_backups/recipes/pingpair_maple/**"
push:
paths:
- ".github/workflows/build_arduino.yml"
- "examples/**"
- "!examples/old_backups/recipes/pingpair_maple/**"
jobs:
check_formatting:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Check code formatting
uses: per1234/artistic-style-action@main
with:
options-file-path: ./examples/examples_formatter.conf
name-patterns: |
- '*.ino'
- '*.cpp'
- '*.hpp'
- '*.h'
target-paths: |
- examples
build:
needs: check_formatting
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
fqbn:
- "arduino:avr:yun"
- "arduino:avr:uno"
- "arduino:avr:diecimila"
- "arduino:avr:nano"
- "arduino:avr:mega"
- "arduino:avr:megaADK"
- "arduino:avr:leonardo"
- "arduino:avr:micro"
- "arduino:avr:esplora"
- "arduino:avr:mini"
- "arduino:avr:ethernet"
- "arduino:avr:fio"
- "arduino:avr:bt"
# - "arduino:avr:LilyPad" # board not found
- "arduino:avr:LilyPadUSB"
- "arduino:avr:pro"
- "arduino:avr:atmegang"
- "arduino:avr:robotControl"
- "arduino:avr:robotMotor"
# - "arduino:avr:gemma" # does not support SPI
- "arduino:avr:circuitplay32u4cat"
- "arduino:avr:yunmini"
- "arduino:avr:chiwawa"
- "arduino:avr:one"
- "arduino:avr:unowifi"
- "arduino:mbed:nano33ble"
# - "arduino:samd:mkr1000" # InterruptConfigure.ino uses pin 2
# - "arduino:samd:mkrzero" # InterruptConfigure.ino uses pin 2
# - "arduino:samd:mkrwifi1010" # InterruptConfigure.ino uses pin 2
- "arduino:samd:nano_33_iot"
# - "arduino:samd:mkrfox1200" # InterruptConfigure.ino uses pin 2
# - "arduino:samd:mkrwan1300" # InterruptConfigure.ino uses pin 2
# - "arduino:samd:mkrwan1310" # InterruptConfigure.ino uses pin 2
# - "arduino:samd:mkrgsm1400" # InterruptConfigure.ino uses pin 2
# - "arduino:samd:mkrnb1500" # InterruptConfigure.ino uses pin 2
# - "arduino:samd:mkrvidor4000" # InterruptConfigure.ino uses pin 2
- "arduino:samd:adafruit_circuitplayground_m0"
- "arduino:samd:mzero_pro_bl"
- "arduino:samd:mzero_bl"
- "arduino:samd:tian"
- "arduino:megaavr:uno2018"
# - "arduino:megaavr:nano4809" # board not found
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Compile examples
uses: arduino/compile-sketches@main
with:
sketch-paths: |
- examples/GettingStarted
- examples/AcknowledgementPayloads
- examples/ManualAcknowledgements
- examples/StreamingData
- examples/MulticeiverDemo
- examples/InterruptConfigure
# - examples/old_backups/GettingStarted_HandlingFailures
# - examples/old_backups/pingpair_dyn
# - examples/old_backups/pingpair_irq
# - examples/old_backups/pingpair_multi_dyn
# - examples/old_backups/pingpair_sleepy
# - examples/old_backups/scanner
# - examples/old_backups/TransferTimeouts
# - examples/old_backups/recipes/led_remote
# - examples/old_backups/recipes/nordic_fob
# - examples/old_backups/recipes/pingpair_maple
fqbn: ${{ matrix.fqbn }}
attiny:
needs: check_formatting
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
fqbn:
- ATTinyCore:avr:attinyx4
- ATTinyCore:avr:attinyx4opti
- ATTinyCore:avr:attinyx4micr
- ATTinyCore:avr:attinyx5
- ATTinyCore:avr:attinyx5micr
- ATTinyCore:avr:attinyx8
- ATTinyCore:avr:attinyx8opti
- ATTinyCore:avr:attinyx8micr
- ATTinyCore:avr:attinyx7
- ATTinyCore:avr:attinyx7opti
- ATTinyCore:avr:attinyx7micr
- ATTinyCore:avr:attinyx61
- ATTinyCore:avr:attinyx61opti
- ATTinyCore:avr:attinyx41
- ATTinyCore:avr:attinyx41opti
- ATTinyCore:avr:attinyx41micr
# - ATTinyCore:avr:attiny43 # doesn't seem to support USI implementation of SPI
- ATTinyCore:avr:attiny828
- ATTinyCore:avr:attiny828opti
- ATTinyCore:avr:attiny1634
- ATTinyCore:avr:attiny1634opti
- ATTinyCore:avr:attinyx313
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Compile examples
uses: arduino/compile-sketches@main
with:
platforms: |
- source-url: "http://drazzy.com/package_drazzy.com_index.json"
name: "ATTinyCore:avr"
- name: "arduino:avr"
sketch-paths: |
- examples/rf24_ATTiny/rf24ping85
- examples/rf24_ATTiny/timingSearch3pin
fqbn: ${{ matrix.fqbn }}

View File

@ -0,0 +1,47 @@
name: Linux build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
config-options:
- "--soc=BCM2835 --driver=RPi"
- "--soc=BCM2836 --driver=RPi"
- "--soc=BCM2835 --driver=wiringPi --extra-cflags=-I/usr/local/include"
- "--driver=SPIDEV"
steps:
- uses: actions/checkout@v1
- name: provide toolchain
run: |
sudo apt-get update
sudo apt-get install binutils-arm-linux-gnueabi gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
arm-linux-gnueabihf-gcc -v
arm-linux-gnueabihf-g++ -v
python3 --version
- name: provide WiringPi
if: ${{ matrix.config-options == '--soc=BCM2835 --driver=wiringPi --extra-cflags=-I/usr/local/include' }}
run: |
git clone https://github.com/CoRfr/WiringPi
cd WiringPi/wiringPi
CC="arm-linux-gnueabihf-gcc -marm -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard" V=1 make -j5
sudo make install
- name: library configure
run: ./configure ${{ matrix.config-options }}
- name: library make
run: make
- name: library make install
run: sudo make install
- name: make linux examples
# compiling examples for wiringPi is broken see nRF24#669 issue
if: ${{ matrix.config-options != '--soc=BCM2835 --driver=wiringPi --extra-cflags=-I/usr/local/include' }}
run: |
cd examples_linux
make
file ./gettingstarted

View File

@ -0,0 +1,46 @@
name: DoxyGen build
on:
pull_request:
branches:
- master
push:
branches:
- master
release:
branches:
- master
types:
- published
- edited
jobs:
build-doxygen:
runs-on: ubuntu-latest
steps:
- name: get latest release version number
id: latest_ver
uses: pozetroninc/github-action-get-latest-release@master
with:
repository: nRF24/RF24
- name: checkout
uses: actions/checkout@v2
- name: overwrite doxygen tags
run: |
mkdir docs
touch doxygenAction
echo "PROJECT_NUMBER = ${{ steps.latest_ver.outputs.release }}" >> doxygenAction
echo "OUTPUT_DIRECTORY = ./docs" >> doxygenAction
echo "@INCLUDE = doxygenAction" >> Doxyfile
- name: build doxygen
uses: mattnotmitt/doxygen-action@v1
with:
working-directory: '.'
doxyfile-path: './Doxyfile'
- name: upload to github pages
if: ${{ github.event_name == 'release'}}
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/html

35
src/libs/RF24-master/.gitignore vendored Normal file
View File

@ -0,0 +1,35 @@
*.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/*.cpp
!examples_linux/*.py
!examples_linux/**/*.cpp
!examples_linux/Makefile
!examples_linux/**/Makefile
*__pycache__/
.directory
.idea
doxygenAction
.vscode/
*venv
*.pyc

View File

@ -0,0 +1,48 @@
# Common Issues
## Settings that must match
Before you report undesirable behavior, please make sure that the
following RF24 configurations match on both receiving and transmitting
nRF24L01 transceivers:
1. `RF24::setAddressWidth()`
2. `RF24::setChannel()`
3. `RF24::setDataRate()`
4. `RF24::setAutoAck()`
5. `RF24::enableDynamicPayloads()` or `RF24::disableDynamicPayloads()`
6. `RF24::enableAckPayload()` or `RF24::disableAckPayload()` (requires auto-ack and
dynamic payloads features)
7. `RF24::setPayloadSize()` (only if the dynamic payloads feature is disabled -- it is disabled by default)
8. `RF24::setCRCLength()` or `RF24::disableCRC()` (the auto-ack feature
automatically enables CRC because it is required)
Also, it helps to think of an address as a path (a commonly shared route)
instead of an identifying device destination. This means that addresses
have to match for a payload to travel from one transceiver to another.
However, the pipe numbers assigned with the matching address do not have
to match. You can think of pipes as parking spots for the packets, while
all packets' payloads live in a TX or RX FIFO buffer. Remember that the
TX FIFO buffers and the RX FIFO buffers both have a maximum occupancy of
3 payloads (regardless of the maximum 32-byte payload size).
## Here are the most common issues and their solutions.
### write() always returns true after setAutoAck(false)
Don't disabled the auto-ack feature. RF24::write() has no reason to doubt
that the payload was delivered if the auto-ack feature is disabled. We
recommend you read the docs about RF24::setAutoAck() before disabling the
auto-ack feature.
### write() returns false when the payload was received
If the settings match on both endpoint transceivers, then this can only
mean that the receiving nRF24L01 failed to send an acknowledgement (ACK)
packet back to the transmitting nRF24L01. Usually this is due to
instability (electric noise) in the power lines (VCC and GND) going to
the receiving nRF24L01.
If you're not receiving ACK packets correctly/reliably on data rates
lower than 2MBPS, try adding a big capacitor close to the module/chip.
Example issues: [#264](https://github.com/nRF24/RF24/issues/264)
[#211](https://github.com/nRF24/RF24/issues/211).
For reliability, please use Electrolytic or Tantalum capacitors. Ceramic
capacitors may not be good enough (depending on the manufacturing source).

View File

@ -0,0 +1,9 @@
These are the current requirements for getting your code included in RF24:
* Try your best to follow the rest of the code, if you're unsure then the NASA C style can help as it's closest to the current style: https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19950022400.pdf
* Definetly follow [PEP-8](https://www.python.org/dev/peps/pep-0008/) if it's Python code.
* Follow the [Arduino IDE formatting style](https://www.arduino.cc/en/Reference/StyleGuide) for Arduino examples
* Add [doxygen-compatible documentation](https://www.doxygen.nl/manual/docblocks.html) to any new functions you add, or update existing documentation if you change behaviour

File diff suppressed because it is too large Load Diff

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.

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 compatibility.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"

View File

@ -0,0 +1,7 @@
![Arduino CLI build](https://github.com/nRF24/RF24/workflows/Arduino%20CLI%20build/badge.svg)
![Linux build](https://github.com/nRF24/RF24/workflows/Linux%20build/badge.svg)
# See http://nRF24.github.io/RF24 for all documentation
### Check our [contributing guidelines](CONTRIBUTING.md) before opening a pull request

File diff suppressed because it is too large Load Diff

2751
src/libs/RF24-master/RF24.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,196 @@
/*
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
/**
* User access to internally used delay time (in microseconds) during RF24::powerUp()
* @warning This default value compensates for all supported hardware. Only adjust this if you
* know your radio's hardware is, in fact, genuine and reliable.
*/
#if !defined(RF24_POWERUP_DELAY)
#define RF24_POWERUP_DELAY 5000
#endif
/**********************/
#define rf24_max(a, b) (a>b?a:b)
#define rf24_min(a, b) (a<b?a:b)
#define RF24_SPI_SPEED 10000000
//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__) || defined (__AVR_ATtinyX5__) || defined (__AVR_ATtinyX4__) || defined (__AVR_ATtinyX313__) || defined (__AVR_ATtinyX61__)
#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>
#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__)
#ifndef _BV
#define _BV(x) (1<<(x))
#endif
#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"
#ifndef pgm_read_ptr
#define pgm_read_ptr(p) (*(p))
#endif
#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
#ifdef ARDUINO_ARCH_AVR
#include <avr/pgmspace.h>
#endif
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
#endif // !defined (ARDUINO)
#ifndef prog_uint16_t
typedef uint16_t prog_uint16_t;
#endif
#ifndef PSTR
#define PSTR(x) (x)
#endif
#ifndef printf_P
#define printf_P printf
#endif
#ifndef strlen_P
#define strlen_P strlen
#endif
#ifndef PROGMEM
#define PROGMEM
#endif
#ifndef pgm_read_word
#define pgm_read_word(p) (*(p))
#endif
#if !defined pgm_read_ptr || defined ARDUINO_ARCH_MBED
#define pgm_read_ptr(p) (*(p))
#endif
#ifndef PRIPSTR
#define PRIPSTR "%s"
#endif
#endif // !defined (ARDUINO) || defined (ESP_PLATFORM) || defined (__arm__) || defined (__ARDUINO_X86__) && !defined (XMEGA)
#endif //Everything else
#if defined (SPI_HAS_TRANSACTION) && !defined (SPI_UART) && !defined (SOFTSPI)
#define RF24_SPI_TRANSACTIONS
#endif // defined (SPI_HAS_TRANSACTION) && !defined (SPI_UART) && !defined (SOFTSPI)
#endif // __RF24_CONFIG_H__

473
src/libs/RF24-master/configure vendored Normal 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 -v /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="-marm -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."

View File

@ -0,0 +1,815 @@
/* 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;
}
td.fielddoc
th.markdownTableHeadLeft,
th.markdownTableHeadRight,
th.markdownTableHeadCenter,
th.markdownTableHeadNone {
background-image: none;
border-radius: unset;
}
td.fielddoc tr:last-child {
border-bottom: 1px solid #2D4068;
}

View File

@ -0,0 +1,208 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/
/**
* A simple example of sending data from 1 nRF24L01 transceiver to another
* with Acknowledgement (ACK) payloads attached to ACK packets.
*
* This example was written to be used on 2 devices acting as "nodes".
* Use the Serial Monitor to change each node's behavior.
*/
#include <SPI.h>
#include "printf.h"
#include "RF24.h"
// instantiate an object for the nRF24L01 transceiver
RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin
// an identifying device destination
// Let these addresses be used for the pair
uint8_t address[][6] = {"1Node", "2Node"};
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
// Used to control whether this node is sending or receiving
bool role = false; // true = TX role, false = RX role
// For this example, we'll be using a payload containing
// a string & an integer number that will be incremented
// on every successful transmission.
// Make a data structure to store the entire payload of different datatypes
struct PayloadStruct {
char message[7]; // only using 6 characters for TX & ACK payloads
uint8_t counter;
};
PayloadStruct payload;
void setup() {
Serial.begin(115200);
while (!Serial) {
// some boards need to wait to ensure access to serial over USB
}
// initialize the transceiver on the SPI bus
if (!radio.begin()) {
Serial.println(F("radio hardware is not responding!!"));
while (1) {} // hold in infinite loop
}
// print example's introductory prompt
Serial.println(F("RF24/examples/AcknowledgementPayloads"));
// To set the radioNumber via the Serial monitor on startup
Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'"));
while (!Serial.available()) {
// wait for user input
}
char input = Serial.parseInt();
radioNumber = input == 1;
Serial.print(F("radioNumber = "));
Serial.println((int)radioNumber);
// role variable is hardcoded to RX behavior, inform the user of this
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// to use ACK payloads, we need to enable dynamic payload lengths (for all nodes)
radio.enableDynamicPayloads(); // ACK payloads are dynamically sized
// Acknowledgement packets have no payloads by default. We need to enable
// this feature for all nodes (TX & RX) to use ACK payloads.
radio.enableAckPayload();
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
// additional setup specific to the node's role
if (role) {
// setup the TX payload
memcpy(payload.message, "Hello ", 6); // set the payload message
radio.stopListening(); // put radio in TX mode
} else {
// setup the ACK payload & load the first response into the FIFO
memcpy(payload.message, "World ", 6); // set the payload message
// load the payload for the first received transmission on pipe 0
radio.writeAckPayload(1, &payload, sizeof(PayloadStruct));
radio.startListening(); // put radio in RX mode
}
// For debugging info
// printf_begin(); // needed only once for printing details
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
}
void loop() {
if (role) {
// This device is a TX node
unsigned long start_timer = micros(); // start the timer
bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report
unsigned long end_timer = micros(); // end the timer
if (report) {
Serial.print(F("Transmission successful! ")); // payload was delivered
Serial.print(F("Time to transmit = "));
Serial.print(end_timer - start_timer); // print the timer result
Serial.print(F(" us. Sent: "));
Serial.print(payload.message); // print the outgoing message
Serial.print(payload.counter); // print the outgoing counter
uint8_t pipe;
if (radio.available(&pipe)) { // is there an ACK payload? grab the pipe number that received it
PayloadStruct received;
radio.read(&received, sizeof(received)); // get incoming ACK payload
Serial.print(F(" Recieved "));
Serial.print(radio.getDynamicPayloadSize()); // print incoming payload size
Serial.print(F(" bytes on pipe "));
Serial.print(pipe); // print pipe number that received the ACK
Serial.print(F(": "));
Serial.print(received.message); // print incoming message
Serial.println(received.counter); // print incoming counter
// save incoming counter & increment for next outgoing
payload.counter = received.counter + 1;
} else {
Serial.println(F(" Recieved: an empty ACK packet")); // empty ACK packet received
}
} else {
Serial.println(F("Transmission failed or timed out")); // payload was not delivered
}
// to make this example readable in the serial monitor
delay(1000); // slow transmissions down by 1 second
} else {
// This device is a RX node
uint8_t pipe;
if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it
uint8_t bytes = radio.getDynamicPayloadSize(); // get the size of the payload
PayloadStruct received;
radio.read(&received, sizeof(received)); // get incoming payload
Serial.print(F("Received "));
Serial.print(bytes); // print the size of the payload
Serial.print(F(" bytes on pipe "));
Serial.print(pipe); // print the pipe number
Serial.print(F(": "));
Serial.print(received.message); // print incoming message
Serial.print(received.counter); // print incoming counter
Serial.print(F(" Sent: "));
Serial.print(payload.message); // print outgoing message
Serial.println(payload.counter); // print outgoing counter
// save incoming counter & increment for next outgoing
payload.counter = received.counter + 1;
// load the payload for the first received transmission on pipe 0
radio.writeAckPayload(1, &payload, sizeof(payload));
}
} // role
if (Serial.available()) {
// change the role via the serial monitor
char c = toupper(Serial.read());
if (c == 'T' && !role) {
// Become the TX node
role = true;
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
memcpy(payload.message, "Hello ", 6); // change payload message
radio.stopListening(); // this also discards any unused ACK payloads
} else if (c == 'R' && role) {
// Become the RX node
role = false;
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
memcpy(payload.message, "World ", 6); // change payload message
// load the payload for the first received transmission on pipe 0
radio.writeAckPayload(1, &payload, sizeof(PayloadStruct));
radio.startListening();
}
}
} // loop

View File

@ -0,0 +1,154 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/
/**
* A simple example of sending data from 1 nRF24L01 transceiver to another.
*
* This example was written to be used on 2 devices acting as "nodes".
* Use the Serial Monitor to change each node's behavior.
*/
#include <SPI.h>
#include "printf.h"
#include "RF24.h"
// instantiate an object for the nRF24L01 transceiver
RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin
// Let these addresses be used for the pair
uint8_t address[][6] = {"1Node", "2Node"};
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
// Used to control whether this node is sending or receiving
bool role = false; // true = TX role, false = RX role
// For this example, we'll be using a payload containing
// a single float number that will be incremented
// on every successful transmission
float payload = 0.0;
void setup() {
Serial.begin(115200);
while (!Serial) {
// some boards need to wait to ensure access to serial over USB
}
// initialize the transceiver on the SPI bus
if (!radio.begin()) {
Serial.println(F("radio hardware is not responding!!"));
while (1) {} // hold in infinite loop
}
// print example's introductory prompt
Serial.println(F("RF24/examples/GettingStarted"));
// To set the radioNumber via the Serial monitor on startup
Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'"));
while (!Serial.available()) {
// wait for user input
}
char input = Serial.parseInt();
radioNumber = input == 1;
Serial.print(F("radioNumber = "));
Serial.println((int)radioNumber);
// role variable is hardcoded to RX behavior, inform the user of this
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// save on transmission time by setting the radio to only transmit the
// number of bytes we need to transmit a float
radio.setPayloadSize(sizeof(payload)); // float datatype occupies 4 bytes
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
// additional setup specific to the node's role
if (role) {
radio.stopListening(); // put radio in TX mode
} else {
radio.startListening(); // put radio in RX mode
}
// For debugging info
// printf_begin(); // needed only once for printing details
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
} // setup
void loop() {
if (role) {
// This device is a TX node
unsigned long start_timer = micros(); // start the timer
bool report = radio.write(&payload, sizeof(float)); // transmit & save the report
unsigned long end_timer = micros(); // end the timer
if (report) {
Serial.print(F("Transmission successful! ")); // payload was delivered
Serial.print(F("Time to transmit = "));
Serial.print(end_timer - start_timer); // print the timer result
Serial.print(F(" us. Sent: "));
Serial.println(payload); // print payload sent
payload += 0.01; // increment float payload
} else {
Serial.println(F("Transmission failed or timed out")); // payload was not delivered
}
// to make this example readable in the serial monitor
delay(1000); // slow transmissions down by 1 second
} else {
// This device is a RX node
uint8_t pipe;
if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it
uint8_t bytes = radio.getPayloadSize(); // get the size of the payload
radio.read(&payload, bytes); // fetch payload from FIFO
Serial.print(F("Received "));
Serial.print(bytes); // print the size of the payload
Serial.print(F(" bytes on pipe "));
Serial.print(pipe); // print the pipe number
Serial.print(F(": "));
Serial.println(payload); // print the payload's value
}
} // role
if (Serial.available()) {
// change the role via the serial monitor
char c = toupper(Serial.read());
if (c == 'T' && !role) {
// Become the TX node
role = true;
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
radio.stopListening();
} else if (c == 'R' && role) {
// Become the RX node
role = false;
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
radio.startListening();
}
}
} // loop

View File

@ -0,0 +1,346 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/
/**
* This example uses Acknowledgement (ACK) payloads attached to ACK packets to
* demonstrate how the nRF24L01's IRQ (Interrupt Request) pin can be
* configured to detect when data is received, or when data has transmitted
* successfully, or when data has failed to transmit.
*
* This example was written to be used on 2 devices acting as "nodes".
* Use the Serial Monitor to change each node's behavior.
*/
#include <SPI.h>
#include "printf.h"
#include "RF24.h"
// We will be using the nRF24L01's IRQ pin for this example
#define IRQ_PIN 2 // this needs to be a digital input capable pin
volatile bool wait_for_event = false; // used to wait for an IRQ event to trigger
// instantiate an object for the nRF24L01 transceiver
RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin
// Let these addresses be used for the pair
uint8_t address[][6] = {"1Node", "2Node"};
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
// Used to control whether this node is sending or receiving
bool role = false; // true = TX node, false = RX node
// For this example, we'll be using a payload containing
// a string that changes on every transmission. (successful or not)
// Make a couple arrays of payloads & an iterator to traverse them
const uint8_t tx_pl_size = 5;
const uint8_t ack_pl_size = 4;
uint8_t pl_iterator = 0;
// The " + 1" compensates for the c-string's NULL terminating 0
char tx_payloads[][tx_pl_size + 1] = {"Ping ", "Pong ", "Radio", "1FAIL"};
char ack_payloads[][ack_pl_size + 1] = {"Yak ", "Back", " ACK"};
void interruptHandler(); // prototype to handle IRQ events
void printRxFifo(); // prototype to print RX FIFO with 1 buffer
void setup() {
Serial.begin(115200);
while (!Serial) {
// some boards need to wait to ensure access to serial over USB
}
// initialize the transceiver on the SPI bus
if (!radio.begin()) {
Serial.println(F("radio hardware is not responding!!"));
while (1) {} // hold in infinite loop
}
// print example's introductory prompt
Serial.println(F("RF24/examples/InterruptConfigure"));
// To set the radioNumber via the Serial monitor on startup
Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'"));
while (!Serial.available()) {
// wait for user input
}
char input = Serial.parseInt();
radioNumber = input == 1;
Serial.print(F("radioNumber = "));
Serial.println((int)radioNumber);
// role variable is hardcoded to RX behavior, inform the user of this
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
// setup the IRQ_PIN
pinMode(IRQ_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(IRQ_PIN), interruptHandler, FALLING);
// IMPORTANT: do not call radio.available() before calling
// radio.whatHappened() when the interruptHandler() is triggered by the
// IRQ pin FALLING event. According to the datasheet, the pipe information
// is unreliable during the IRQ pin FALLING transition.
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// For this example we use acknowledgment (ACK) payloads to trigger the
// IRQ pin when data is received on the TX node.
// to use ACK payloads, we need to enable dynamic payload lengths
radio.enableDynamicPayloads(); // ACK payloads are dynamically sized
// Acknowledgement packets have no payloads by default. We need to enable
// this feature for all nodes (TX & RX) to use ACK payloads.
radio.enableAckPayload();
// Fot this example, we use the same address to send data back and forth
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
// additional setup specific to the node's role
if (role) {
// setup for TX mode
radio.stopListening(); // put radio in TX mode
} else {
// setup for RX mode
// let IRQ pin only trigger on "data ready" event in RX mode
radio.maskIRQ(1, 1, 0); // args = "data_sent", "data_fail", "data_ready"
// Fill the TX FIFO with 3 ACK payloads for the first 3 received
// transmissions on pipe 1
radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size);
radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size);
radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size);
radio.startListening(); // put radio in RX mode
}
// For debugging info
// printf_begin(); // needed only once for printing details
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
}
void loop() {
if (role && !wait_for_event) {
// delay(1); // wait for IRQ pin to fully RISE
// This device is a TX node. This if block is only triggered when
// NOT waiting for an IRQ event to happen
if (pl_iterator == 0) {
// Test the "data ready" event with the IRQ pin
Serial.println(F("\nConfiguring IRQ pin to ignore the 'data sent' event"));
radio.maskIRQ(true, false, false); // args = "data_sent", "data_fail", "data_ready"
Serial.println(F(" Pinging RX node for 'data ready' event..."));
} else if (pl_iterator == 1) {
// Test the "data sent" event with the IRQ pin
Serial.println(F("\nConfiguring IRQ pin to ignore the 'data ready' event"));
radio.maskIRQ(false, false, true); // args = "data_sent", "data_fail", "data_ready"
Serial.println(F(" Pinging RX node for 'data sent' event..."));
} else if (pl_iterator == 2) {
// Use this iteration to fill the RX node's FIFO which sets us up for the next test.
// write() uses virtual interrupt flags that work despite the masking of the IRQ pin
radio.maskIRQ(1, 1, 1); // disable IRQ masking for this step
Serial.println(F("\nSending 1 payload to fill RX node's FIFO. IRQ pin is neglected."));
// write() will call flush_tx() on 'data fail' events
if (radio.write(&tx_payloads[pl_iterator], tx_pl_size)) {
if (radio.rxFifoFull()) {
Serial.println(F("RX node's FIFO is full; it is not listening any more"));
} else {
Serial.println("Transmission successful, but the RX node might still be listening.");
}
} else {
Serial.println(F("Transmission failed or timed out. Continuing anyway."));
radio.flush_tx(); // discard payload(s) that failed to transmit
}
} else if (pl_iterator == 3) {
// test the "data fail" event with the IRQ pin
Serial.println(F("\nConfiguring IRQ pin to reflect all events"));
radio.maskIRQ(0, 0, 0); // args = "data_sent", "data_fail", "data_ready"
Serial.println(F(" Pinging inactive RX node for 'data fail' event..."));
}
if (pl_iterator < 4 && pl_iterator != 2) {
// IRQ pin is LOW when activated. Otherwise it is always HIGH
// Wait until IRQ pin is activated.
wait_for_event = true;
// use the non-blocking call to write a payload and begin transmission
// the "false" argument means we are expecting an ACK packet response
radio.startFastWrite(tx_payloads[pl_iterator++], tx_pl_size, false);
// In this example, the "data fail" event is always configured to
// trigger the IRQ pin active. Because the auto-ACK feature is on by
// default, we don't need a timeout check to prevent an infinite loop.
} else if (pl_iterator == 4) {
// all IRQ tests are done; flush_tx() and print the ACK payloads for fun
// CE pin is still HIGH which consumes more power. Example is now idling so...
radio.stopListening(); // ensure CE pin is LOW
// stopListening() also calls flush_tx() when ACK payloads are enabled
printRxFifo();
pl_iterator++;
// inform user what to do next
Serial.println(F("\n*** PRESS 'T' to restart the transmissions"));
Serial.println(F("*** PRESS 'R' to change to Receive role\n"));
} else if (pl_iterator == 2) {
pl_iterator++; // proceed from step 3 to last step (stop at step 4 for readability)
}
} else if (!role) {
// This device is a RX node
if (radio.rxFifoFull()) {
// wait until RX FIFO is full then stop listening
delay(100); // let ACK payload finish transmitting
radio.stopListening(); // also discards unused ACK payloads
printRxFifo(); // flush the RX FIFO
// Fill the TX FIFO with 3 ACK payloads for the first 3 received
// transmissions on pipe 1.
radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size);
radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size);
radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size);
delay(100); // let TX node finish its role
radio.startListening(); // We're ready to start over. Begin listening.
}
} // role
if (Serial.available()) {
// change the role via the serial monitor
char c = toupper(Serial.read());
if (c == 'T') {
// Become the TX node
if (!role)
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
else
Serial.println(F("*** RESTARTING IRQ PIN TEST ***"));
role = true;
wait_for_event = false;
pl_iterator = 0; // reset the iterator
radio.flush_tx(); // discard any payloads in the TX FIFO
// startListening() clears the IRQ masks also. This is required for
// continued TX operations when a transmission fails.
radio.stopListening(); // this also discards any unused ACK payloads
} else if (c == 'R' && role) {
// Become the RX node
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
role = false;
radio.maskIRQ(0, 0, 0); // the IRQ pin should only trigger on "data ready" event
// Fill the TX FIFO with 3 ACK payloads for the first 3 received
// transmissions on pipe 1
radio.flush_tx(); // make sure there is room for 3 new ACK payloads
radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size);
radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size);
radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size);
radio.startListening();
}
} // Serial.available()
} // loop
/**
* when the IRQ pin goes active LOW, call this fuction print out why
*/
void interruptHandler() {
// print IRQ status and all masking flags' states
Serial.println(F("\tIRQ pin is actively LOW")); // show that this function was called
delayMicroseconds(250);
bool tx_ds, tx_df, rx_dr; // declare variables for IRQ masks
radio.whatHappened(tx_ds, tx_df, rx_dr); // get values for IRQ masks
// whatHappened() clears the IRQ masks also. This is required for
// continued TX operations when a transmission fails.
// clearing the IRQ masks resets the IRQ pin to its inactive state (HIGH)
Serial.print(F("\tdata_sent: "));
Serial.print(tx_ds); // print "data sent" mask state
Serial.print(F(", data_fail: "));
Serial.print(tx_df); // print "data fail" mask state
Serial.print(F(", data_ready: "));
Serial.println(rx_dr); // print "data ready" mask state
if (tx_df) // if TX payload failed
radio.flush_tx(); // clear all payloads from the TX FIFO
// print if test passed or failed. Unintentional fails mean the RX node was not listening.
// pl_iterator has already been incremented by now
if (pl_iterator <= 1) {
Serial.print(F(" 'Data Ready' event test "));
Serial.println(rx_dr ? F("passed") : F("failed"));
} else if (pl_iterator == 2) {
Serial.print(F(" 'Data Sent' event test "));
Serial.println(tx_ds ? F("passed") : F("failed"));
} else if (pl_iterator == 4) {
Serial.print(F(" 'Data Fail' event test "));
Serial.println(tx_df ? F("passed") : F("failed"));
}
wait_for_event = false; // ready to continue with loop() operations
} // interruptHandler
/**
* Print the entire RX FIFO with one buffer. This will also flush the RX FIFO.
* Remember that the payload sizes are declared as tx_pl_size and ack_pl_size.
*/
void printRxFifo() {
if (radio.available()) { // if there is data in the RX FIFO
// to flush the data from the RX FIFO, we'll fetch it all using 1 buffer
uint8_t pl_size = !role ? tx_pl_size : ack_pl_size;
char rx_fifo[pl_size * 3 + 1]; // RX FIFO is full & we know ACK payloads' size
if (radio.rxFifoFull()) {
rx_fifo[pl_size * 3] = 0; // add a NULL terminating char to use as a c-string
radio.read(&rx_fifo, pl_size * 3); // this clears the RX FIFO (for this example)
} else {
uint8_t i = 0;
while (radio.available()) {
radio.read(&rx_fifo + (i * pl_size), pl_size);
i++;
}
rx_fifo[i * pl_size] = 0; // add a NULL terminating char to use as a c-string
}
Serial.print(F("Complete RX FIFO: "));
Serial.println(rx_fifo); // print the entire RX FIFO with 1 buffer
}
}

View File

@ -0,0 +1,220 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/
/**
* A simple example of sending data from 1 nRF24L01 transceiver to another
* with manually transmitted (non-automatic) Acknowledgement (ACK) payloads.
* This example still uses ACK packets, but they have no payloads. Instead the
* acknowledging response is sent with `write()`. This tactic allows for more
* updated acknowledgement payload data, where actual ACK payloads' data are
* outdated by 1 transmission because they have to loaded before receiving a
* transmission.
*
* This example was written to be used on 2 devices acting as "nodes".
* Use the Serial Monitor to change each node's behavior.
*/
#include <SPI.h>
#include "printf.h"
#include "RF24.h"
// instantiate an object for the nRF24L01 transceiver
RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin
// Let these addresses be used for the pair
uint8_t address[][6] = {"1Node", "2Node"};
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
// Used to control whether this node is sending or receiving
bool role = false; // true = TX node, false = RX node
// For this example, we'll be using a payload containing
// a string & an integer number that will be incremented
// on every successful transmission.
// Make a data structure to store the entire payload of different datatypes
struct PayloadStruct {
char message[7]; // only using 6 characters for TX & RX payloads
uint8_t counter;
};
PayloadStruct payload;
void setup() {
// append a NULL terminating character for printing as a c-string
payload.message[6] = 0;
Serial.begin(115200);
while (!Serial) {
// some boards need to wait to ensure access to serial over USB
}
// initialize the transceiver on the SPI bus
if (!radio.begin()) {
Serial.println(F("radio hardware is not responding!!"));
while (1) {} // hold in infinite loop
}
// print example's introductory prompt
Serial.println(F("RF24/examples/ManualAcknowledgements"));
// To set the radioNumber via the Serial monitor on startup
Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'"));
while (!Serial.available()) {
// wait for user input
}
char input = Serial.parseInt();
radioNumber = input == 1;
Serial.print(F("radioNumber = "));
Serial.println((int)radioNumber);
// role variable is hardcoded to RX behavior, inform the user of this
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// save on transmission time by setting the radio to only transmit the
// number of bytes we need to transmit a float
radio.setPayloadSize(sizeof(payload)); // char[7] & uint8_t datatypes occupy 8 bytes
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
if (role) {
// setup the TX node
memcpy(payload.message, "Hello ", 6); // set the outgoing message
radio.stopListening(); // put radio in TX mode
} else {
// setup the RX node
memcpy(payload.message, "World ", 6); // set the outgoing message
radio.startListening(); // put radio in RX mode
}
// For debugging info
// printf_begin(); // needed only once for printing details
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
} // setup()
void loop() {
if (role) {
// This device is a TX node
unsigned long start_timer = micros(); // start the timer
bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report
if (report) {
// transmission successful; wait for response and print results
radio.startListening(); // put in RX mode
unsigned long start_timeout = millis(); // timer to detect timeout
while (!radio.available()) { // wait for response
if (millis() - start_timeout > 200) // only wait 200 ms
break;
}
unsigned long end_timer = micros(); // end the timer
radio.stopListening(); // put back in TX mode
// print summary of transactions
Serial.print(F("Transmission successful!")); // payload was delivered
uint8_t pipe;
if (radio.available(&pipe)) { // is there a payload received
Serial.print(F(" Round-trip delay: "));
Serial.print(end_timer - start_timer); // print the timer result
Serial.print(F(" us. Sent: "));
Serial.print(payload.message); // print the outgoing payload's message
Serial.print(payload.counter); // print outgoing payload's counter
PayloadStruct received;
radio.read(&received, sizeof(received)); // get payload from RX FIFO
Serial.print(F(" Received "));
Serial.print(radio.getPayloadSize()); // print the size of the payload
Serial.print(F(" bytes on pipe "));
Serial.print(pipe); // print the pipe number
Serial.print(F(": "));
Serial.print(received.message); // print the incoming payload's message
Serial.println(received.counter); // print the incoming payload's counter
payload.counter = received.counter; // save incoming counter for next outgoing counter
} else {
Serial.println(F(" Recieved no response.")); // no response received
}
} else {
Serial.println(F("Transmission failed or timed out")); // payload was not delivered
} // report
// to make this example readable in the serial monitor
delay(1000); // slow transmissions down by 1 second
} else {
// This device is a RX node
uint8_t pipe;
if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it
PayloadStruct received;
radio.read(&received, sizeof(received)); // get incoming payload
payload.counter = received.counter + 1; // increment incoming counter for next outgoing response
// transmit response & save result to `report`
radio.stopListening(); // put in TX mode
radio.writeFast(&payload, sizeof(payload)); // load response to TX FIFO
bool report = radio.txStandBy(150); // keep retrying for 150 ms
radio.startListening(); // put back in RX mode
// print summary of transactions
Serial.print(F("Received "));
Serial.print(radio.getPayloadSize()); // print the size of the payload
Serial.print(F(" bytes on pipe "));
Serial.print(pipe); // print the pipe number
Serial.print(F(": "));
Serial.print(received.message); // print incoming message
Serial.print(received.counter); // print incoming counter
if (report) {
Serial.print(F(" Sent: "));
Serial.print(payload.message); // print outgoing message
Serial.println(payload.counter); // print outgoing counter
} else {
Serial.println(" Response failed."); // failed to send response
}
}
} // role
if (Serial.available()) {
// change the role via the serial monitor
char c = toupper(Serial.read());
if (c == 'T' && !role) {
// Become the TX node
role = true;
memcpy(payload.message, "Hello ", 6); // set the outgoing message
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
radio.stopListening(); // put in TX mode
} else if (c == 'R' && role) {
// Become the RX node
role = false;
memcpy(payload.message, "World ", 6); // set the response message
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
radio.startListening(); // put in RX mode
}
}
} // loop

View File

@ -0,0 +1,198 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty 2bndy5
*/
/**
* A simple example of sending data from as many as 6 nRF24L01 transceivers to
* 1 receiving transceiver. This technique is trademarked by
* Nordic Semiconductors as "MultiCeiver".
*
* This example was written to be used on up to 6 devices acting as TX nodes &
* only 1 device acting as the RX node (that's a maximum of 7 devices).
* Use the Serial Monitor to change each node's behavior.
*/
#include <SPI.h>
#include "printf.h"
#include "RF24.h"
// instantiate an object for the nRF24L01 transceiver
RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin
// For this example, we'll be using 6 addresses; 1 for each TX node
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// Notice that the last byte is the only byte that changes in the last 5
// addresses. This is a limitation of the nRF24L01 transceiver for pipes 2-5
// because they use the same first 4 bytes from pipe 1.
uint64_t address[6] = {0x7878787878LL,
0xB3B4B5B6F1LL,
0xB3B4B5B6CDLL,
0xB3B4B5B6A3LL,
0xB3B4B5B60FLL,
0xB3B4B5B605LL
};
// Because this example allow up to 6 nodes (specified by numbers 0-5) to
// transmit and only 1 node to receive, we will use a negative value in our
// role variable to signify this node is a receiver.
// role variable is used to control whether this node is sending or receiving
char role = 'R'; // 0-5 = TX node; any negative number = RX node
// For this example, we'll be using a payload containing
// a node ID number and a single integer number that will be incremented
// on every successful transmission.
// Make a data structure to use as a payload.
struct PayloadStruct
{
unsigned long nodeID;
unsigned long payloadID;
};
PayloadStruct payload;
// This example uses all 6 pipes to receive while TX nodes only use 2 pipes
// To make this easier we'll use a function to manage the addresses, and the
// payload's nodeID
void setRole(); // declare a prototype; definition is found after the loop()
void setup() {
Serial.begin(115200);
while (!Serial) {
// some boards need to wait to ensure access to serial over USB
}
// initialize the transceiver on the SPI bus
if (!radio.begin()) {
Serial.println(F("radio hardware is not responding!!"));
while (1) {} // hold in infinite loop
}
// print example's introductory prompt
Serial.println(F("RF24/examples/MulticeiverDemo"));
Serial.println(F("*** Enter a number between 0 and 5 (inclusive) to change"));
Serial.println(F(" the identifying node number that transmits."));
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity of
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// save on transmission time by setting the radio to only transmit the
// number of bytes we need to transmit a float
radio.setPayloadSize(sizeof(payload)); // 2x int datatype occupy 8 bytes
// Set the pipe addresses accordingly. This function additionally also
// calls startListening() or stopListening() and sets the payload's nodeID
setRole();
// For debugging info
// printf_begin(); // needed only once for printing details
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
} // setup()
void loop() {
if (role <= 53) {
// This device is a TX node
unsigned long start_timer = micros(); // start the timer
bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report
unsigned long end_timer = micros(); // end the timer
if (report) {
// payload was delivered
Serial.print(F("Transmission of payloadID "));
Serial.print(payload.payloadID); // print payloadID
Serial.print(F(" as node "));
Serial.print(payload.nodeID); // print nodeID
Serial.print(F(" successful!"));
Serial.print(F(" Time to transmit: "));
Serial.print(end_timer - start_timer); // print the timer result
Serial.println(F(" us"));
} else {
Serial.println(F("Transmission failed or timed out")); // payload was not delivered
}
payload.payloadID++; // increment payload number
// to make this example readable in the serial monitor
delay(500); // slow transmissions down by 1 second
} else if (role == 'R') {
// This device is the RX node
uint8_t pipe;
if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it
uint8_t bytes = radio.getPayloadSize(); // get the size of the payload
radio.read(&payload, bytes); // fetch payload from FIFO
Serial.print(F("Received "));
Serial.print(bytes); // print the size of the payload
Serial.print(F(" bytes on pipe "));
Serial.print(pipe); // print the pipe number
Serial.print(F(" from node "));
Serial.print(payload.nodeID); // print the payload's origin
Serial.print(F(". PayloadID: "));
Serial.println(payload.payloadID); // print the payload's number
}
} // role
if (Serial.available()) {
// change the role via the serial monitor
char c = Serial.read();
if (toupper(c) == 'R' && role <= 53) {
// Become the RX node
role = 'R';
Serial.println(F("*** CHANGING ROLE TO RECEIVER ***"));
Serial.println(F("--- Enter a number between 0 and 5 (inclusive) to act as"));
Serial.println(F(" a unique node number that transmits to the RX node."));
setRole(); // change address on all pipes to TX nodes
} else if (c >= 48 && c <= 53 && c != role) {
// Become a TX node with identifier 'c'
role = c - 48;
Serial.print(F("*** CHANGING ROLE TO NODE "));
Serial.print(c);
Serial.println(F(" ***"));
Serial.println(F("--- Enter a number between 0 and 5 (inclusive) to change"));
Serial.println(F(" the identifying node number that transmits."));
Serial.println(F("--- PRESS 'R' to act as the RX node."));
setRole(); // change address on pipe 0 to the RX node
}
}
} // loop
void setRole() {
if (role == 'R') {
// For the RX node
// Set the addresses for all pipes to TX nodes
for (uint8_t i = 0; i < 6; ++i)
radio.openReadingPipe(i, address[i]);
radio.startListening(); // put radio in RX mode
} else {
// For the TX node
// set the payload's nodeID & reset the payload's identifying number
payload.nodeID = role;
payload.payloadID = 0;
// Set the address on pipe 0 to the RX node.
radio.stopListening(); // put radio in TX mode
radio.openWritingPipe(address[role]);
// According to the datasheet, the auto-retry features's delay value should
// be "skewed" to allow the RX node to receive 1 transmission at a time.
// So, use varying delay between retry attempts and 15 (at most) retry attempts
radio.setRetries(((role * 3) % 12) + 3, 15); // maximum value is 15 for both args
}
} // setRole

View File

@ -0,0 +1,185 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty 2bndy5
*/
/**
* A simple example of streaming data from 1 nRF24L01 transceiver to another.
*
* This example was written to be used on 2 devices acting as "nodes".
* Use the Serial Monitor to change each node's behavior.
*/
#include <SPI.h>
#include "printf.h"
#include "RF24.h"
// instantiate an object for the nRF24L01 transceiver
RF24 radio(7, 8); // using pin 7 for the CE pin, and pin 8 for the CSN pin
// Let these addresses be used for the pair
uint8_t address[][6] = {"1Node", "2Node"};
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
// Used to control whether this node is sending or receiving
bool role = false; // true = TX node, false = RX node
// For this example, we'll be sending 32 payloads each containing
// 32 bytes of data that looks like ASCII art when printed to the serial
// monitor. The TX node and RX node needs only a single 32 byte buffer.
#define SIZE 32 // this is the maximum for this example. (minimum is 1)
char buffer[SIZE + 1]; // for the RX node
uint8_t counter = 0; // for counting the number of received payloads
void makePayload(uint8_t); // prototype to construct a payload dynamically
void setup() {
buffer[SIZE] = 0; // add a NULL terminating character (for easy printing)
Serial.begin(115200);
while (!Serial) {
// some boards need to wait to ensure access to serial over USB
}
// initialize the transceiver on the SPI bus
if (!radio.begin()) {
Serial.println(F("radio hardware is not responding!!"));
while (1) {} // hold in infinite loop
}
// print example's introductory prompt
Serial.println(F("RF24/examples/StreamingData"));
// To set the radioNumber via the Serial monitor on startup
Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'"));
while (!Serial.available()) {
// wait for user input
}
char input = Serial.parseInt();
radioNumber = input == 1;
Serial.print(F("radioNumber = "));
Serial.println((int)radioNumber);
// role variable is hardcoded to RX behavior, inform the user of this
Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// save on transmission time by setting the radio to only transmit the
// number of bytes we need to transmit
radio.setPayloadSize(SIZE); // default value is the maximum 32 bytes
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
// additional setup specific to the node's role
if (role) {
radio.stopListening(); // put radio in TX mode
} else {
radio.startListening(); // put radio in RX mode
}
// For debugging info
// printf_begin(); // needed only once for printing details
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
} // setup()
void loop() {
if (role) {
// This device is a TX node
radio.flush_tx();
uint8_t i = 0;
uint8_t failures = 0;
unsigned long start_timer = micros(); // start the timer
while (i < SIZE) {
makePayload(i); // make the payload
if (!radio.writeFast(&buffer, SIZE)) {
failures++;
radio.reUseTX();
} else {
i++;
}
if (failures >= 100) {
Serial.print(F("Too many failures detected. Aborting at payload "));
Serial.println(buffer[0]);
break;
}
}
unsigned long end_timer = micros(); // end the timer
Serial.print(F("Time to transmit = "));
Serial.print(end_timer - start_timer); // print the timer result
Serial.print(F(" us with "));
Serial.print(failures); // print failures detected
Serial.println(F(" failures detected"));
// to make this example readable in the serial monitor
delay(1000); // slow transmissions down by 1 second
} else {
// This device is a RX node
if (radio.available()) { // is there a payload?
radio.read(&buffer, SIZE); // fetch payload from FIFO
Serial.print(F("Received: "));
Serial.print(buffer); // print the payload's value
Serial.print(F(" - "));
Serial.println(counter++); // print the received counter
}
} // role
if (Serial.available()) {
// change the role via the serial monitor
char c = toupper(Serial.read());
if (c == 'T' && !role) {
// Become the TX node
role = true;
counter = 0; //reset the RX node's counter
Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
radio.stopListening();
} else if (c == 'R' && role) {
// Become the RX node
role = false;
Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));
radio.startListening();
}
}
} // loop
void makePayload(uint8_t i) {
// Make a single payload based on position in stream.
// This example employs function to save memory on certain boards.
// let the first character be an identifying alphanumeric prefix
// this lets us see which payload didn't get received
buffer[0] = i + (i < 26 ? 65 : 71);
for (uint8_t j = 0; j < SIZE - 1; ++j) {
char chr = j >= (SIZE - 1) / 2 + abs((SIZE - 1) / 2 - i);
chr |= j < (SIZE - 1) / 2 - abs((SIZE - 1) / 2 - i);
buffer[j + 1] = chr + 48;
}
}

View File

@ -0,0 +1,31 @@
# This configuration file contains a selection of the available options provided by the formatting tool "Artistic Style"
# http://astyle.sourceforge.net/astyle.html
#
# If you wish to change them, don't edit this file.
# Instead, copy it in the same folder of file "preferences.txt" and modify the copy. This way, you won't lose your custom formatter settings when upgrading the IDE
# If you don't know where file preferences.txt is stored, open the IDE, File -> Preferences and you'll find a link
mode=c
# 2 spaces indentation
indent=spaces=2
# also indent macros
indent-preprocessor
# indent classes, switches (and cases), comments starting at column 1
indent-classes
indent-switches
indent-cases
indent-col1-comments
# put a space around operators
pad-oper
# put a space after if/for/while
pad-header
# if you like one-liners, keep them
keep-one-line-statements
# remove-comment-prefix

View File

@ -0,0 +1,217 @@
/*
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
bool 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
unsigned long got_time; // Variable for the received timestamp
// 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"));
}
delay(1000); // Try again 1s later
}
/****************** Pong Back Role ***************************/
if (role == 0) {
unsigned long got_time; // Variable for the received timestamp
if (radio.available()) {
uint32_t failTimer = millis();
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,191 @@
/*
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 (unsigned long 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");
Serial.print("Payload Count: ");
Serial.println(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,182 @@
/*
* Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
/**
* Example using Dynamic Payloads
*
* This is an example of how to use payloads of a varying (dynamic) size.
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
// Hardware configuration
RF24 radio(7, 8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t addresses[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 role_pin is a digital input pin used to set the role of this radio.
// Connect the role_pin to GND to be the 'pong' receiver
// Leave the role_pin open to be the 'ping' transmitter
const short role_pin = 5; // use pin 5
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; // The role of the current running sketch
// variables used for changing the payload size dynamically (used when role == role_ping_out)
const int min_payload_size = 4;
const int max_payload_size = 32;
const int payload_size_increment = 1;
int send_payload_size = min_payload_size;
char receive_payload[max_payload_size + 1]; // +1 to allow room for a terminating NULL char
void setup(void)
{
pinMode(role_pin, INPUT); // set up the role pin
digitalWrite(role_pin, HIGH);
delay(20); // Just to get a solid reading on the role pin
// read the role_pin, establish our role
if (digitalRead(role_pin)) {
role = role_ping_out;
} else {
role = role_pong_back;
}
Serial.begin(115200);
printf_begin(); // needed for printDetails()
// Print preamble
Serial.println(F("RF24/examples/pingpair_dyn/"));
Serial.print(F("ROLE: "));
Serial.println(role_friendly_name[role]);
// Setup and configure rf radio
radio.begin();
radio.enableDynamicPayloads(); // Enable dynamic payloads
radio.setRetries(5, 15); // delay between retries = 5 * 250 + 250 = 1500 microseconds, number of retries = 15
// Open a writing and reading pipe on each radio, with opposite addresses
if (role == role_ping_out) {
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1, addresses[1]);
} else {
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1, addresses[0]);
}
radio.startListening(); // Start listening
radio.printDetails(); // Dump the configuration of the rf unit for debugging
}
void loop() {
/****************** Ping Out Role ***************************/
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";
radio.stopListening(); // First, stop listening so we can talk.
// Send the payload
Serial.print(F("Now sending length "));
Serial.println(send_payload_size);
radio.write(send_payload, send_payload_size); // This will block until complete
radio.startListening(); // Now, continue listening
unsigned long started_waiting_at = millis(); // Start a timer for measuring timout
bool timeout = false;
while (!radio.available() && !timeout) // Wait until we get a response or timeout is reached
{
if (millis() - started_waiting_at > 500) // Only wait for 500 milliseconds
timeout = true;
}
// Describe the results
if (timeout) {
Serial.println(F("Failed, response timed out."));
} else {
// Grab the response and print it
uint8_t len = radio.getDynamicPayloadSize(); // get payload's length
// If an illegal payload size was detected, all RX payloads will be flushed
if (!len)
return;
radio.read(receive_payload, len);
// Use payload as a C-string (for easy printing)
receive_payload[len] = 0; // put a NULL terminating zero at the end
// Spew it
Serial.print(F("Got response size="));
Serial.print(len);
Serial.print(F(" value="));
Serial.println(receive_payload);
}
send_payload_size += payload_size_increment; // Update size for next time.
if (send_payload_size > max_payload_size) // if payload length is larger than the radio can handle
send_payload_size = min_payload_size; // reset the payload length
delay(1000); // Try again 1s later
}
/****************** Pong Back Role ***************************/
// Receive each packet, send it back, and dump it out
if (role == role_pong_back) {
while (radio.available()) // if there is data ready
{
uint8_t len = radio.getDynamicPayloadSize(); // Fetch the the payload size
// If an illegal payload size was detected, all RX payloads will be flushed
if (!len)
continue;
radio.read(receive_payload, len);
// Use payload as a C-string (for easy printing)
receive_payload[len] = 0; // put a NULL terminating zero at the end
// Spew it
Serial.print(F("Got response size="));
Serial.print(len);
Serial.print(F(" value="));
Serial.println(receive_payload);
radio.stopListening(); // First, stop listening so we can talk
// Send a reply that the packet was received
//
// You will have better luck delivering your message if
// you wait for the other node to start listening first
delay(20);
radio.write(receive_payload, len);
Serial.println(F("Sent response."));
radio.startListening(); // Now, resume listening so we catch the next packets.
}
}
} // loop
// vim:cin:ai:sts=2 sw=2 ft=cpp

View File

@ -0,0 +1,172 @@
/*
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
// Our ACK payload will simply be 4 bytes containing the number of payloads received
static uint32_t message_count = 1; // start counting at 1
// 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 role_pin is a digital input pin used to set the role of this radio.
// Connect the role_pin to GND to be the 'pong' receiver
// Leave the role_pin open to be the 'ping' transmitter
const short role_pin = 5; // use pin 5
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
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 role_pin pin to establish our role
role = role_sender;
else
role = role_receiver;
Serial.begin(115200);
printf_begin(); // needed for printDetails()
// print introduction
Serial.print(F("\n\rRF24/examples/pingpair_irq\n\rROLE: "));
Serial.println(role_friendly_name[role]);
/********************** Setup and configure rf radio *********************/
radio.begin();
// Examples are usually run with both radios in close proximity to each other
radio.setPALevel(RF24_PA_LOW); // defaults to RF24_PA_MAX
radio.enableAckPayload(); // We will be using the ACK Payload feature which is not enabled by default
radio.enableDynamicPayloads(); // Ack payloads are dynamic payloads
// Open a writing and reading pipe on each radio, with opposite addresses
if (role == role_sender) {
radio.openWritingPipe(address[0]);
radio.openReadingPipe(1, address[1]);
} else {
radio.openWritingPipe(address[1]);
radio.openReadingPipe(1, address[0]);
radio.startListening(); // First we need to start listening
// Add an ACK payload for the first time around; 1 is the pipe number to acknowledge
radio.writeAckPayload(1, &message_count, sizeof(message_count));
++message_count; // increment counter by 1 for next ACK payload
}
radio.printDetails(); // Dump the configuration of the rf unit for debugging
delay(50);
// Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver
attachInterrupt(0, check_radio, LOW);
} // setup
void loop() {
/****************** Ping Out Role ***************************/
if (role == role_sender) {
// Repeatedly send the current time
unsigned long time = millis(); // Take the time
Serial.print(F("Now sending "));
Serial.println(time);
radio.startWrite(&time, sizeof(unsigned long), 0); // Send the time
delay(2000); // Try again soon (in 2 seconds)
}
/****************** Pong Back Role ***************************/
// Receiver does nothing! All the work is in Interrupt Handler
if (role == role_receiver) {}
} // loop
/********************** Interrupt Handler *********************/
void check_radio(void) {
bool tx, fail, rx; // declare variables to store IRQ flags
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?
/**************** Ping Out Role (about received ACK payload) ************************/
// If we're the sender, we've received an ack payload
if (role == role_sender) {
// Get the payload and dump it
radio.read(&message_count, sizeof(message_count));
Serial.print(F("Ack: "));
Serial.println(message_count);
}
/****************** Pong Back Role ***************************/
// If we're the receiver, we've received a time message
if (role == role_receiver) {
// Get the payload and dump it
static unsigned long got_time; // variable to hold the received time
radio.read(&got_time, sizeof(got_time)); // get the payload
Serial.print(F("Got payload "));
Serial.println(got_time);
// Add an ACK payload for the next time around; 1 is the pipe number to acknowledge
radio.writeAckPayload(1, &message_count, sizeof(message_count));
++message_count; // increment packet counter
}
}
} // check_radio

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(7, 8);
// 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 = 5;
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,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,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,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,2 @@
Note: These recipe examples may have not been maintained with library updates, and are provided as-is for reference purposes.
Warning: These are recipe examples are intended for specific hardware usage.

View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
* Updated 2020 TMRh20
*
* 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 and Continuous Carrier Wave Output
*
* 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.
*
* Run this sketch on two devices. On one device, start CCW output by sending a 'g'
* character over Serial. The other device scanning should detect the output of the sending
* device on the given channel. Adjust channel and output power of CCW below.
*
* Inspired by cpixip.
* See http://arduino.cc/forum/index.php/topic,54795.0.html
*/
#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();
//delay(1000);
// Print out header, high then low digit
int i = 0;
while ( i < num_channels )
{
Serial.print(i >> 4, HEX);
++i;
}
Serial.println();
i = 0;
while ( i < num_channels )
{
Serial.print(i & 0xf, HEX);
++i;
}
Serial.println();
//delay(1000);
}
//
// Loop
//
const int num_reps = 100;
bool constCarrierMode = 0;
void loop(void)
{
/****************************************/
// Send g over Serial to begin CCW output
// Configure the channel and power level below
if (Serial.available()) {
char c = Serial.read();
if (c == 'g') {
constCarrierMode = 1;
radio.stopListening();
delay(2);
Serial.println("Starting Carrier Out");
radio.startConstCarrier(RF24_PA_LOW, 40);
} else if (c == 'e') {
constCarrierMode = 0;
radio.stopConstCarrier();
Serial.println("Stopping Carrier Out");
}
}
/****************************************/
if (constCarrierMode == 0) {
// 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 )
{
Serial.print(min(0xf, values[i]), HEX);
++i;
}
Serial.println();
}//If constCarrierMode == 0
}

View File

@ -0,0 +1,204 @@
/**
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* written in 2014 by tong67 (https://github.com/tong67)
* Updated 2020 by 2bndy5 (http://github.com/2bndy5) for the
* SpenceKonde ATTinyCore (https://github.com/SpenceKonde/ATTinyCore)
*/
/**
* The RF24 library uses the [ATTinyCore by
* SpenceKonde](https://github.com/SpenceKonde/ATTinyCore)
*
* This sketch is a duplicate of the ManualAcknowledgements.ino example
* (without all the Serial input/output code), and it demonstrates
* a ATTiny25/45/85 or ATTiny24/44/84 driving the nRF24L01 transceiver using
* the RF24 class to communicate with another node.
*
* A simple example of sending data from 1 nRF24L01 transceiver to another
* with manually transmitted (non-automatic) Acknowledgement (ACK) payloads.
* This example still uses ACK packets, but they have no payloads. Instead the
* acknowledging response is sent with `write()`. This tactic allows for more
* updated acknowledgement payload data, where actual ACK payloads' data are
* outdated by 1 transmission because they have to loaded before receiving a
* transmission.
*
* This example was written to be used on 2 devices acting as "nodes".
*/
/*
* ********** Hardware configuration (& schematics) *******************
*
* When direct use of 3V does not work (UNO boards tend to have poor 3V supply),
* use 5V with LED (1.8V ~ 2.2V drop) instead.
* For low power consumption solutions floating pins (SCK and MOSI) should be
* pulled HIGH or LOW with 10K resistors.
*
* ATTiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 4
* ^^
* +-\/-+ //
* PB5 1|o |8 Vcc --- nRF24L01 VCC --- |<|--- 5V
* nRF24L01 CE --- PB3 2| |7 PB2 --- nRF24L01 SCK LED
* nRF24L01 CSN --- PB4 3| |6 PB1 --- nRF24L01 MOSI
* nRF24L01 GND --- GND 4| |5 PB0 --- nRF24L01 MISO
* +----+
*
* ATTiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 3 => PB3 and PB4 are
* free to use for other purposes. This "3 pin solution" is from
* Ralph Doncaster (AKA NerdRalph) which is outlined on his blog at
* 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 settle time delay value to use for RF24::csDelay in RF24::csn(), use
* the examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino sketch.
*
* This configuration is enabled in the RF24 library when CE_PIN and
* CSN_PIN parameters to the constructor are equal. Notice (in the schematic
* below) that these pins aren't directly to the ATTiny85. Because the CE pin
* is always HIGH, the power consumption is higher than it would be for the
* typical 5 pins solution.
* ^^
* +-\/-+ nRF24L01 CE --------| //
* PB5 1|o |8 Vcc --- nRF24L01 VCC -------x----------x--|<|-- 5V
* PB3 2| |7 PB2 --- nRF24L01 SCK ---|<|---x-[22k]--| LED
* PB4 3| |6 PB1 --- nRF24L01 MOSI 1n4148 |
* nRF24L01 GND -x- GND 4| |5 PB0 --- nRF24L01 MISO |
* | +----+ |
* |-----------------------------------------||----x-- nRF24L01 CSN
* 10nF
*
* ATTiny24/44/84 Pin map with CE_PIN 8 and CSN_PIN 7 & assuming 1.9V to 3V on VCC
* Schematic provided and successfully tested by
* Carmine Pastore (https://github.com/Carminepz)
*
* +-\/-+
* nRF24L01 VCC ---- VCC 1|o |14 GND --- nRF24L01 GND
* PB0 2| |13 AREF
* PB1 3| |12 PA1
* PB3 4| |11 PA2 --- nRF24L01 CE
* PB2 5| |10 PA3 --- nRF24L01 CSN
* PA7 6| |9 PA4 --- nRF24L01 SCK
* nRF24L01 MOSI --- PA6 7| |8 PA5 --- nRF24L01 MISO
* +----+
*/
#include "SPI.h"
#include "RF24.h"
// 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
// instantiate an object for the nRF24L01 transceiver
RF24 radio(CE_PIN, CSN_PIN);
// Let these addresses be used for the pair
uint8_t address[][6] = {"1Node", "2Node"};
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
// Used to control whether this node is sending or receiving
bool role = false; // true = TX node, false = RX node
// For this example, we'll be using a payload containing
// a string & an integer number that will be incremented
// on every successful transmission.
// Make a data structure to store the entire payload of different datatypes
struct PayloadStruct {
char message[7]; // only using 6 characters for TX & RX payloads
uint8_t counter;
};
PayloadStruct payload;
void setup() {
// append a NULL terminating character for printing as a c-string
payload.message[6] = 0;
// initialize the transceiver on the SPI bus
if (!radio.begin()) {
while (1) {} // hold in infinite loop
}
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// save on transmission time by setting the radio to only transmit the
// number of bytes we need to transmit a float
radio.setPayloadSize(sizeof(payload)); // char[7] & uint8_t datatypes occupy 8 bytes
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
if (role) {
// setup the TX node
memcpy(payload.message, "Hello ", 6); // set the outgoing message
radio.stopListening(); // put radio in TX mode
} else {
// setup the RX node
memcpy(payload.message, "World ", 6); // set the outgoing message
radio.startListening(); // put radio in RX mode
}
} // setup()
void loop() {
if (role) {
// This device is a TX node
bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report
if (report) {
// transmission successful; wait for response and print results
radio.startListening(); // put in RX mode
unsigned long start_timeout = millis(); // timer to detect no response
while (!radio.available()) { // wait for response or timeout
if (millis() - start_timeout > 200) // only wait 200 ms
break;
}
radio.stopListening(); // put back in TX mode
// print summary of transactions
if (radio.available()) { // is there a payload received?
PayloadStruct received;
radio.read(&received, sizeof(received)); // get payload from RX FIFO
payload.counter = received.counter; // save incoming counter for next outgoing counter
}
} // report
// to make this example readable in the serial monitor
delay(1000); // slow transmissions down by 1 second
} else {
// This device is a RX node
if (radio.available()) { // is there a payload?
PayloadStruct received;
radio.read(&received, sizeof(received)); // get incoming payload
payload.counter = received.counter + 1; // increment incoming counter for next outgoing response
// transmit response & save result to `report`
radio.stopListening(); // put in TX mode
radio.writeFast(&payload, sizeof(payload)); // load response to TX FIFO
bool report = radio.txStandBy(150); // keep retrying for 150 ms
radio.startListening(); // put back in RX mode
}
} // role
} // loop

View File

@ -0,0 +1,209 @@
/**
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* written by tong67 (https://github.com/tong67)
* edited by 2bndy5 (http://github.com/2bndy5) for compatibility with SpenceKonde's ATTinyCore
*/
/*
* This sketch can determine the best settle time values to use for
* macros, defined as RF24_CSN_SETTLE_HIGH_DELAY and RF24_CSN_SETTLE_LOW_DELAY,
* in RF24::csn().
* The settle time values used here are 100/20. However, these values depend
* on the actual used RC combiniation and voltage drop by LED. The
* intermediate results are written to TX (PB3, pin 2 -- using Serial).
*
* For schematic details, see introductory comment block in the
* examples/rf24_ATTiny/rf24ping85/rf24ping85.ino sketch.
*/
#include <stdio.h>
#include <SPI.h>
#include <Arduino.h>
#include <nRF24L01.h>
#if defined (ARDUINO) && !defined (__arm__)
#if defined(__AVR_ATtinyX5__) || defined(__AVR_ATtinyX4__)
#define RF24_TINY
#endif
#endif
/****************************************************************************/
#if defined(RF24_TINY)
// when Attiny84 or Attiny85 is detected
#define CE_PIN 3 /** "Chip Enable" pin, activates the RX or TX role */
#define CSN_PIN 3 /** SPI Chip Select Not */
#else
// when not running on an ATTiny84 or ATTiny85
#define CE_PIN 7 /** "Chip Enable" pin, activates the RX or TX role */
#define CSN_PIN 8 /** SPI Chip Select Not */
#endif
#define MAX_HIGH 100
#define MAX_LOW 100
#define MINIMAL 8
// Use these adjustable variables to test for best configuration to be used on
// the ATTiny chips. These variables are defined as macros in the library's
// RF24/utility/ATTiny/RF24_arch_config.h file. To change them, simply define
// the corresponding macro(s) before #include <RF24> in your sketch.
uint8_t csnHighSettle = MAX_HIGH; // defined as RF24_CSN_SETTLE_HIGH_DELAY
uint8_t csnLowSettle = MAX_LOW; // defined as RF24_CSN_SETTLE_LOW_DELAY
/****************************************************************************/
void ce(bool level) {
if (CE_PIN != CSN_PIN) digitalWrite(CE_PIN, level);
}
/****************************************************************************/
void csn(bool mode) {
if (CE_PIN != CSN_PIN) {
digitalWrite(CSN_PIN, mode);
} else {
// digitalWrite(SCK, mode);
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 | reg);
uint8_t result = SPI.transfer(0xff);
csn(HIGH);
return result;
}
/****************************************************************************/
void write_register(uint8_t reg, uint8_t value)
{
csn(LOW);
SPI.transfer(W_REGISTER | reg);
SPI.transfer(value);
csn(HIGH);
}
/****************************************************************************/
void setup(void) {
#ifndef __AVR_ATtinyX313__
// not enough memory on ATTiny4313 or ATTint2313(a) to use Serial I/O for this sketch
// start serial port and SPI
Serial.begin(115200);
SPI.begin();
// configure CE and CSN as output when used
pinMode(CE_PIN, OUTPUT);
if (CSN_PIN != CE_PIN)
pinMode(CSN_PIN, OUTPUT);
// 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 pin 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_register(NRF_CONFIG, read_register(NRF_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_register(NRF_CONFIG, read_register(NRF_CONFIG) | _BV(PWR_UP));
delay(5) ;
// Goto Standby-II
ce(HIGH);
Serial.print("Scanning for optimal setting time for csn");
/************************** Main program *********************************/
uint8_t result; // used to compare read/write results with read/write cmds
bool success = true;
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 (uint8_t k = 0; k < 2; k++) {
bottom_found = false;
bottom_success = 0;
while (bottom_success < 255) {
csnHighSettle = limit[0];
csnLowSettle = limit[1];
// check current values
uint8_t i = 0;
while (i < 255 && success) {
for (uint8_t j = 0; j < 2; j++) {
write_register(EN_AA, value[j]);
result = read_register(EN_AA);
if (value[j] != result) {
success = false;
}
}
i++;
}
// process result of current values
if (!success) {
Serial.print("Settle Not OK. 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++;
}
}
} // while (bottom_success < 255)
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;
} // for (uint8_t k = 0; k < 2; k++)
Serial.print("Advised Settle times are: csnHigh=");
Serial.print(advice[0], DEC);
Serial.print(" csnLow=");
Serial.println(advice[1], DEC);
#endif // not defined __AVR_ATtinyX313__
}
void loop(void) {} // this program runs only once, thus it resides in setup()

View File

@ -0,0 +1,23 @@
#############################################################################
#
# 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
#
ifeq ($(wildcard ../Makefile.inc), )
$(error Configuration not found. Run ./configure first)
endif
include ../Makefile.inc
# define all programs
PROGRAMS = gettingstarted acknowledgementPayloads manualAcknowledgements streamingData multiceiverDemo interruptConfigure
include Makefile.examples

View File

@ -0,0 +1,230 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/
/**
* A simple example of sending data from 1 nRF24L01 transceiver to another
* with Acknowledgement (ACK) payloads attached to ACK packets.
*
* This example was written to be used on 2 devices acting as "nodes".
* Use `ctrl+c` to quit at any time.
*/
#include <ctime> // time()
#include <iostream> // cin, cout, endl
#include <string> // string, getline()
#include <time.h> // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
#include <RF24/RF24.h> // RF24, RF24_PA_LOW, delay()
using namespace std;
/****************** Linux ***********************/
// Radio CE Pin, CSN Pin, SPI Speed
// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
// ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
// Generic:
RF24 radio(22, 0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.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
// For this example, we'll be using a payload containing
// a string & an integer number that will be incremented
// on every successful transmission.
// Make a data structure to store the entire payload of different datatypes
struct PayloadStruct {
char message[7]; // only using 6 characters for TX & ACK payloads
uint8_t counter;
};
PayloadStruct payload;
void setRole(); // prototype to set the node's role
void master(); // prototype of the TX node's behavior
void slave(); // prototype of the RX node's behavior
// custom defined timer for evaluating transmission time in microseconds
struct timespec startTimer, endTimer;
uint32_t getMicros(); // prototype to get ellapsed time in microseconds
int main(int argc, char** argv) {
// perform hardware check
if (!radio.begin()) {
cout << "radio hardware is not responding!!" << endl;
return 0; // quit now
}
// Let these addresses be used for the pair
uint8_t address[2][6] = {"1Node", "2Node"};
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
// print example's name
cout << argv[0] << endl;
// Set the radioNumber via the terminal on startup
cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' ";
string input;
getline(cin, input);
radioNumber = input.length() > 0 && (uint8_t)input[0] == 49;
// to use ACK payloads, we need to enable dynamic payload lengths
radio.enableDynamicPayloads(); // ACK payloads are dynamically sized
// Acknowledgement packets have no payloads by default. We need to enable
// this feature for all nodes (TX & RX) to use ACK payloads.
radio.enableAckPayload();
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
// For debugging info
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
// ready to execute program now
setRole(); // calls master() or slave() based on user input
return 0;
}
/**
* set this node's role from stdin stream.
* this only considers the first char as input.
*/
void setRole() {
string input = "";
while (!input.length()) {
cout << "*** PRESS 'T' to begin transmitting to the other node\n";
cout << "*** PRESS 'R' to begin receiving from the other node\n";
cout << "*** PRESS 'Q' to exit" << endl;
getline(cin, input);
if (input.length() >= 1) {
if (input[0] == 'T' || input[0] == 't')
master();
else if (input[0] == 'R' || input[0] == 'r')
slave();
else if (input[0] == 'Q' || input[0] == 'q')
break;
else
cout << input[0] << " is an invalid input. Please try again." << endl;
}
input = ""; // stay in the while loop
} // while
} // setRole()
/**
* make this node act as the transmitter
*/
void master() {
memcpy(payload.message, "Hello ", 6); // set the payload message
radio.stopListening(); // put radio in TX mode
unsigned int failures = 0; // keep track of failures
while (failures < 6) {
clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer
bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report
uint32_t timerEllapsed = getMicros(); // end the timer
if (report) {
// payload was delivered
cout << "Transmission successful! Time to transmit = ";
cout << timerEllapsed; // print the timer result
cout << " us. Sent: ";
cout << payload.message; // print outgoing message
cout << (unsigned int)payload.counter; // print outgoing counter counter
uint8_t pipe;
if (radio.available(&pipe)) {
PayloadStruct received;
radio.read(&received, sizeof(received)); // get incoming ACK payload
cout << " Received ";
cout << radio.getDynamicPayloadSize(); // print incoming payload size
cout << " bytes on pipe " << (unsigned int)pipe; // print pipe that received it
cout << ": " << received.message; // print incoming message
cout << (unsigned int)received.counter << endl; // print incoming counter
payload.counter = received.counter + 1; // save incoming counter & increment for next outgoing
} // if got an ACK payload
else {
cout << " Received an empty ACK packet." << endl; // ACK had no payload
}
} // if delivered
else {
cout << "Transmission failed or timed out" << endl; // payload was not delivered
failures++; // increment failures
}
// to make this example readable in the terminal
delay(1000); // slow transmissions down by 1 second
} // while
cout << failures << " failures detected. Leaving TX role." << endl;
} // master
/**
* make this node act as the receiver
*/
void slave() {
memcpy(payload.message, "World ", 6); // set the payload message
// load the payload for the first received transmission on pipe 0
radio.writeAckPayload(1, &payload, sizeof(payload));
radio.startListening(); // put radio in RX mode
time_t startTimer = time(nullptr); // start a timer
while (time(nullptr) - startTimer < 6) { // use 6 second timeout
uint8_t pipe;
if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it
uint8_t bytes = radio.getDynamicPayloadSize(); // get the size of the payload
PayloadStruct received;
radio.read(&received, sizeof(received)); // fetch payload from RX FIFO
cout << "Received " << (unsigned int)bytes; // print the size of the payload
cout << " bytes on pipe " << (unsigned int)pipe; // print the pipe number
cout << ": " << received.message;
cout << (unsigned int)received.counter; // print received payload
cout << " Sent: ";
cout << payload.message;
cout << (unsigned int)payload.counter << endl; // print ACK payload sent
startTimer = time(nullptr); // reset timer
// save incoming counter & increment for next outgoing
payload.counter = received.counter + 1;
// load the payload for the first received transmission on pipe 0
radio.writeAckPayload(1, &payload, sizeof(payload));
} // if received something
} // while
cout << "Nothing received in 6 seconds. Leaving RX role." << endl;
radio.stopListening(); // recommended idle behavior is TX mode
} // slave
/**
* Calculate the ellapsed time in microseconds
*/
uint32_t getMicros() {
// this function assumes that the timer was started using
// `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);`
clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer);
uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec;
uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000;
return ((seconds) * 1000 + useconds) + 0.5;
}

View File

@ -0,0 +1,238 @@
"""
A simple example of sending data from 1 nRF24L01 transceiver to another
with Acknowledgement (ACK) payloads attached to ACK packets.
This example was written to be used on 2 devices acting as 'nodes'.
"""
import sys
import argparse
import time
from RF24 import RF24, RF24_PA_LOW
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
"-n",
"--node",
type=int,
choices=range(2),
help="the identifying radio number (or node ID number)"
)
parser.add_argument(
"-r",
"--role",
type=int,
choices=range(2),
help="'1' specifies the TX role. '0' specifies the RX role."
)
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
# Radio CE Pin, CSN Pin, SPI Speed
# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
# ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
# Generic:
radio = RF24(22, 0)
################## Linux (BBB,x86,etc) #########################
# See http://nRF24.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
# using the python keyword global is bad practice. Instead we'll use a
# 1 item list to store our integer number for the payloads' counter
counter = [0]
def master():
"""Transmits a message and an incrementing integer every second."""
radio.stopListening() # put radio in TX mode
failures = 0
while failures < 6:
# construct a payload to send
buffer = b"Hello \x00" + bytes(counter)
# send the payload and prompt
start_timer = time.monotonic_ns() # start timer
result = radio.write(buffer) # save the report
end_timer = time.monotonic_ns() # stop timer
if result:
# print timer results upon transmission success
print(
"Transmission successful! Time to transmit: "
"{} us. Sent: {}{}".format(
int((end_timer - start_timer) / 1000),
buffer[:6].decode("utf-8"),
counter[0]
),
end=" "
)
has_payload, pipe_number = radio.available_pipe()
if has_payload:
# print the received ACK that was automatically sent
length = radio.getDynamicPayloadSize()
response = radio.read(length)
print(
"Received {} on pipe {}: {}{}".format(
length,
pipe_number,
bytes(response[:6]).decode("utf-8"),
response[7:8][0]
)
)
# increment counter from received payload
if response[7:8][0] < 255:
counter[0] = response[7:8][0] + 1
else:
counter[0] = 0
else:
print("Received an empty ACK packet")
else:
failures += 1
print("Transmission failed or timed out")
time.sleep(1) # let the RX node prepare a new ACK payload
print(failures, "failures detected. Leaving TX role.")
def slave(timeout=6):
"""Listen for any payloads and print the transaction
:param int timeout: The number of seconds to wait (with no transmission)
until exiting function.
"""
radio.startListening() # put radio in RX mode
# setup the first transmission's ACK payload
buffer = b"World \x00" + bytes(counter)
# we must set the ACK payload data and corresponding
# pipe number [0,5]
radio.writeAckPayload(1, buffer) # load ACK for first response
start_timer = time.monotonic() # start timer
while (time.monotonic() - start_timer) < timeout:
has_payload, pipe_number = radio.available_pipe()
if has_payload:
length = radio.getDynamicPayloadSize() # grab the payload length
received = radio.read(length) # fetch 1 payload from RX FIFO
# increment counter from received payload
counter[0] = received[7:8][0] + 1 if received[7:8][0] < 255 else 0
print(
"Received {} bytes on pipe {}: {}{} Sent: {}{}".format(
length,
pipe_number,
bytes(received[:6]).decode("utf-8"),
received[7:8][0],
buffer[:6].decode("utf-8"),
buffer[7:8][0]
)
)
buffer = b"World \x00" + bytes(counter) # build a new ACK payload
radio.writeAckPayload(1, buffer) # load ACK for next response
start_timer = time.monotonic() # reset timer
print("Nothing received in 6 seconds. Leaving RX role")
# recommended behavior is to keep in TX mode while idle
radio.stopListening() # put radio in TX mode & flush unused ACK payloads
def set_role():
"""Set the role using stdin stream. Timeout arg for slave() can be
specified using a space delimiter (e.g. 'R 10' calls `slave(10)`)
:return:
- True when role is complete & app should continue running.
- False when app should exit
"""
user_input = input(
"*** Enter 'R' for receiver role.\n"
"*** Enter 'T' for transmitter role.\n"
"*** Enter 'Q' to quit example.\n"
) or "?"
user_input = user_input.split()
if user_input[0].upper().startswith("R"):
if len(user_input) > 1:
slave(int(user_input[1]))
else:
slave()
return True
elif user_input[0].upper().startswith("T"):
master()
return True
elif user_input[0].upper().startswith("Q"):
radio.powerDown()
return False
print(user_input[0], "is an unrecognized input. Please try again.")
return set_role()
if __name__ == "__main__":
args = parser.parse_args() # parse any CLI args
# initialize the nRF24L01 on the spi bus
if not radio.begin():
raise RuntimeError("radio hardware is not responding")
# For this example, we will use different addresses
# An address need to be a buffer protocol object (bytearray)
address = [b"1Node", b"2Node"]
# It is very helpful to think of an address as a path instead of as
# an identifying device destination
print(sys.argv[0]) # print example name
# to use different addresses on a pair of radios, we need a variable to
# uniquely identify which address this radio will use to transmit
# 0 uses address[0] to transmit, 1 uses address[1] to transmit
radio_number = args.node # uses default value from `parser`
if args.node is None: # if '--node' arg wasn't specified
radio_number = bool(
int(
input(
"Which radio is this? Enter '0' or '1'. Defaults to '0' "
) or 0
)
)
# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity of each other
radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
# ACK payloads are dynamically sized.
radio.enableDynamicPayloads() # to use ACK payloads
# to enable the custom ACK payload feature
radio.enableAckPayload()
# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity of each other
radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
# set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radio_number]) # always uses pipe 0
# set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
# for debugging, we have 2 options that print a large block of details
# (smaller) function that prints raw register values
# radio.printDetails()
# (larger) function that prints human readable data
# radio.printPrettyDetails()
try:
if args.role is None: # if not specified with CLI arg '-r'
while set_role():
pass # continue example until 'Q' is entered
else: # if role was set using CLI args
# run role once and exit
master() if bool(args.role) else slave()
except KeyboardInterrupt:
print(" Keyboard Interrupt detected. Exiting...")
radio.powerDown()
sys.exit()

View File

@ -0,0 +1,203 @@
"""
A simple example of sending data from 1 nRF24L01 transceiver to another.
This example was written to be used on 2 devices acting as 'nodes'.
"""
import sys
import argparse
import time
import struct
from RF24 import RF24, RF24_PA_LOW
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
"-n",
"--node",
type=int,
choices=range(2),
help="the identifying radio number (or node ID number)"
)
parser.add_argument(
"-r",
"--role",
type=int,
choices=range(2),
help="'1' specifies the TX role. '0' specifies the RX role."
)
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
# Radio CE Pin, CSN Pin, SPI Speed
# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
# ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
# Generic:
radio = RF24(22, 0)
################## Linux (BBB,x86,etc) #########################
# See http://nRF24.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
# using the python keyword global is bad practice. Instead we'll use a 1 item
# list to store our float number for the payloads sent/received
payload = [0.0]
def master():
"""Transmits an incrementing float every second"""
radio.stopListening() # put radio in TX mode
failures = 0
while failures < 6:
# use struct.pack() to packet your data into the payload
# "<f" means a single little endian (4 byte) float value.
buffer = struct.pack("<f", payload[0])
start_timer = time.monotonic_ns() # start timer
result = radio.write(buffer)
end_timer = time.monotonic_ns() # end timer
if not result:
print("Transmission failed or timed out")
failures += 1
else:
print(
"Transmission successful! Time to Transmit: "
"{} us. Sent: {}".format(
(end_timer - start_timer) / 1000,
payload[0]
)
)
payload[0] += 0.01
time.sleep(1)
print(failures, "failures detected. Leaving TX role.")
def slave(timeout=6):
"""Listen for any payloads and print the transaction
:param int timeout: The number of seconds to wait (with no transmission)
until exiting function.
"""
radio.startListening() # put radio in RX mode
start_timer = time.monotonic()
while (time.monotonic() - start_timer) < timeout:
has_payload, pipe_number = radio.available_pipe()
if has_payload:
# fetch 1 payload from RX FIFO
buffer = radio.read(radio.payloadSize)
# use struct.unpack() to convert the buffer into usable data
# expecting a little endian float, thus the format string "<f"
# buffer[:4] truncates padded 0s in case payloadSize was not set
payload[0] = struct.unpack("<f", buffer[:4])[0]
# print details about the received packet
print(
"Received {} bytes on pipe {}: {}".format(
radio.payloadSize,
pipe_number,
payload[0]
)
)
start_timer = time.monotonic() # reset the timeout timer
print("Nothing received in 6 seconds. Leaving RX role")
# recommended behavior is to keep in TX mode while idle
radio.stopListening() # put the radio in TX mode
def set_role():
"""Set the role using stdin stream. Timeout arg for slave() can be
specified using a space delimiter (e.g. 'R 10' calls `slave(10)`)
:return:
- True when role is complete & app should continue running.
- False when app should exit
"""
user_input = input(
"*** Enter 'R' for receiver role.\n"
"*** Enter 'T' for transmitter role.\n"
"*** Enter 'Q' to quit example.\n"
) or "?"
user_input = user_input.split()
if user_input[0].upper().startswith("R"):
if len(user_input) > 1:
slave(int(user_input[1]))
else:
slave()
return True
elif user_input[0].upper().startswith("T"):
master()
return True
elif user_input[0].upper().startswith("Q"):
radio.powerDown()
return False
print(user_input[0], "is an unrecognized input. Please try again.")
return set_role()
if __name__ == "__main__":
args = parser.parse_args() # parse any CLI args
# initialize the nRF24L01 on the spi bus
if not radio.begin():
raise RuntimeError("radio hardware is not responding")
# For this example, we will use different addresses
# An address need to be a buffer protocol object (bytearray)
address = [b"1Node", b"2Node"]
# It is very helpful to think of an address as a path instead of as
# an identifying device destination
print(sys.argv[0]) # print example name
# to use different addresses on a pair of radios, we need a variable to
# uniquely identify which address this radio will use to transmit
# 0 uses address[0] to transmit, 1 uses address[1] to transmit
radio_number = args.node # uses default value from `parser`
if args.node is None: # if '--node' arg wasn't specified
radio_number = bool(
int(
input(
"Which radio is this? Enter '0' or '1'. Defaults to '0' "
) or 0
)
)
# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity of each other
radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
# set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radio_number]) # always uses pipe 0
# set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
# To save time during transmission, we'll set the payload size to be only
# what we need. A float value occupies 4 bytes in memory using
# struct.pack(); "<f" means a little endian unsigned float
radio.payloadSize = len(struct.pack("<f", payload[0]))
# for debugging, we have 2 options that print a large block of details
# (smaller) function that prints raw register values
# radio.printDetails()
# (larger) function that prints human readable data
# radio.printPrettyDetails()
try:
if args.role is None: # if not specified with CLI arg '-r'
while set_role():
pass # continue example until 'Q' is entered
else: # if role was set using CLI args
# run role once and exit
master() if bool(args.role) else slave()
except KeyboardInterrupt:
print(" Keyboard Interrupt detected. Exiting...")
radio.powerDown()
sys.exit()

View File

@ -0,0 +1,191 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/
/**
* A simple example of sending data from 1 nRF24L01 transceiver to another.
*
* This example was written to be used on 2 devices acting as "nodes".
* Use `ctrl+c` to quit at any time.
*/
#include <ctime> // time()
#include <iostream> // cin, cout, endl
#include <string> // string, getline()
#include <time.h> // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
#include <RF24/RF24.h> // RF24, RF24_PA_LOW, delay()
using namespace std;
/****************** Linux ***********************/
// Radio CE Pin, CSN Pin, SPI Speed
// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
// ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
// Generic:
RF24 radio(22, 0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.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
// For this example, we'll be using a payload containing
// a single float number that will be incremented
// on every successful transmission
float payload = 0.0;
void setRole(); // prototype to set the node's role
void master(); // prototype of the TX node's behavior
void slave(); // prototype of the RX node's behavior
// custom defined timer for evaluating transmission time in microseconds
struct timespec startTimer, endTimer;
uint32_t getMicros(); // prototype to get ellapsed time in microseconds
int main(int argc, char** argv) {
// perform hardware check
if (!radio.begin()) {
cout << "radio hardware is not responding!!" << endl;
return 0; // quit now
}
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
// print example's name
cout << argv[0] << endl;
// Let these addresses be used for the pair
uint8_t address[2][6] = {"1Node", "2Node"};
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// Set the radioNumber via the terminal on startup
cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' ";
string input;
getline(cin, input);
radioNumber = input.length() > 0 && (uint8_t)input[0] == 49;
// save on transmission time by setting the radio to only transmit the
// number of bytes we need to transmit a float
radio.setPayloadSize(sizeof(payload)); // float datatype occupies 4 bytes
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
// For debugging info
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
// ready to execute program now
setRole(); // calls master() or slave() based on user input
return 0;
}
/**
* set this node's role from stdin stream.
* this only considers the first char as input.
*/
void setRole() {
string input = "";
while (!input.length()) {
cout << "*** PRESS 'T' to begin transmitting to the other node\n";
cout << "*** PRESS 'R' to begin receiving from the other node\n";
cout << "*** PRESS 'Q' to exit" << endl;
getline(cin, input);
if (input.length() >= 1) {
if (input[0] == 'T' || input[0] == 't')
master();
else if (input[0] == 'R' || input[0] == 'r')
slave();
else if (input[0] == 'Q' || input[0] == 'q')
break;
else
cout << input[0] << " is an invalid input. Please try again." << endl;
}
input = ""; // stay in the while loop
} // while
} // setRole()
/**
* make this node act as the transmitter
*/
void master() {
radio.stopListening(); // put radio in TX mode
unsigned int failure = 0; // keep track of failures
while (failure < 6) {
clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer
bool report = radio.write(&payload, sizeof(float)); // transmit & save the report
uint32_t timerEllapsed = getMicros(); // end the timer
if (report) {
// payload was delivered
cout << "Transmission successful! Time to transmit = ";
cout << timerEllapsed; // print the timer result
cout << " us. Sent: " << payload << endl; // print payload sent
payload += 0.01; // increment float payload
} else {
// payload was not delivered
cout << "Transmission failed or timed out" << endl;
failure++;
}
// to make this example readable in the terminal
delay(1000); // slow transmissions down by 1 second
}
cout << failure << " failures detected. Leaving TX role." << endl;
}
/**
* make this node act as the receiver
*/
void slave() {
radio.startListening(); // put radio in RX mode
time_t startTimer = time(nullptr); // start a timer
while (time(nullptr) - startTimer < 6) { // use 6 second timeout
uint8_t pipe;
if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it
uint8_t bytes = radio.getPayloadSize(); // get the size of the payload
radio.read(&payload, bytes); // fetch payload from FIFO
cout << "Received " << (unsigned int)bytes; // print the size of the payload
cout << " bytes on pipe " << (unsigned int)pipe; // print the pipe number
cout << ": " << payload << endl; // print the payload's value
startTimer = time(nullptr); // reset timer
}
}
cout << "Nothing received in 6 seconds. Leaving RX role." << endl;
radio.stopListening();
}
/**
* Calculate the ellapsed time in microseconds
*/
uint32_t getMicros() {
// this function assumes that the timer was started using
// `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);`
clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer);
uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec;
uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000;
return ((seconds) * 1000 + useconds) + 0.5;
}

View File

@ -0,0 +1,319 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/
/**
* This example uses Acknowledgement (ACK) payloads attached to ACK packets to
* demonstrate how the nRF24L01's IRQ (Interrupt Request) pin can be
* configured to detect when data is received, or when data has transmitted
* successfully, or when data has failed to transmit.
*
* This example was written to be used on 2 devices acting as "nodes".
* Use `ctrl+c` to quit at any time.
*/
#include <ctime> // time()
#include <iostream> // cin, cout, endl
#include <string> // string, getline()
#include <time.h> // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
#include <RF24/RF24.h> // RF24, RF24_PA_LOW, delay(), pinMode(), INPUT, attachInterrupt(), INT_EDGE_FALLING
using namespace std;
// We will be using the nRF24L01's IRQ pin for this example
#define IRQ_PIN 12 // this needs to be a digital input capable pin
// this example is a sequential program. so we need to wait for the event to be handled
volatile bool wait_for_event = false; // used to signify that the event is handled
/****************** Linux ***********************/
// Radio CE Pin, CSN Pin, SPI Speed
// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
// ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
// Generic:
RF24 radio(22, 0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.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
// For this example, we'll be using a payload containing
// a string that changes on every transmission. (successful or not)
// Make a couple arrays of payloads & an iterator to traverse them
const uint8_t tx_pl_size = 5;
const uint8_t ack_pl_size = 4;
uint8_t pl_iterator = 0;
// The " + 1" compensates for the c-string's NULL terminating 0
char tx_payloads[4][tx_pl_size + 1] = {"Ping ", "Pong ", "Radio", "1FAIL"};
char ack_payloads[3][ack_pl_size + 1] = {"Yak ", "Back", " ACK"};
void interruptHandler(); // prototype to handle the interrupt request (IRQ) pin
void setRole(); // prototype to set the node's role
void master(); // prototype of the TX node's behavior
void slave(); // prototype of the RX node's behavior
void ping_n_wait(); // prototype that sends a payload and waits for the IRQ pin to get triggered
void printRxFifo(const uint8_t); // prototype to print entire contents of RX FIFO with 1 buffer
int main(int argc, char** argv) {
// perform hardware check
if (!radio.begin()) {
cout << "radio hardware is not responding!!" << endl;
return 0; // quit now
}
// Let these addresses be used for the pair
uint8_t address[2][6] = {"1Node", "2Node"};
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
// print example's name
cout << argv[0] << endl;
// Set the radioNumber via the terminal on startup
cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' ";
string input;
getline(cin, input);
radioNumber = input.length() > 0 && (uint8_t)input[0] == 49;
// to use ACK payloads, we need to enable dynamic payload lengths
radio.enableDynamicPayloads(); // ACK payloads are dynamically sized
// Acknowledgement packets have no payloads by default. We need to enable
// this feature for all nodes (TX & RX) to use ACK payloads.
radio.enableAckPayload();
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
// For debugging info
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
// setup the digital input pin connected to the nRF24L01's IRQ pin
pinMode(IRQ_PIN, INPUT);
// register the interrupt request (IRQ) to call our
// Interrupt Service Routine (ISR) callback function interruptHandler()
attachInterrupt(IRQ_PIN, INT_EDGE_FALLING, &interruptHandler);
// IMPORTANT: do not call radio.available() before calling
// radio.whatHappened() when the interruptHandler() is triggered by the
// IRQ pin FALLING event. According to the datasheet, the pipe information
// is unreliable during the IRQ pin FALLING transition.
// ready to execute program now
setRole(); // calls master() or slave() based on user input
return 0;
} // main
/**
* set this node's role from stdin stream.
* this only considers the first char as input.
*/
void setRole() {
string input = "";
while (!input.length()) {
cout << "*** PRESS 'T' to begin transmitting to the other node\n";
cout << "*** PRESS 'R' to begin receiving from the other node\n";
cout << "*** PRESS 'Q' to exit" << endl;
getline(cin, input);
if (input.length() >= 1) {
if (input[0] == 'T' || input[0] == 't')
master();
else if (input[0] == 'R' || input[0] == 'r')
slave();
else if (input[0] == 'Q' || input[0] == 'q')
break;
else
cout << input[0] << " is an invalid input. Please try again." << endl;
}
input = ""; // stay in the while loop
} // while
} // setRole
/**
* act as the transmitter to show 3 different IRQ events by sending 4 payloads:
* 1. Successfully receive ACK payload first
* 2. Successfully transmit on second
* 3. Send a third payload to fill RX node's RX FIFO (supposedly making RX node unresponsive)
* 4. intentionally fail transmit on the fourth
*/
void master() {
pl_iterator = 0; // reset the iterator for the following tests done in master()
// Test the "data ready" event with the IRQ pin
cout << "\nConfiguring IRQ pin to ignore the 'data sent' event\n";
radio.maskIRQ(true, false, false); // args = "data_sent", "data_fail", "data_ready"
cout << " Pinging RX node for 'data ready' event...";
ping_n_wait(); // transmit a payload and detect the IRQ pin
pl_iterator++; // increment iterator for next test
// Test the "data sent" event with the IRQ pin
cout << "\nConfiguring IRQ pin to ignore the 'data ready' event\n";
radio.maskIRQ(false, false, true); // args = "data_sent", "data_fail", "data_ready"
cout << " Pinging RX node for 'data sent' event...";
radio.flush_tx(); // flush payloads from any failed prior test
ping_n_wait(); // transmit a payload and detect the IRQ pin
pl_iterator++; // increment iterator for next test
// Use this iteration to fill the RX node's FIFO which sets us up for the next test.
// write() uses virtual interrupt flags that work despite the masking of the IRQ pin
radio.maskIRQ(1, 1, 1); // disable IRQ masking for this step
cout << "\nSending 1 payload to fill RX node's FIFO. IRQ pin is neglected.\n";
// write() will call flush_tx() on 'data fail' events
if (radio.write(&tx_payloads[pl_iterator], tx_pl_size))
cout << "RX node's FIFO is full; it is not listening any more" << endl;
else {
cout << "Transmission failed or timed out. Continuing anyway." << endl;
radio.flush_tx();
}
pl_iterator++; // increment iterator for next test
// test the "data fail" event with the IRQ pin
cout << "\nConfiguring IRQ pin to reflect all events\n";
radio.maskIRQ(0, 0, 0); // args = "data_sent", "data_fail", "data_ready"
cout << " Pinging inactive RX node for 'data fail' event...";
ping_n_wait(); // transmit a payload and detect the IRQ pin
// CE pin is still HIGH which consumes more power. Example is now idling so...
radio.stopListening(); // ensure CE pin is LOW
// stopListening() also calls flush_tx() when ACK payloads are enabled
if (radio.available()) {
printRxFifo(ack_pl_size); // doing this will flush the RX FIFO
}
} // master
/**
* act as the receiver
*/
void slave() {
// let IRQ pin only trigger on "data_ready" event in RX mode
radio.maskIRQ(1, 1, 0); // args = "data_sent", "data_fail", "data_ready"
// Fill the TX FIFO with 3 ACK payloads for the first 3 received
// transmissions on pipe 0.
radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size);
radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size);
radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size);
radio.startListening(); // put radio in RX mode
time_t startTimer = time(nullptr); // start a timer
while (time(nullptr) - startTimer < 6 && !radio.rxFifoFull()) {
// use 6 second timeout & wait till RX FIFO is full
}
delay(100); // wait for ACK payload to finish transmitting
radio.stopListening(); // also discards unused ACK payloads
if (radio.available()) {
printRxFifo(tx_pl_size);
}
else {
cout << "Timeout was reached. Going back to setRole()" << endl;
}
} // slave
/**
* pings the receiver with a non-blocking startWrite(), then waits till
* the IRQ pin is triggered
*/
void ping_n_wait() {
// use the non-blocking call to write a payload and begin transmission
// the "false" argument means we are expecting an ACK packet response
radio.startFastWrite(tx_payloads[pl_iterator], tx_pl_size, false);
wait_for_event = true;
while (wait_for_event) {
/*
* IRQ pin is LOW when activated. Otherwise it is always HIGH
* Wait in this empty loop until IRQ pin is activated.
*
* In this example, the "data fail" event is always configured to
* trigger the IRQ pin active. Because the auto-ACK feature is on by
* default, we don't need a timeout check to prevent an infinite loop.
*/
}
}
/**
* when the IRQ pin goes active LOW, call this fuction print out why
*/
void interruptHandler() {
// print IRQ status and all masking flags' states
cout << "\tIRQ pin is actively LOW" << endl; // show that this function was called
bool tx_ds, tx_df, rx_dr; // declare variables for IRQ masks
radio.whatHappened(tx_ds, tx_df, rx_dr); // get values for IRQ masks
// whatHappened() clears the IRQ masks also. This is required for
// continued TX operations when a transmission fails.
// clearing the IRQ masks resets the IRQ pin to its inactive state (HIGH)
cout << "\tdata_sent: " << tx_ds; // print "data sent" mask state
cout << ", data_fail: " << tx_df; // print "data fail" mask state
cout << ", data_ready: " << rx_dr << endl; // print "data ready" mask state
if (tx_df) // if TX payload failed
radio.flush_tx(); // clear all payloads from the TX FIFO
// print if test passed or failed. Unintentional fails mean the RX node was not listening.
if (pl_iterator == 0)
cout << " 'Data Ready' event test " << (rx_dr ? "passed" : "failed") << endl;
else if (pl_iterator == 1)
cout << " 'Data Sent' event test " << (tx_ds ? "passed" : "failed") << endl;
else if (pl_iterator == 3)
cout << " 'Data Fail' event test " << (tx_df ? "passed" : "failed") << endl;
wait_for_event = false; // ready to continue
} // interruptHandler
/**
* Print the entire RX FIFO with one buffer. This will also flush the RX FIFO.
* @param pl_size used to determine received payload size. Remember that the
* payload sizes are declared as tx_pl_size and ack_pl_size.
*/
void printRxFifo(const uint8_t pl_size) {
char rx_fifo[pl_size * 3 + 1]; // assuming RX FIFO is full; declare a buffer to hold it all
if (radio.rxFifoFull()) {
rx_fifo[pl_size * 3] = 0; // add a NULL terminating char to use as a c-string
radio.read(&rx_fifo, pl_size * 3); // this clears the RX FIFO (for this example)
}
else {
uint8_t i = 0;
while (radio.available()) {
radio.read(&rx_fifo + (i * pl_size), pl_size);
i++;
}
rx_fifo[i * pl_size] = 0; // add a NULL terminating char to use as a c-string
}
// print the entire RX FIFO with 1 buffer
cout << "Complete RX FIFO: " << rx_fifo << endl;
}

View File

@ -0,0 +1,300 @@
"""
This example uses Acknowledgement (ACK) payloads attached to ACK packets to
demonstrate how the nRF24L01's IRQ (Interrupt Request) pin can be
configured to detect when data is received, or when data has transmitted
successfully, or when data has failed to transmit.
This example was written to be used on 2 devices acting as "nodes".
"""
import sys
import argparse
import time
import RPi.GPIO as GPIO
from RF24 import RF24, RF24_PA_LOW
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
"-n",
"--node",
type=int,
choices=range(2),
help="the identifying radio number (or node ID number)"
)
parser.add_argument(
"-r",
"--role",
type=int,
choices=range(2),
help="'1' specifies the TX role. '0' specifies the RX role."
)
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
# Radio CE Pin, CSN Pin, SPI Speed
# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
# ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
# Generic:
radio = RF24(22, 0)
################## Linux (BBB,x86,etc) #########################
# See http://nRF24.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
# select your digital input pin that's connected to the IRQ pin on the nRF24L01
IRQ_PIN = 12
# For this example, we'll be using a payload containing
# a string that changes on every transmission. (successful or not)
# Make a couple tuples of payloads & an iterator to traverse them
pl_iterator = [0] # use a 1-item list instead of python's global keyword
tx_payloads = (b"Ping ", b"Pong ", b"Radio", b"1FAIL")
ack_payloads = (b"Yak ", b"Back", b" ACK")
def interrupt_handler(channel):
"""This function is called when IRQ pin is detected active LOW"""
print("IRQ pin", channel, "went active LOW.")
tx_ds, tx_df, rx_dr = radio.whatHappened() # get IRQ status flags
if tx_df:
radio.flush_tx()
print("\ttx_ds: {}, tx_df: {}, rx_dr: {}".format(tx_ds, tx_df, rx_dr))
if pl_iterator[0] == 0:
print(
" 'data ready' event test {}".format(
"passed" if rx_dr else "failed"
)
)
elif pl_iterator[0] == 1:
print(
" 'data sent' event test {}".format(
"passed" if tx_ds else "failed"
)
)
elif pl_iterator[0] == 3:
print(
" 'data fail' event test {}".format(
"passed" if tx_df else "failed"
)
)
# setup IRQ GPIO pin
GPIO.setmode(GPIO.BCM)
GPIO.setup(IRQ_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(IRQ_PIN, GPIO.FALLING, callback=interrupt_handler)
# IMPORTANT: do not call radio.available() before calling
# radio.whatHappened() when the interruptHandler() is triggered by the
# IRQ pin FALLING event. According to the datasheet, the pipe information
# is unreliable during the IRQ pin FALLING transition.
def _ping_n_wait(pl_iter):
"""private function to ping RX node and wait for IRQ pin to be handled
:param int pl_iter: The index of the buffer in `tx_payloads` tuple to
send. This number is also used to determine if event test was
successful or not.
"""
# set pl_iterator[0] so interrupt_handler() can determine if test was
# successful or not
pl_iterator[0] = pl_iter
# the following False parameter means we're expecting an ACK packet
radio.startFastWrite(tx_payloads[pl_iter], False)
time.sleep(0.1) # wait 100 ms for interrupt_handler() to complete
def print_rx_fifo(pl_size):
"""fush RX FIFO by printing all available payloads with 1 buffer
:param int pl_size: the expected size of each payload
"""
if radio.rxFifoFull():
# all 3 payloads received were 5 bytes each, and RX FIFO is full
# so, fetching 15 bytes from the RX FIFO also flushes RX FIFO
print(
"Complete RX FIFO:",
radio.read(pl_size * 3).decode("utf-8")
)
else:
buffer = bytearray()
while radio.available():
buffer += radio.read(pl_size)
if buffer: # if any payloads were read from the RX FIFO
print("Complete RX FIFO:", buffer.decode("utf-8"))
def master():
"""Transmits 4 times and reports results
1. successfully receive ACK payload first
2. successfully transmit on second
3. send a third payload to fill RX node's RX FIFO
(supposedly making RX node unresponsive)
4. intentionally fail transmit on the fourth
"""
radio.stopListening() # put radio in TX mode
# on data ready test
print("\nConfiguring IRQ pin to only ignore 'on data sent' event")
radio.maskIRQ(True, False, False) # args = tx_ds, tx_df, rx_dr
print(" Pinging slave node for an ACK payload...", end=" ")
_ping_n_wait(0)
# on "data sent" test
print("\nConfiguring IRQ pin to only ignore 'on data ready' event")
radio.maskIRQ(False, False, True) # args = tx_ds, tx_df, rx_dr
print(" Pinging slave node again... ", end=" ")
_ping_n_wait(1)
# trigger slave node to stopListening() by filling slave node's RX FIFO
print("\nSending one extra payload to fill RX FIFO on slave node.")
radio.maskIRQ(1, 1, 1) # disable IRQ pin for this step
if radio.write(tx_payloads[2]):
# when send_only parameter is True, send() ignores RX FIFO usage
if radio.rxFifoFull():
print("RX node's FIFO is full; it is not listening any more")
else:
print(
"Transmission successful, but the RX node might still be "
"listening."
)
else:
radio.flush_tx()
print("Transmission failed or timed out. Continuing anyway.")
# on "data fail" test
print("\nConfiguring IRQ pin to go active for all events.")
radio.maskIRQ(False, False, False) # args = tx_ds, tx_df, rx_dr
print(" Sending a ping to inactive slave node...", end=" ")
_ping_n_wait(3)
# CE pin is still HIGH which consumes more power. Example is now idling so...
radio.stopListening() # ensure CE pin is LOW
# stopListening() also calls flush_tx() when ACK payloads are enabled
print_rx_fifo(len(ack_payloads[0])) # empty RX FIFO
def slave(timeout=6): # will listen for 6 seconds before timing out
"""Only listen for 3 payload from the master node
:param int timeout: The number of seconds to wait (with no transmission)
until exiting function.
"""
pl_iterator[0] = 0 # reset this to indicate event is a 'data_ready' event
# setup radio to recieve pings, fill TX FIFO with ACK payloads
radio.writeAckPayload(1, ack_payloads[0])
radio.writeAckPayload(1, ack_payloads[1])
radio.writeAckPayload(1, ack_payloads[2])
radio.startListening() # start listening & clear status flags
start_timer = time.monotonic() # start timer now
while not radio.rxFifoFull() and time.monotonic() - start_timer < timeout:
# if RX FIFO is not full and timeout is not reached, then keep waiting
pass
time.sleep(0.1) # wait for last ACK payload to transmit
radio.stopListening() # put radio in TX mode & discard any ACK payloads
print_rx_fifo(len(tx_payloads[0]))
def set_role():
"""Set the role using stdin stream. Timeout arg for slave() can be
specified using a space delimiter (e.g. 'R 10' calls `slave(10)`)
:return:
- True when role is complete & app should continue running.
- False when app should exit
"""
user_input = input(
"*** Enter 'R' for receiver role.\n"
"*** Enter 'T' for transmitter role.\n"
"*** Enter 'Q' to quit example.\n"
) or "?"
user_input = user_input.split()
if user_input[0].upper().startswith("R"):
if len(user_input) > 1:
slave(int(user_input[1]))
else:
slave()
return True
elif user_input[0].upper().startswith("T"):
master()
return True
elif user_input[0].upper().startswith("Q"):
radio.powerDown()
return False
else:
print(user_input[0], "is an unrecognized input. Please try again.")
return set_role()
if __name__ == "__main__":
args = parser.parse_args() # parse any CLI args
# initialize the nRF24L01 on the spi bus
if not radio.begin():
raise RuntimeError("radio hardware is not responding")
# For this example, we will use different addresses
# An address need to be a buffer protocol object (bytearray)
address = [b"1Node", b"2Node"]
# It is very helpful to think of an address as a path instead of as
# an identifying device destination
print(sys.argv[0]) # print example name
# to use different addresses on a pair of radios, we need a variable to
# uniquely identify which address this radio will use to transmit
# 0 uses address[0] to transmit, 1 uses address[1] to transmit
radio_number = args.node # uses default value from `parser`
if args.node is None: # if '--node' arg wasn't specified
radio_number = bool(
int(
input(
"Which radio is this? Enter '0' or '1'. Defaults to '0' "
) or 0
)
)
# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity of each other
radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
# ACK payloads are dynamically sized.
radio.enableDynamicPayloads() # to use ACK payloads
# this example uses the ACK payload to trigger the IRQ pin active for
# the "on data received" event
radio.enableAckPayload() # enable ACK payloads
# set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radio_number]) # always uses pipe 0
# set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
# for debugging, we have 2 options that print a large block of details
# (smaller) function that prints raw register values
# radio.printDetails()
# (larger) function that prints human readable data
# radio.printPrettyDetails()
try:
if args.role is None: # if not specified with CLI arg '-r'
while set_role():
pass # continue example until 'Q' is entered
else: # if role was set using CLI args
# run role once and exit
master() if bool(args.role) else slave()
except KeyboardInterrupt:
print(" Keyboard Interrupt detected. Exiting...")
radio.powerDown()
sys.exit()

View File

@ -0,0 +1,259 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/
/**
* A simple example of sending data from 1 nRF24L01 transceiver to another
* with manually transmitted (non-automatic) Acknowledgement (ACK) payloads.
* This example still uses ACK packets, but they have no payloads. Instead the
* acknowledging response is sent with `write()`. This tactic allows for more
* updated acknowledgement payload data, where actual ACK payloads' data are
* outdated by 1 transmission because they have to loaded before receiving a
* transmission.
*
* This example was written to be used on 2 devices acting as "nodes".
* Use `ctrl+c` to quit at any time.
*/
#include <ctime> // time()
#include <iostream> // cin, cout, endl
#include <string> // string, getline()
#include <time.h> // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
#include <RF24/RF24.h> // RF24, RF24_PA_LOW, delay()
using namespace std;
/****************** Linux ***********************/
// Radio CE Pin, CSN Pin, SPI Speed
// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
// ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
// Generic:
RF24 radio(22, 0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.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
// For this example, we'll be using a payload containing
// a string & an integer number that will be incremented
// on every successful transmission.
// Make a data structure to store the entire payload of different datatypes
struct PayloadStruct {
char message[7]; // only using 6 characters for TX & RX payloads
uint8_t counter;
};
PayloadStruct payload;
void setRole(); // prototype to set the node's role
void master(); // prototype of the TX node's behavior
void slave(); // prototype of the RX node's behavior
// custom defined timer for evaluating transmission time in microseconds
struct timespec startTimer, endTimer;
uint32_t getMicros(); // prototype to get ellapsed time in microseconds
int main(int argc, char** argv) {
// perform hardware check
if (!radio.begin()) {
cout << "radio hardware is not responding!!" << endl;
return 0; // quit now
}
// append a NULL terminating 0 for printing as a c-string
payload.message[6] = 0;
// Let these addresses be used for the pair of nodes used in this example
uint8_t address[2][6] = {"1Node", "2Node"};
// the TX address^ , ^the RX address
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
// print example's name
cout << argv[0] << endl;
// Set the radioNumber via the terminal on startup
cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' ";
string input;
getline(cin, input);
radioNumber = input.length() > 0 && (uint8_t)input[0] == 49;
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// save on transmission time by setting the radio to only transmit the
// number of bytes we need to transmit a float
radio.setPayloadSize(sizeof(payload)); // char[7] & uint8_t datatypes occupy 8 bytes
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
// For debugging info
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
// ready to execute program now
setRole(); // calls master() or slave() based on user input
return 0;
} // main
/**
* set this node's role from stdin stream.
* this only considers the first char as input.
*/
void setRole() {
string input = "";
while (!input.length()) {
cout << "*** PRESS 'T' to begin transmitting to the other node\n";
cout << "*** PRESS 'R' to begin receiving from the other node\n";
cout << "*** PRESS 'Q' to exit" << endl;
getline(cin, input);
if (input.length() >= 1) {
if (input[0] == 'T' || input[0] == 't')
master();
else if (input[0] == 'R' || input[0] == 'r')
slave();
else if (input[0] == 'Q' || input[0] == 'q')
break;
else
cout << input[0] << " is an invalid input. Please try again." << endl;
}
input = ""; // stay in the while loop
} // while
} // setRole()
/**
* make this node act as the transmitter
*/
void master() {
memcpy(payload.message, "Hello ", 6); // set the outgoing message
radio.stopListening(); // put in TX mode
unsigned int failures = 0; // keep track of failures
while (failures < 6) {
clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer
bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report
if (report) {
// transmission successful; wait for response and print results
radio.startListening(); // put in RX mode
unsigned long start_timeout = millis(); // timer to detect no response
while (!radio.available()) { // wait for response
if (millis() - start_timeout > 200) // only wait 200 ms
break;
}
unsigned long ellapsedTime = getMicros(); // end the timer
radio.stopListening(); // put back in TX mode
// print summary of transactions
uint8_t pipe;
cout << "Transmission successful! ";
if (radio.available(&pipe)) { // is there a payload received? grab the pipe number that received it
uint8_t bytes = radio.getPayloadSize(); // grab the incoming payload size
cout << "Round trip delay = ";
cout << ellapsedTime; // print the timer result
cout << " us. Sent: " << payload.message; // print outgoing message
cout << (unsigned int)payload.counter; // print outgoing counter
PayloadStruct received;
radio.read(&received, sizeof(received)); // get incoming payload
cout << " Recieved " << (unsigned int)bytes; // print incoming payload size
cout << " on pipe " << (unsigned int)pipe; // print RX pipe number
cout << ": " << received.message; // print the incoming message
cout << (unsigned int)received.counter; // print the incoming counter
cout << endl;
payload.counter = received.counter; // save incoming counter for next outgoing counter
}
else {
cout << "Recieved no response." << endl; // no response received
}
}
else {
cout << "Transmission failed or timed out"; // payload was not delivered
cout << endl;
failures++; // increment failure counter
} // report
// to make this example readable in the terminal
delay(1000); // slow transmissions down by 1 second
} // while
cout << failures << " failures detected. Leaving TX role." << endl;
} // master
/**
* make this node act as the receiver
*/
void slave() {
memcpy(payload.message, "World ", 6); // set the response message
radio.startListening(); // put in RX mode
time_t startTimer = time(nullptr); // start a timer
while (time(nullptr) - startTimer < 6) { // use 6 second timeout
uint8_t pipe;
if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it
uint8_t bytes = radio.getPayloadSize(); // get size of incoming payload
PayloadStruct received;
radio.read(&received, sizeof(received)); // get incoming payload
payload.counter = received.counter + 1; // increment payload for response
// transmit response & save result to `report`
radio.stopListening(); // put in TX mode
radio.writeFast(&payload, sizeof(payload)); // load response into TX FIFO
bool report = radio.txStandBy(150); // keep retrying for 150 ms
radio.startListening(); // put back in RX mode
// print summary of transactions
cout << "Received " << (unsigned int)bytes; // print the size of the payload
cout << " bytes on pipe ";
cout << (unsigned int)pipe; // print the pipe number
cout << ": " << received.message; // print incoming message
cout << (unsigned int)received.counter; // print incoming counter
if (report) {
cout << " Sent: " << payload.message; // print outgoing message
cout << (unsigned int)payload.counter; // print outgoing counter
cout << endl;
}
else {
cout << " Response failed to send." << endl; // failed to send response
}
startTimer = time(nullptr); // reset timer
} // available
} // while
cout << "Nothing received in 6 seconds. Leaving RX role." << endl;
radio.stopListening(); // recommended idle mode is TX mode
} // slave
/**
* Calculate the ellapsed time in microseconds
*/
uint32_t getMicros() {
// this function assumes that the timer was started using
// `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);`
clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer);
uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec;
uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000;
return ((seconds) * 1000 + useconds) + 0.5;
}

View File

@ -0,0 +1,254 @@
"""
A simple example of sending data from 1 nRF24L01 transceiver to another
with manually transmitted (non-automatic) Acknowledgement (ACK) payloads.
This example still uses ACK packets, but they have no payloads. Instead the
acknowledging response is sent with `write()`. This tactic allows for more
updated acknowledgement payload data, where actual ACK payloads' data are
outdated by 1 transmission because they have to loaded before receiving a
transmission.
This example was written to be used on 2 devices acting as 'nodes'.
"""
import sys
import argparse
import time
import struct
from RF24 import RF24, RF24_PA_LOW
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
"-n",
"--node",
type=int,
choices=range(2),
help="the identifying radio number (or node ID number)"
)
parser.add_argument(
"-r",
"--role",
type=int,
choices=range(2),
help="'1' specifies the TX role. '0' specifies the RX role."
)
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
# Radio CE Pin, CSN Pin, SPI Speed
# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
# ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
# Generic:
radio = RF24(22, 0)
################## Linux (BBB,x86,etc) #########################
# See http://nRF24.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
# using the python keyword global is bad practice. Instead we'll use a 1 item
# list to store our integer number for the payloads' counter
counter = [0]
def master():
"""Transmits a message and an incrementing integer every second, then
wait for a response for up to 200 ms.
"""
radio.stopListening() # put radio in TX mode
failures = 0
while failures < 6:
# use bytes() to pack our counter data into the payload
# NOTE b"\x00" byte is a c-string's NULL terminating 0
buffer = b"Hello \x00" + bytes(counter)
start_timer = time.monotonic_ns() # start timer
result = radio.write(buffer)
if not result:
failures += 1
print("Transmission failed or timed out")
else:
radio.startListening() # put radio in RX mode
timout = time.monotonic() * 1000 + 200 # use 200 ms timeout
# declare a variable to save the incoming response
while not radio.available() and time.monotonic() * 1000 < timout:
pass # wait for incoming payload or timeout
radio.stopListening() # put radio in TX mode
end_timer = time.monotonic_ns() # end timer
print(
"Transmission successful. Sent: {}{}.".format(
buffer[:6].decode("utf-8"),
counter[0]
),
end=" "
)
has_payload, pipe_number = radio.available_pipe()
if has_payload:
# grab the incoming payload
received = radio.read(radio.payloadSize)
# NOTE received[7:8] discards NULL terminating 0
counter[0] = received[7:8][0] # save the counter
print(
"Received {} bytes on pipe {}: {}{}. "
"Round-trip delay: {} us.".format(
radio.payloadSize,
pipe_number,
bytes(received[:6]).decode("utf-8"),
counter[0],
(end_timer - start_timer) / 1000
)
)
else:
print("No response received.")
time.sleep(1) # make example readable by slowing down transmissions
print(failures, "failures detected. Leaving TX role.")
def slave(timeout=6):
"""Listen for any payloads and print the transaction
:param int timeout: The number of seconds to wait (with no transmission)
until exiting function.
"""
radio.startListening() # put radio in RX mode
start_timer = time.monotonic() # start a timer to detect timeout
while (time.monotonic() - start_timer) < timeout:
# receive `count` payloads or wait 6 seconds till timing out
has_payload, pipe_number = radio.available_pipe()
if has_payload:
received = radio.read(radio.payloadSize) # fetch the payload
# NOTE received[7:8] discards NULL terminating 0
# increment the counter from received payload
counter[0] = received[7:8][0] + 1 if received[7:8][0] < 255 else 0
# use bytes() to pack our counter data into the payload
# NOTE b"\x00" byte is a c-string's NULL terminating 0
buffer = b"World \x00" + bytes(counter)
radio.stopListening() # put radio in TX mode
radio.writeFast(buffer) # load response into TX FIFO
# keep retrying to send response for 150 milliseconds
result = radio.txStandBy(150) # save response's result
# NOTE txStandBy() flushes TX FIFO on transmission failure
radio.startListening() # put radio back in RX mode
# print the payload received payload
print(
"Received {} bytes on pipe {}: {}{}.".format(
radio.payloadSize,
pipe_number,
bytes(received[:6]).decode("utf-8"),
received[7:8][0]
),
end=" "
)
if result: # did response succeed?
# print response's payload
print(
"Sent: {}{}".format(
buffer[:6].decode("utf-8"),
counter[0]
)
)
else:
print("Response failed or timed out")
start_timer = time.monotonic() # reset the timeout timer
print("Nothing received in 6 seconds. Leaving RX role")
# recommended behavior is to keep in TX mode while idle
radio.stopListening() # put the radio in TX mode
def set_role():
"""Set the role using stdin stream. Timeout arg for slave() can be
specified using a space delimiter (e.g. 'R 10' calls `slave(10)`)
:return:
- True when role is complete & app should continue running.
- False when app should exit
"""
user_input = input(
"*** Enter 'R' for receiver role.\n"
"*** Enter 'T' for transmitter role.\n"
"*** Enter 'Q' to quit example.\n"
) or "?"
user_input = user_input.split()
if user_input[0].upper().startswith("R"):
if len(user_input) > 1:
slave(int(user_input[1]))
else:
slave()
return True
elif user_input[0].upper().startswith("T"):
master()
return True
elif user_input[0].upper().startswith("Q"):
radio.powerDown()
return False
print(user_input[0], "is an unrecognized input. Please try again.")
return set_role()
if __name__ == "__main__":
args = parser.parse_args() # parse any CLI args
# initialize the nRF24L01 on the spi bus
if not radio.begin():
raise RuntimeError("radio hardware is not responding")
# For this example, we will use different addresses
# An address need to be a buffer protocol object (bytearray)
address = [b"1Node", b"2Node"]
# It is very helpful to think of an address as a path instead of as
# an identifying device destination
print(sys.argv[0]) # print example name
# to use different addresses on a pair of radios, we need a variable to
# uniquely identify which address this radio will use to transmit
# 0 uses address[0] to transmit, 1 uses address[1] to transmit
radio_number = args.node # uses default value from `parser`
if args.node is None: # if '--node' arg wasn't specified
radio_number = bool(
int(
input(
"Which radio is this? Enter '0' or '1'. Defaults to '0' "
) or 0
)
)
# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity of each other
radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
# set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radio_number]) # always uses pipe 0
# set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
# To save time during transmission, we'll set the payload size to be only
# what we need. For this example, we'll be using a byte for the
# payload counter and 7 bytes for the payload message
radio.payloadSize = 8
# for debugging, we have 2 options that print a large block of details
# (smaller) function that prints raw register values
# radio.printDetails()
# (larger) function that prints human readable data
# radio.printPrettyDetails()
try:
if args.role is None: # if not specified with CLI arg '-r'
while set_role():
pass # continue example until 'Q' is entered
else: # if role was set using CLI args
# run role once and exit
master() if bool(args.role) else slave()
except KeyboardInterrupt:
print(" Keyboard Interrupt detected. Exiting...")
radio.powerDown()
sys.exit()

View File

@ -0,0 +1,273 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/
/**
* A simple example of sending data from as many as 6 nRF24L01 transceivers to
* 1 receiving transceiver. This technique is trademarked by
* Nordic Semiconductors as "MultiCeiver".
*
* This example was written to be used on up to 6 devices acting as TX nodes &
* only 1 device acting as the RX node (that's a maximum of 7 devices).
* Use `ctrl+c` to quit at any time.
*/
#include <ctime> // time()
#include <cstring> // strcmp()
#include <iostream> // cin, cout, endl
#include <string> // string, getline()
#include <time.h> // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
#include <RF24/RF24.h> // RF24, RF24_PA_LOW, delay()
using namespace std;
/****************** Linux ***********************/
// Radio CE Pin, CSN Pin, SPI Speed
// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
// ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
// Generic:
RF24 radio(22, 0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.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
// For this example, we'll be using 6 addresses; 1 for each TX node
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// Notice that the last byte is the only byte that changes in the last 5
// addresses. This is a limitation of the nRF24L01 transceiver for pipes 2-5
// because they use the same first 4 bytes from pipe 1.
uint64_t address[6] = {0x7878787878LL,
0xB3B4B5B6F1LL,
0xB3B4B5B6CDLL,
0xB3B4B5B6A3LL,
0xB3B4B5B60FLL,
0xB3B4B5B605LL};
// For this example, we'll be using a payload containing
// a node ID number and a single integer number that will be incremented
// on every successful transmission.
// Make a data structure to use as a payload.
struct PayloadStruct
{
unsigned int nodeID;
unsigned int payloadID;
};
PayloadStruct payload;
void setRole(); // prototype to set the node's role
void master(unsigned int); // prototype of a TX node's behavior
void slave(); // prototype of the RX node's behavior
void printHelp(string); // prototype to function that explain CLI arg usage
// custom defined timer for evaluating transmission time in microseconds
struct timespec startTimer, endTimer;
uint32_t getMicros(); // prototype to get ellapsed time in microseconds
int main(int argc, char** argv) {
// perform hardware check
if (!radio.begin()) {
cout << "radio hardware is not responding!!" << endl;
return 0; // quit now
}
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
unsigned int nodeNumber = 'R'; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
bool foundArgNode = false;
if (argc > 1) {
if ((argc - 1) != 2) {
// CLI arg "-n"/"--node" needs an option specified for it
// only 1 arg is expected, so only traverse the first "--arg option" pair
printHelp(string(argv[0]));
return 0;
}
else if (strcmp(argv[1], "-n") == 0 || strcmp(argv[1], "--node") == 0) {
// "-n" or "--node" has been specified
foundArgNode = true;
if ((argv[2][0] - 48) < 6) {
nodeNumber = argv[2][0] - 48;
}
else if (argv[2][0] == 'R' || argv[2][0] == 'r') {
nodeNumber = 'R';
}
else {
printHelp(string(argv[0]));
return 0;
}
}
else {
// "-n"/"--node" arg was not specified
printHelp(string(argv[0]));
return 0;
}
}
// print example's name
cout << argv[0] << endl;
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// save on transmission time by setting the radio to only transmit the
// number of bytes we need to transmit a float
radio.setPayloadSize(sizeof(payload)); // 2x int datatype occupy 8 bytes
// For debugging info
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
// ready to execute program now
if (!foundArgNode) {
setRole(); // calls master() or slave() based on user input
}
else {
nodeNumber < 6 ? master(nodeNumber) : slave();
}
return 0;
}
/**
* set this node's role from stdin stream.
* this only considers the first char as input.
*/
void setRole() {
string input = "";
while (!input.length()) {
cout << "*** Enter a number between 0 and 5 (inclusive) to act as\n";
cout << " a unique node number that transmits to the RX node.\n";
cout << "*** PRESS 'R' to begin receiving from the other nodes\n";
cout << "*** PRESS 'Q' to exit" << endl;
getline(cin, input);
if (input.length() >= 1) {
unsigned int toNumber = (unsigned int)(input[0]) - 48;
if (toNumber < 6 && toNumber >= 0)
master(toNumber);
else if (input[0] == 'R' || input[0] == 'r')
slave();
else if (input[0] == 'Q' || input[0] == 'q')
break;
else
cout << input[0] << " is an invalid input. Please try again." << endl;
}
input = ""; // stay in the while loop
} // while
} // setRole
/**
* act as unique TX node identified by the `role` number
*/
void master(unsigned int role) {
// set the payload's nodeID & reset the payload's identifying number
payload.nodeID = role;
payload.payloadID = 0;
// Set the address on pipe 0 to the RX node.
radio.stopListening(); // put radio in TX mode
radio.openWritingPipe(address[role]);
// According to the datasheet, the auto-retry features's delay value should
// be "skewed" to allow the RX node to receive 1 transmission at a time.
// So, use varying delay between retry attempts and 15 (at most) retry attempts
radio.setRetries(((role * 3) % 12) + 3, 15); // maximum value is 15 for both args
unsigned int failures = 0;
while (failures < 6) {
clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer
bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report
uint32_t timerEllapsed = getMicros(); // end the timer
if (report) {
// payload was delivered
cout << "Transmission of PayloadID ";
cout << payload.payloadID; // print payload number
cout << " as node " << payload.nodeID; // print node number
cout << " successful! Time to transmit = ";
cout << timerEllapsed << " us" << endl; // print the timer result
}
else {
// payload was not delivered
failures++;
cout << "Transmission failed or timed out" << endl;
}
payload.payloadID++; // increment payload number
// to make this example readable in the terminal
delay(500); // slow transmissions down by 0.5 second
} // while
cout << failures << " failures detected. Leaving TX role." << endl;
} // master
/**
* act as the RX node that receives from up to 6 other TX nodes
*/
void slave() {
// Set the addresses for all pipes to TX nodes
for (uint8_t i = 0; i < 6; ++i)
radio.openReadingPipe(i, address[i]);
radio.startListening(); // put radio in RX mode
time_t startTimer = time(nullptr); // start a timer
while (time(nullptr) - startTimer < 6) { // use 6 second timeout
uint8_t pipe;
if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it
uint8_t bytes = radio.getPayloadSize(); // get the size of the payload
radio.read(&payload, bytes); // fetch payload from FIFO
cout << "Received " << (unsigned int)bytes; // print the size of the payload
cout << " bytes on pipe " << (unsigned int)pipe; // print the pipe number
cout << " from node " << payload.nodeID; // print the payload's origin
cout << ". PayloadID: " << payload.payloadID << endl; // print the payload's number
startTimer = time(nullptr); // reset timer
}
}
cout << "Nothing received in 6 seconds. Leaving RX role." << endl;
} // slave
/**
* Calculate the ellapsed time in microseconds
*/
uint32_t getMicros() {
// this function assumes that the timer was started using
// `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);`
clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer);
uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec;
uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000;
return ((seconds) * 1000 + useconds) + 0.5;
}
/**
* print a manual page of instructions on how to use this example's CLI args
*/
void printHelp(string progName) {
cout << "usage: " << progName << " [-h] [-n {0,1,2,3,4,5,r,R}]\n\n"
<< "A simple example of sending data from as many as 6 nRF24L01 transceivers to\n"
<< "1 receiving transceiver. This technique is trademarked by\n"
<< "Nordic Semiconductors as 'MultiCeiver'.\n"
<< "\nThis example was written to be used on up to 6 devices acting as TX nodes with\n"
<< "another device acting as a RX node (that's a total of 7 devices).\n"
<< "\noptional arguments:\n -h, --help\t\tshow this help message and exit\n"
<< " -n {0,1,2,3,4,5,r,R}, --node {0,1,2,3,4,5,r,R}"
<< "\n\t\t\t0-5 specifies the identifying node ID number for the TX role."
<< "\n\t\t\t'r' or 'R' specifies the RX role." << endl;
}

View File

@ -0,0 +1,199 @@
"""
A simple example of sending data from as many as 6 nRF24L01 transceivers to
1 receiving transceiver. This technique is trademarked by
Nordic Semiconductors as "MultiCeiver".
This example was written to be used on up to 6 devices acting as TX nodes &
only 1 device acting as the RX node (that's a maximum of 7 devices).
"""
import sys
import argparse
import time
import struct
from RF24 import RF24, RF24_PA_LOW
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
"-n",
"--node",
choices=("0", "1", "2", "3", "4", "5", "R", "r"),
help="the identifying node ID number for the TX role. "
"Use 'R' or 'r' to specify the RX role"
)
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
# Radio CE Pin, CSN Pin, SPI Speed
# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
# ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
# Generic:
radio = RF24(22, 0)
################## Linux (BBB,x86,etc) #########################
# See http://nRF24.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 the addresses for all transmitting radio nodes
addresses = [
b"\x78" * 5,
b"\xF1\xB6\xB5\xB4\xB3",
b"\xCD\xB6\xB5\xB4\xB3",
b"\xA3\xB6\xB5\xB4\xB3",
b"\x0F\xB6\xB5\xB4\xB3",
b"\x05\xB6\xB5\xB4\xB3"
]
# It is very helpful to think of an address as a path instead of as
# an identifying device destination
def master(node_number):
"""start transmitting to the base station.
:param int node_number: the node's identifying index (from the
the `addresses` list). This is a required parameter
"""
radio.stopListening() # put radio in TX mode
# set the TX address to the address of the base station.
radio.openWritingPipe(addresses[node_number])
counter = 0
failures = 0
while failures < 6:
counter += 1
# payloads will include the node_number and a payload ID character
payload = struct.pack("<ii", node_number, counter)
start_timer = time.monotonic_ns()
report = radio.write(payload)
end_timer = time.monotonic_ns()
# show something to see it isn't frozen
print(
"Transmission of payloadID {} as node {}".format(
counter,
node_number
),
end=" "
)
if report:
print(
"successfull! Time to transmit = {} us".format(
(end_timer - start_timer) / 1000
)
)
else:
failures += 1
print("failed or timed out")
time.sleep(0.5) # slow down the test for readability
print(failures, "failures detected. Leaving TX role.")
def slave(timeout=10):
"""Use the radio as a base station for lisening to all nodes
:param int timeout: The number of seconds to wait (with no transmission)
until exiting function.
"""
# write the addresses to all pipes.
for pipe_n, addr in enumerate(addresses):
radio.openReadingPipe(pipe_n, addr)
radio.startListening() # put radio in RX mode
start_timer = time.monotonic() # start timer
while time.monotonic() - start_timer < timeout:
has_payload, pipe_number = radio.available_pipe()
if has_payload:
# unpack payload
nodeID, payloadID = struct.unpack(
"<ii",
radio.read(radio.payloadSize)
)
# show the pipe number that received the payload
print(
"Received {} bytes on pipe {} from node {}. PayloadID: "
"{}".format(
radio.payloadSize,
pipe_number,
nodeID,
payloadID
)
)
start_timer = time.monotonic() # reset timer with every payload
print("Nothing received in 6 seconds. Leaving RX role")
radio.stopListening()
def set_role():
"""Set the role using stdin stream. Timeout arg for slave() can be
specified using a space delimiter (e.g. 'R 10' calls `slave(10)`)
:return:
- True when role is complete & app should continue running.
- False when app should exit
"""
user_input = input(
"*** Enter 'R' for receiver role.\n"
"*** Enter a number in range [0, 5] to use a specific node ID for "
"transmitter role.\n"
"*** Enter 'Q' to quit example.\n"
) or "?"
user_input = user_input.split()
if user_input[0].upper().startswith("R"):
if len(user_input) > 1:
slave(int(user_input[1]))
else:
slave()
return True
elif user_input[0].isdigit() and 0 <= int(user_input[0]) <= 5:
master(int(user_input[0]))
return True
elif user_input[0].upper().startswith("Q"):
radio.powerDown()
return False
print(user_input[0], "is an unrecognized input. Please try again.")
return set_role()
if __name__ == "__main__":
args = parser.parse_args() # parse any CLI args
# initialize the nRF24L01 on the spi bus
if not radio.begin():
raise RuntimeError("radio hardware is not responding")
print(sys.argv[0]) # print example name
# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity of each other
radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
# To save time during transmission, we'll set the payload size to be only what
# we need.
# 2 int occupy 8 bytes in memory using len(struct.pack())
# "<ii" means 2x little endian unsigned int
radio.payloadSize = len(struct.pack("<ii", 0, 0))
# for debugging, we have 2 options that print a large block of details
# radio.printDetails(); # (smaller) function that prints raw register values
# radio.printPrettyDetails(); # (larger) function that prints human readable data
try:
if args.node is None: # if not specified with CLI arg '-n'
while set_role():
pass # continue example until 'Q' is entered
else: # if role was set using CLI args
# run role once and exit
if args.node.isdigit():
master(int(args.node))
else:
slave()
except KeyboardInterrupt:
print(" Keyboard Interrupt detected. Exiting...")
radio.powerDown()
sys.exit()

View File

@ -0,0 +1,291 @@
/*
* See documentation at https://nRF24.github.io/RF24
* See License information at root directory of this library
* Author: Brendan Doherty (2bndy5)
*/
/**
* A simple example of streaming data from 1 nRF24L01 transceiver to another.
*
* This example was written to be used on 2 devices acting as "nodes".
* Use `ctrl+c` to quit at any time.
*/
#include <cmath> // abs()
#include <ctime> // time()
#include <cstring> // strcmp()
#include <iostream> // cin, cout, endl
#include <string> // string, getline()
#include <time.h> // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
#include <RF24/RF24.h> // RF24, RF24_PA_LOW, delay()
using namespace std;
/****************** Linux ***********************/
// Radio CE Pin, CSN Pin, SPI Speed
// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
// ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
// Generic:
RF24 radio(22, 0);
/****************** Linux (BBB,x86,etc) ***********************/
// See http://nRF24.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
// For this example, we'll be sending 32 payloads each containing
// 32 bytes of data that looks like ASCII art when printed to the serial
// monitor. The TX node and RX node needs only a single 32 byte buffer.
#define SIZE 32 // this is the maximum for this example. (minimum is 1)
char buffer[SIZE + 1]; // for the RX node
unsigned int counter = 0; // for counting the number of received payloads
void makePayload(uint8_t); // prototype to construct a payload dynamically
void setRole(); // prototype to set the node's role
void master(); // prototype of the TX node's behavior
void slave(); // prototype of the RX node's behavior
void printHelp(string); // prototype to function that explain CLI arg usage
// custom defined timer for evaluating transmission time in microseconds
struct timespec startTimer, endTimer;
uint32_t getMicros(); // prototype to get ellapsed time in microseconds
int main(int argc, char** argv) {
// perform hardware check
if (!radio.begin()) {
cout << "radio hardware is not responding!!" << endl;
return 0; // quit now
}
// add a NULL terminating 0 for printing as a c-string
buffer[SIZE] = 0;
// Let these addresses be used for the pair of nodes used in this example
uint8_t address[2][6] = {"1Node", "2Node"};
// the TX address^ , ^the RX address
// It is very helpful to think of an address as a path instead of as
// an identifying device destination
// to use different addresses on a pair of radios, we need a variable to
// uniquely identify which address this radio will use to transmit
bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
bool foundArgNode = false;
bool foundArgRole = false;
bool role = false;
if (argc > 1) {
// CLI args are specified
if ((argc - 1) % 2 != 0) {
// some CLI arg doesn't have an option specified for it
printHelp(string(argv[0])); // all args need an option in this example
return 0;
}
else {
// iterate through args starting after program name
int a = 1;
while (a < argc) {
bool invalidOption = false;
if (strcmp(argv[a], "-n") == 0 || strcmp(argv[a], "--node") == 0) {
// "-n" or "--node" has been specified
foundArgNode = true;
if (argv[a + 1][0] - 48 <= 1) {
radioNumber = (argv[a + 1][0] - 48) == 1;
}
else {
// option is invalid
invalidOption = true;
}
}
else if (strcmp(argv[a], "-r") == 0 || strcmp(argv[a], "--role") == 0) {
// "-r" or "--role" has been specified
foundArgRole = true;
if (argv[a + 1][0] - 48 <= 1) {
role = (argv[a + 1][0] - 48) == 1;
}
else {
// option is invalid
invalidOption = true;
}
}
if (invalidOption) {
printHelp(string(argv[0]));
return 0;
}
a += 2;
} // while
if (!foundArgNode && !foundArgRole) {
// no valid args were specified
printHelp(string(argv[0]));
return 0;
}
} // else
} // if
// print example's name
cout << argv[0] << endl;
if (!foundArgNode) {
// Set the radioNumber via the terminal on startup
cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' ";
string input;
getline(cin, input);
radioNumber = input.length() > 0 && (uint8_t)input[0] == 49;
}
// save on transmission time by setting the radio to only transmit the
// number of bytes we need to transmit a float
radio.setPayloadSize(SIZE); // default value is the maximum 32 bytes
// Set the PA Level low to try preventing power supply related problems
// because these examples are likely run with nodes in close proximity to
// each other.
radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
// set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
// set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
// For debugging info
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
// ready to execute program now
if (!foundArgRole) { // if CLI arg "-r"/"--role" was not specified
setRole(); // calls master() or slave() based on user input
}
else { // if CLI arg "-r"/"--role" was specified
role ? master() : slave(); // based on CLI arg option
}
return 0;
}
/**
* set this node's role from stdin stream.
* this only considers the first char as input.
*/
void setRole() {
string input = "";
while (!input.length()) {
cout << "*** PRESS 'T' to begin transmitting to the other node\n";
cout << "*** PRESS 'R' to begin receiving from the other node\n";
cout << "*** PRESS 'Q' to exit" << endl;
getline(cin, input);
if (input.length() >= 1) {
if (input[0] == 'T' || input[0] == 't')
master();
else if (input[0] == 'R' || input[0] == 'r')
slave();
else if (input[0] == 'Q' || input[0] == 'q')
break;
else
cout << input[0] << " is an invalid input. Please try again." << endl;
}
input = ""; // stay in the while loop
} // while
} // setRole()
/**
* make this node act as the transmitter
*/
void master() {
radio.stopListening(); // put radio in TX mode
unsigned int failures = 0; // keep track of failures
uint8_t i = 0;
clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer
while (i < SIZE) {
makePayload(i);
if (!radio.writeFast(&buffer, SIZE)) {
failures++;
radio.reUseTX();
} else {
i++;
}
if (failures >= 100) {
// most likely no device is listening for the data stream
cout << "Too many failures detected. ";
cout << "Aborting at payload " << buffer[0];
break;
}
} // while
uint32_t ellapsedTime = getMicros(); // end the timer
cout << "Time to transmit data = ";
cout << ellapsedTime; // print the timer result
cout << " us. " << failures; // print number of retries
cout << " failures detected. Leaving TX role." << endl;
} // master
/**
* make this node act as the receiver
*/
void slave() {
counter = 0;
radio.startListening(); // put radio in RX mode
time_t startTimer = time(nullptr); // start a timer
while (time(nullptr) - startTimer < 6) { // use 6 second timeout
if (radio.available()) { // is there a payload
radio.read(&buffer, SIZE); // fetch payload from FIFO
cout << "Received: " << buffer; // print the payload's value
cout << " - " << counter << endl; // print the counter
counter++; // increment counter
startTimer = time(nullptr); // reset timer
}
}
radio.stopListening(); // use TX mode for idle behavior
cout << "Nothing received in 6 seconds. Leaving RX role." << endl;
}
/**
* Make a single payload based on position in stream.
* This example employs this function to save on memory allocated.
*/
void makePayload(uint8_t i) {
// let the first character be an identifying alphanumeric prefix
// this lets us see which payload didn't get received
buffer[0] = i + (i < 26 ? 65 : 71);
for (uint8_t j = 0; j < SIZE - 1; ++j) {
char chr = j >= (SIZE - 1) / 2 + abs((SIZE - 1) / 2 - i);
chr |= j < (SIZE - 1) / 2 - abs((SIZE - 1) / 2 - i);
buffer[j + 1] = chr + 48;
}
}
/**
* Calculate the ellapsed time in microseconds
*/
uint32_t getMicros() {
// this function assumes that the timer was started using
// `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);`
clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer);
uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec;
uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000;
return ((seconds) * 1000 + useconds) + 0.5;
}
/**
* print a manual page of instructions on how to use this example's CLI args
*/
void printHelp(string progName) {
cout << "usage: " << progName << " [-h] [-n {0,1}] [-r {0,1}]\n\n"
<< "A simple example of streaming data from 1 nRF24L01 transceiver to another.\n"
<< "\nThis example was written to be used on 2 devices acting as 'nodes'.\n"
<< "\noptional arguments:\n -h, --help\t\tshow this help message and exit\n"
<< " -n {0,1}, --node {0,1}\n\t\t\tthe identifying radio number\n"
<< " -r {0,1}, --role {0,1}\n\t\t\t'1' specifies the TX role."
<< " '0' specifies the RX role." << endl;
}

View File

@ -0,0 +1,219 @@
"""
A simple example of streaming data from 1 nRF24L01 transceiver to another.
This example was written to be used on 2 devices acting as 'nodes'.
"""
import sys
import argparse
import time
from RF24 import RF24, RF24_PA_LOW
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
"-n",
"--node",
type=int,
choices=range(2),
help="the identifying radio number (or node ID number)"
)
parser.add_argument(
"-r",
"--role",
type=int,
choices=range(2),
help="'1' specifies the TX role. '0' specifies the RX role."
)
########### USER CONFIGURATION ###########
# See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md
# Radio CE Pin, CSN Pin, SPI Speed
# CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use
# their own pin numbering
# CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
# ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
# Generic:
radio = RF24(22, 0)
################## Linux (BBB,x86,etc) #########################
# See http://nRF24.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
# Specify the number of bytes in the payload. This is also used to
# specify the number of payloads in 1 stream of data
SIZE = 32 # this is the default maximum payload size
def make_buffer(buf_iter):
"""Returns a dynamically created payloads
:param int buf_iter: The position of the payload in the data stream
"""
# we'll use `SIZE` for the number of payloads in the list and the
# payloads' length
# prefix payload with a sequential letter to indicate which
# payloads were lost (if any)
buff = bytes([buf_iter + (65 if 0 <= buf_iter < 26 else 71)])
for j in range(SIZE - 1):
char = bool(j >= (SIZE - 1) / 2 + abs((SIZE - 1) / 2 - buf_iter))
char |= bool(j < (SIZE - 1) / 2 - abs((SIZE - 1) / 2 - buf_iter))
buff += bytes([char + 48])
return buff
def master(count=1):
"""Uses all 3 levels of the TX FIFO to send a stream of data
:param int count: how many times to transmit the stream of data.
"""
radio.stopListening() # put radio in TX mode
radio.flush_tx() # clear the TX FIFO so we can use all 3 levels
failures = 0 # keep track of manual retries
start_timer = time.monotonic_ns() # start timer
for multiplier in range(count): # repeat transmit the same data stream
buf_iter = 0 # iterator of payloads for the while loop
while buf_iter < SIZE: # cycle through all the payloads
buffer = make_buffer(buf_iter) # make a payload
if not radio.writeFast(buffer): # transmission failed
failures += 1 # increment manual retry count
if failures > 99 and buf_iter < 7 and multiplier < 2:
# we need to prevent an infinite loop
print(
"Too many failures detected. Aborting at payload ",
buffer[0]
)
multiplier = count # be sure to exit the for loop
break # exit the while loop
radio.reUseTX() # resend payload in top level of TX FIFO
else: # transmission succeeded
buf_iter += 1
end_timer = time.monotonic_ns() # end timer
print(
"Time to transmit data = {} us. Detected {} failures.".format(
(end_timer - start_timer) / 1000,
failures
)
)
def slave(timeout=6):
"""Listen for any payloads and print them out (suffixed with received
counter)
:param int timeout: The number of seconds to wait (with no transmission)
until exiting function.
"""
radio.startListening() # put radio in RX mode
count = 0 # keep track of the number of received payloads
start_timer = time.monotonic() # start timer
while (time.monotonic() - start_timer) < timeout:
if radio.available():
count += 1
# retreive the received packet's payload
receive_payload = radio.read(radio.payloadSize)
print("Received: {} - {}".format(receive_payload, count))
start_timer = time.monotonic() # reset timer on every RX payload
# recommended behavior is to keep in TX mode while idle
radio.stopListening() # put the radio in TX mode
def set_role():
"""Set the role using stdin stream. Role args can be specified using space
delimiters (e.g. 'R 10' calls `slave(10)` & 'T 3' calls `master(3)`)
:return:
- True when role is complete & app should continue running.
- False when app should exit
"""
user_input = input(
"*** Enter 'R' for receiver role.\n"
"*** Enter 'T' for transmitter role.\n"
"*** Enter 'Q' to quit example.\n"
) or "?"
user_input = user_input.split()
if user_input[0].upper().startswith("R"):
if len(user_input) > 1:
slave(int(user_input[1]))
else:
slave()
return True
elif user_input[0].upper().startswith("T"):
if len(user_input) > 1:
master(int(user_input[1]))
else:
master()
return True
elif user_input[0].upper().startswith("Q"):
radio.powerDown()
return False
print(user_input[0], "is an unrecognized input. Please try again.")
return set_role()
if __name__ == "__main__":
args = parser.parse_args() # parse any CLI args
# initialize the nRF24L01 on the spi bus
if not radio.begin():
raise RuntimeError("radio hardware is not responding")
# For this example, we will use different addresses
# An address need to be a buffer protocol object (bytearray)
address = [b"1Node", b"2Node"]
# It is very helpful to think of an address as a path instead of as
# an identifying device destination
print(sys.argv[0]) # print example name
# to use different addresses on a pair of radios, we need a variable to
# uniquely identify which address this radio will use to transmit
# 0 uses address[0] to transmit, 1 uses address[1] to transmit
radio_number = args.node # uses default value from `parser`
if args.node is None: # if '--node' arg wasn't specified
radio_number = bool(
int(
input(
"Which radio is this? Enter '0' or '1'. Defaults to '0' "
) or 0
)
)
# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity of each other
radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default
# set the TX address of the RX node into the TX pipe
radio.openWritingPipe(address[radio_number]) # always uses pipe 0
# set the RX address of the TX node into a RX pipe
radio.openReadingPipe(1, address[not radio_number]) # using pipe 1
# To save time during transmission, we'll set the payload size to be only
# what we need. For this example, we'll be using the default maximum 32
radio.payloadSize = SIZE
# for debugging, we have 2 options that print a large block of details
# (smaller) function that prints raw register values
# radio.printDetails()
# (larger) function that prints human readable data
# radio.printPrettyDetails()
try:
if args.role is None: # if not specified with CLI arg '-r'
while set_role():
pass # continue example until 'Q' is entered
else: # if role was set using CLI args
# run role once and exit
master() if bool(args.role) else slave()
except KeyboardInterrupt:
print(" Keyboard Interrupt detected. Exiting...")
radio.powerDown()
sys.exit()

View File

@ -0,0 +1,59 @@
RF24 KEYWORD1
begin KEYWORD2
isChipConnected KEYWORD2
startListening KEYWORD2
stopListening KEYWORD2
available KEYWORD2
read KEYWORD2
write KEYWORD2
openWritingPipe KEYWORD2
openReadingPipe KEYWORD2
printDetails KEYWORD2
printPrettyDetails KEYWORD2
rxFifoFull KEYWORD2
powerDown KEYWORD2
powerUp KEYWORD2
writeFast KEYWORD2
writeBlocking KEYWORD2
txStandBy KEYWORD2
writeAckPayload KEYWORD2
whatHappened KEYWORD2
startFastWrite KEYWORD2
startWrite KEYWORD2
reUseTX KEYWORD2
flush_tx KEYWORD2
flush_rx KEYWORD2
testCarrier KEYWORD2
testRPD KEYWORD2
isValid KEYWORD2
closeReadingPipe KEYWORD2
failureDetected KEYWORD2
setAddressWidth KEYWORD2
setRetries KEYWORD2
setChannel KEYWORD2
getChannel KEYWORD2
setPayloadSize KEYWORD2
getPayloadSize KEYWORD2
getDynamicPayloadSize KEYWORD2
enableAckPayload KEYWORD2
disableAckPayload KEYWORD2
enableDynamicPayloads KEYWORD2
disableDynamicPayloads KEYWORD2
isPVariant KEYWORD2
setAutoAck KEYWORD2
setPALevel KEYWORD2
getPALevel KEYWORD2
getARC KEYWORD2
setDataRate KEYWORD2
getDataRate KEYWORD2
setCRCLength KEYWORD2
getCRCLength KEYWORD2
disableCRC KEYWORD2
maskIRQ KEYWORD2
txDelay KEYWORD2
csDelay KEYWORD2
startConstCarrier KEYWORD2
stopConstCarrier KEYWORD2
enableDynamicAck KEYWORD2
isAckPayloadAvailable KEYWORD2
printf_begin KEYWORD2

View File

@ -0,0 +1,20 @@
{
"name": "RF24",
"keywords": "rf, radio, wireless, spi",
"description": "Radio driver, OSI layer 2 library for nrf24L01(+) modules.",
"repository": {
"type": "git",
"url": "https://github.com/nRF24/RF24.git"
},
"version": "1.3.11",
"frameworks": "arduino",
"platforms": [
"atmelavr",
"atmelsam",
"teensy",
"atmelmegaavr",
"espressif32",
"espressif8266",
"linux_arm"
]
}

View File

@ -0,0 +1,9 @@
name=RF24
version=1.3.11
author=TMRh20
maintainer=TMRh20,Avamander
sentence=Radio driver, OSI layer 2 library for nrf24L01(+) modules.
paragraph=Core library for nRF24L01(+) communication. Simple to use for beginners, but offers advanced configuration options. Many examples are included to demonstrate various modes of communication.
category=Communication
url=https://nRF24.github.io/RF24/
architectures=*

View File

@ -0,0 +1,128 @@
/*
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 CONT_WAVE 7
#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

View File

@ -0,0 +1,42 @@
/*
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 // defined(__ARDUINO_X86__)
}
#endif // __PRINTF_H__

View File

@ -0,0 +1,70 @@
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,323 @@
#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);
}
void setPALevel_wrap(RF24& ref, rf24_pa_dbm_e level) {
ref.setPALevel(level, 1);
}
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();
#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("disableDynamicPayloads", &RF24::disableDynamicPayloads)
.def("flush_tx", &RF24::flush_tx)
.def("flush_rx", &RF24::flush_rx)
.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("printPrettyDetails", &RF24::printPrettyDetails)
.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("setDataRate", &RF24::setDataRate, (bp::arg("speed")))
.def("setPALevel", &RF24::setPALevel, (bp::arg("level"), bp::arg("lnaEnable")=1))
.def("setPALevel", &setPALevel_wrap, (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("startConstCarrier", &RF24::startConstCarrier, (bp::arg("level"), bp::arg("channel")))
.def("stopConstCarrier",&RF24::stopConstCarrier)
.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("channel", &RF24::getChannel, &RF24::setChannel)
.add_property("payloadSize", &RF24::getPayloadSize, &RF24::setPayloadSize)
.def_readwrite("failureDetected", &RF24::failureDetected);}

View File

@ -0,0 +1,21 @@
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,107 @@
#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,55 @@
#!/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,133 @@
#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,15 @@
#!/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://nRF24.github.io/RF24 for more information

View File

@ -0,0 +1,56 @@
#!/usr/bin/env python
import os
import sys
import setuptools
import crossunixccompiler
version = ""
def process_configparams():
version = "" # using python keyword `global` is bad practice
# NOTE current repo directory structure requires the use of
# `python3 setup.py build` and `python3 setup.py install`
# where `pip3 install ./pyRF24` copies pyRF24 directory to
# `tmp` folder that doesn't have the needed `../Makefile.inc`
# NOTE can't access "../Makefile.inc" from working dir because
# it's relative. Brute force absolute path dynamically.
script_dir = os.path.split(os.path.abspath(os.getcwd()))[0]
abs_file_path = os.path.join(script_dir, "Makefile.inc")
with open(abs_file_path) 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
return version
if sys.version_info >= (3,):
BOOST_LIB = "boost_python3"
else:
BOOST_LIB = "boost_python"
version = 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,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();
radio.enableDynamicPayloads(); // needed for using ACK payloads
//
// 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,272 @@
/*
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,26 @@
#!/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,417 @@
/*
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();
radio.enableDynamicPayloads(); // needed for using ACK payloads
// 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,26 @@
#!/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,53 @@
/*
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 <SPI.h>
#define _SPI SPI
#if !defined(RF24_CSN_SETTLE_LOW_DELAY)
#define RF24_CSN_SETTLE_LOW_DELAY 11
#endif
#if !defined(RF24_CSN_SETTLE_HIGH_DELAY)
#define RF24_CSN_SETTLE_HIGH_DELAY 100
#endif
#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,54 @@
This is a fork from **http://nRF24.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://nRF24.github.io/RF24 for all documentation**

View File

@ -0,0 +1,83 @@
/*
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,64 @@
/*
* 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,49 @@
/*
* 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 */
/*@}*/

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