mirror of
https://github.com/digistump/DigistumpArduino.git
synced 2025-11-01 21:14:50 -07:00
Initial import of support files for all Digistump boards - Digispark, Pro, DigiX - including libraries, examples, tools, and other support files for the Arduino IDE
This commit is contained in:
4
hardware/digistump/sam/libraries/RF24Network/.gitignore
vendored
Normal file
4
hardware/digistump/sam/libraries/RF24Network/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
version.h
|
||||
output/
|
||||
ojam/
|
||||
.*.swp
|
||||
1551
hardware/digistump/sam/libraries/RF24Network/Doxyfile
Normal file
1551
hardware/digistump/sam/libraries/RF24Network/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
210
hardware/digistump/sam/libraries/RF24Network/Jamfile
Normal file
210
hardware/digistump/sam/libraries/RF24Network/Jamfile
Normal file
@@ -0,0 +1,210 @@
|
||||
# (1) Project Information
|
||||
|
||||
PROJECT_LIBS = SPI RF24 RF24Network ;
|
||||
|
||||
# (2) Board Information
|
||||
|
||||
UPLOAD_PROTOCOL ?= stk500v1 ;
|
||||
UPLOAD_SPEED ?= 57600 ;
|
||||
MCU ?= atmega328p ;
|
||||
F_CPU ?= 16000000 ;
|
||||
CORE ?= arduino ;
|
||||
VARIANT ?= standard ;
|
||||
ARDUINO_VERSION ?= 100 ;
|
||||
|
||||
# (3) USB Ports
|
||||
|
||||
PORTS = p4 p6 p9 u0 u1 u2 ;
|
||||
PORT_p6 = /dev/tty.usbserial-A600eHIs ;
|
||||
PORT_p4 = /dev/tty.usbserial-A40081RP ;
|
||||
PORT_p9 = /dev/tty.usbserial-A9007LmI ;
|
||||
PORT_u0 = /dev/ttyUSB0 ;
|
||||
PORT_u1 = /dev/ttyUSB1 ;
|
||||
PORT_u2 = /dev/ttyUSB2 ;
|
||||
|
||||
# (4) Location of AVR tools
|
||||
#
|
||||
# This configuration assumes using avr-tools that were obtained separate from the Arduino
|
||||
# distribution.
|
||||
|
||||
if $(OS) = MACOSX
|
||||
{
|
||||
AVR_BIN = /usr/local/avrtools/bin ;
|
||||
AVR_ETC = /usr/local/avrtools/etc ;
|
||||
AVR_INCLUDE = /usr/local/avrtools/include ;
|
||||
}
|
||||
else
|
||||
{
|
||||
AVR_BIN = /usr/bin ;
|
||||
AVR_INCLUDE = /usr/lib/avr/include ;
|
||||
AVR_ETC = /etc ;
|
||||
}
|
||||
|
||||
# (5) Directories where Arduino core and libraries are located
|
||||
|
||||
ARDUINO_DIR ?= /opt/Arduino ;
|
||||
ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ;
|
||||
ARDUINO_LIB = $(ARDUINO_DIR)/libraries ;
|
||||
SKETCH_LIB = $(HOME)/Source/Arduino/libraries ;
|
||||
|
||||
#
|
||||
# --------------------------------------------------
|
||||
# Below this line usually never needs to be modified
|
||||
#
|
||||
|
||||
# Tool locations
|
||||
|
||||
CC = $(AVR_BIN)/avr-gcc ;
|
||||
C++ = $(AVR_BIN)/avr-g++ ;
|
||||
LINK = $(AVR_BIN)/avr-gcc ;
|
||||
OBJCOPY = $(AVR_BIN)/avr-objcopy ;
|
||||
AVRDUDE = $(AVR_BIN)/avrdude ;
|
||||
|
||||
# Flags
|
||||
|
||||
DEFINES += NODE=$(NODE) F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ;
|
||||
OPTIM = -Os ;
|
||||
CCFLAGS = -Wall -Wextra -mmcu=$(MCU) -ffunction-sections -fdata-sections ;
|
||||
C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ;
|
||||
LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ;
|
||||
AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ;
|
||||
|
||||
# Search everywhere for headers
|
||||
|
||||
HDRS = $(PWD) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ;
|
||||
|
||||
# Output locations
|
||||
|
||||
LOCATE_TARGET = $(F_CPU) ;
|
||||
LOCATE_SOURCE = $(F_CPU) ;
|
||||
|
||||
#
|
||||
# Custom rules
|
||||
#
|
||||
|
||||
rule GitVersion
|
||||
{
|
||||
Always $(<) ;
|
||||
Depends all : $(<) ;
|
||||
}
|
||||
|
||||
actions GitVersion
|
||||
{
|
||||
echo "const char program_version[] = \"\\" > $(<)
|
||||
git log -1 --pretty=format:%h >> $(<)
|
||||
echo "\";" >> $(<)
|
||||
}
|
||||
|
||||
GitVersion version.h ;
|
||||
|
||||
rule Pde
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
MakeLocate $(<) : $(LOCATE_SOURCE) ;
|
||||
Clean clean : $(<) ;
|
||||
}
|
||||
|
||||
if ( $(ARDUINO_VERSION) < 100 )
|
||||
{
|
||||
ARDUINO_H = WProgram.h ;
|
||||
}
|
||||
else
|
||||
{
|
||||
ARDUINO_H = Arduino.h ;
|
||||
}
|
||||
|
||||
actions Pde
|
||||
{
|
||||
echo "#include <$(ARDUINO_H)>" > $(<)
|
||||
echo "#line 1 \"$(>)\"" >> $(<)
|
||||
cat $(>) >> $(<)
|
||||
}
|
||||
|
||||
rule C++Pde
|
||||
{
|
||||
local _CPP = $(>:B).cpp ;
|
||||
Pde $(_CPP) : $(>) ;
|
||||
C++ $(<) : $(_CPP) ;
|
||||
}
|
||||
|
||||
rule UserObject
|
||||
{
|
||||
switch $(>:S)
|
||||
{
|
||||
case .ino : C++Pde $(<) : $(>) ;
|
||||
case .pde : C++Pde $(<) : $(>) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule Objects
|
||||
{
|
||||
local _i ;
|
||||
|
||||
for _i in [ FGristFiles $(<) ]
|
||||
{
|
||||
local _b = $(_i:B)$(SUFOBJ) ;
|
||||
local _o = $(_b:G=$(SOURCE_GRIST:E)) ;
|
||||
Object $(_o) : $(_i) ;
|
||||
Depends obj : $(_o) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule Main
|
||||
{
|
||||
MainFromObjects $(<) : $(>:B)$(SUFOBJ) ;
|
||||
Objects $(>) ;
|
||||
}
|
||||
|
||||
rule Hex
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
MakeLocate $(<) : $(LOCATE_TARGET) ;
|
||||
Depends hex : $(<) ;
|
||||
Clean clean : $(<) ;
|
||||
}
|
||||
|
||||
actions Hex
|
||||
{
|
||||
$(OBJCOPY) -O ihex -R .eeprom $(>) $(<)
|
||||
}
|
||||
|
||||
rule Upload
|
||||
{
|
||||
Depends $(1) : $(2) ;
|
||||
Depends $(2) : $(3) ;
|
||||
NotFile $(1) ;
|
||||
Always $(1) ;
|
||||
Always $(2) ;
|
||||
UploadAction $(2) : $(3) ;
|
||||
}
|
||||
|
||||
actions UploadAction
|
||||
{
|
||||
$(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i
|
||||
}
|
||||
|
||||
#
|
||||
# Targets
|
||||
#
|
||||
|
||||
# Grab everything from the core directory
|
||||
CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ;
|
||||
|
||||
# Grab everything from libraries. To avoid this "grab everything" behaviour, you
|
||||
# can specify specific modules to pick up in PROJECT_MODULES
|
||||
LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ;
|
||||
|
||||
# Grab everything from the current dir
|
||||
PROJECT_MODULES += [ GLOB $(PWD) : *.c *.cpp *.pde *.ino ] ;
|
||||
|
||||
# Main output executable
|
||||
MAIN = $(PWD:B).elf ;
|
||||
|
||||
Main $(MAIN) : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ;
|
||||
Hex $(MAIN:B).hex : $(MAIN) ;
|
||||
|
||||
# Upload targets
|
||||
for _p in $(PORTS)
|
||||
{
|
||||
Upload $(_p) : $(PORT_$(_p)) : $(MAIN:B).hex ;
|
||||
}
|
||||
3
hardware/digistump/sam/libraries/RF24Network/README.md
Normal file
3
hardware/digistump/sam/libraries/RF24Network/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Network Layer for nRF24L01(+) radios
|
||||
|
||||
Please see the full documentation at http://maniacbug.github.com/RF24Network/index.html
|
||||
440
hardware/digistump/sam/libraries/RF24Network/RF24Network.cpp
Normal file
440
hardware/digistump/sam/libraries/RF24Network/RF24Network.cpp
Normal file
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
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 "RF24Network_config.h"
|
||||
#include "RF24.h"
|
||||
#include "RF24Network.h"
|
||||
|
||||
uint16_t RF24NetworkHeader::next_id = 1;
|
||||
|
||||
uint64_t pipe_address( uint16_t node, uint8_t pipe );
|
||||
bool is_valid_address( uint16_t node );
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
RF24Network::RF24Network( RF24& _radio ): radio(_radio), next_frame(frame_queue)
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24Network::begin(uint8_t _channel, uint16_t _node_address )
|
||||
{
|
||||
if (! is_valid_address(_node_address) )
|
||||
return;
|
||||
|
||||
node_address = _node_address;
|
||||
|
||||
// Set up the radio the way we want it to look
|
||||
radio.setChannel(_channel);
|
||||
radio.setDataRate(RF24_1MBPS);
|
||||
radio.setCRCLength(RF24_CRC_16);
|
||||
|
||||
// Setup our address helper cache
|
||||
setup_address();
|
||||
|
||||
// Open up all listening pipes
|
||||
int i = 6;
|
||||
while (i--)
|
||||
radio.openReadingPipe(i,pipe_address(_node_address,i));
|
||||
radio.startListening();
|
||||
|
||||
// Spew debugging state about the radio
|
||||
radio.printDetails();
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24Network::update(void)
|
||||
{
|
||||
// if there is data ready
|
||||
uint8_t pipe_num;
|
||||
while ( radio.available(&pipe_num) )
|
||||
{
|
||||
// Dump the payloads until we've gotten everything
|
||||
boolean done = false;
|
||||
while (!done)
|
||||
{
|
||||
// Fetch the payload, and see if this was the last one.
|
||||
done = radio.read( frame_buffer, sizeof(frame_buffer) );
|
||||
|
||||
// Read the beginning of the frame as the header
|
||||
const RF24NetworkHeader& header = * reinterpret_cast<RF24NetworkHeader*>(frame_buffer);
|
||||
|
||||
IF_SERIAL_DEBUG(printf_P(PSTR("%lu: MAC Received on %u %s\n\r"),millis(),pipe_num,header.toString()));
|
||||
IF_SERIAL_DEBUG(const uint16_t* i = reinterpret_cast<const uint16_t*>(frame_buffer + sizeof(RF24NetworkHeader));printf_P(PSTR("%lu: NET message %04x\n\r"),millis(),*i));
|
||||
|
||||
// Throw it away if it's not a valid address
|
||||
if ( !is_valid_address(header.to_node) )
|
||||
continue;
|
||||
|
||||
// Is this for us?
|
||||
if ( header.to_node == node_address )
|
||||
// Add it to the buffer of frames for us
|
||||
enqueue();
|
||||
else
|
||||
// Relay it
|
||||
write(header.to_node);
|
||||
|
||||
// NOT NEEDED anymore. Now all reading pipes are open to start.
|
||||
#if 0
|
||||
// If this was for us, from one of our children, but on our listening
|
||||
// pipe, it could mean that we are not listening to them. If so, open up
|
||||
// and listen to their talking pipe
|
||||
|
||||
if ( header.to_node == node_address && pipe_num == 0 && is_descendant(header.from_node) )
|
||||
{
|
||||
uint8_t pipe = pipe_to_descendant(header.from_node);
|
||||
radio.openReadingPipe(pipe,pipe_address(node_address,pipe));
|
||||
|
||||
// Also need to open pipe 1 so the system can get the full 5-byte address of the pipe.
|
||||
radio.openReadingPipe(1,pipe_address(node_address,1));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
bool RF24Network::enqueue(void)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
IF_SERIAL_DEBUG(printf_P(PSTR("%lu: NET Enqueue @%x "),millis(),next_frame-frame_queue));
|
||||
|
||||
// Copy the current frame into the frame queue
|
||||
if ( next_frame < frame_queue + sizeof(frame_queue) )
|
||||
{
|
||||
memcpy(next_frame,frame_buffer, frame_size );
|
||||
next_frame += frame_size;
|
||||
|
||||
result = true;
|
||||
IF_SERIAL_DEBUG(printf_P(PSTR("ok\n\r")));
|
||||
}
|
||||
else
|
||||
{
|
||||
IF_SERIAL_DEBUG(printf_P(PSTR("failed\n\r")));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
bool RF24Network::available(void)
|
||||
{
|
||||
// Are there frames on the queue for us?
|
||||
return (next_frame > frame_queue);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint16_t RF24Network::parent() const
|
||||
{
|
||||
if ( node_address == 0 )
|
||||
return -1;
|
||||
else
|
||||
return parent_node;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24Network::peek(RF24NetworkHeader& header)
|
||||
{
|
||||
if ( available() )
|
||||
{
|
||||
// Copy the next available frame from the queue into the provided buffer
|
||||
memcpy(&header,next_frame-frame_size,sizeof(RF24NetworkHeader));
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
size_t RF24Network::read(RF24NetworkHeader& header,void* message, size_t maxlen)
|
||||
{
|
||||
size_t bufsize = 0;
|
||||
|
||||
if ( available() )
|
||||
{
|
||||
// Move the pointer back one in the queue
|
||||
next_frame -= frame_size;
|
||||
uint8_t* frame = next_frame;
|
||||
|
||||
// How much buffer size should we actually copy?
|
||||
bufsize = min(maxlen,frame_size-sizeof(RF24NetworkHeader));
|
||||
|
||||
// Copy the next available frame from the queue into the provided buffer
|
||||
memcpy(&header,frame,sizeof(RF24NetworkHeader));
|
||||
memcpy(message,frame+sizeof(RF24NetworkHeader),bufsize);
|
||||
|
||||
IF_SERIAL_DEBUG(printf_P(PSTR("%lu: NET Received %s\n\r"),millis(),header.toString()));
|
||||
}
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
bool RF24Network::write(RF24NetworkHeader& header,const void* message, size_t len)
|
||||
{
|
||||
// Fill out the header
|
||||
header.from_node = node_address;
|
||||
|
||||
// Build the full frame to send
|
||||
memcpy(frame_buffer,&header,sizeof(RF24NetworkHeader));
|
||||
if (len)
|
||||
memcpy(frame_buffer + sizeof(RF24NetworkHeader),message,min(frame_size-sizeof(RF24NetworkHeader),len));
|
||||
|
||||
IF_SERIAL_DEBUG(printf_P(PSTR("%lu: NET Sending %s\n\r"),millis(),header.toString()));
|
||||
if (len)
|
||||
{
|
||||
IF_SERIAL_DEBUG(const uint16_t* i = reinterpret_cast<const uint16_t*>(message);printf_P(PSTR("%lu: NET message %04x\n\r"),millis(),*i));
|
||||
}
|
||||
|
||||
|
||||
// If the user is trying to send it to himself
|
||||
if ( header.to_node == node_address )
|
||||
// Just queue it in the received queue
|
||||
return enqueue();
|
||||
else
|
||||
// Otherwise send it out over the air
|
||||
return write(header.to_node);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
bool RF24Network::write(uint16_t to_node)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
// Throw it away if it's not a valid address
|
||||
if ( !is_valid_address(to_node) )
|
||||
return false;
|
||||
|
||||
// First, stop listening so we can talk.
|
||||
//radio.stopListening();
|
||||
|
||||
// Where do we send this? By default, to our parent
|
||||
uint16_t send_node = parent_node;
|
||||
// On which pipe
|
||||
uint8_t send_pipe = parent_pipe;
|
||||
|
||||
// If the node is a direct child,
|
||||
if ( is_direct_child(to_node) )
|
||||
{
|
||||
// Send directly
|
||||
send_node = to_node;
|
||||
|
||||
// To its listening pipe
|
||||
send_pipe = 0;
|
||||
}
|
||||
// If the node is a child of a child
|
||||
// talk on our child's listening pipe,
|
||||
// and let the direct child relay it.
|
||||
else if ( is_descendant(to_node) )
|
||||
{
|
||||
send_node = direct_child_route_to(to_node);
|
||||
send_pipe = 0;
|
||||
}
|
||||
|
||||
IF_SERIAL_DEBUG(printf_P(PSTR("%lu: MAC Sending to 0%o via 0%o on pipe %x\n\r"),millis(),to_node,send_node,send_pipe));
|
||||
|
||||
// First, stop listening so we can talk
|
||||
radio.stopListening();
|
||||
|
||||
// Put the frame on the pipe
|
||||
ok = write_to_pipe( send_node, send_pipe );
|
||||
|
||||
// NOT NEEDED anymore. Now all reading pipes are open to start.
|
||||
#if 0
|
||||
// If we are talking on our talking pipe, it's possible that no one is listening.
|
||||
// If this fails, try sending it on our parent's listening pipe. That will wake
|
||||
// it up, and next time it will listen to us.
|
||||
|
||||
if ( !ok && send_node == parent_node )
|
||||
ok = write_to_pipe( parent_node, 0 );
|
||||
#endif
|
||||
|
||||
// Now, continue listening
|
||||
radio.startListening();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
bool RF24Network::write_to_pipe( uint16_t node, uint8_t pipe )
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
uint64_t out_pipe = pipe_address( node, pipe );
|
||||
|
||||
// Open the correct pipe for writing.
|
||||
radio.openWritingPipe(out_pipe);
|
||||
|
||||
// Retry a few times
|
||||
short attempts = 5;
|
||||
do
|
||||
{
|
||||
ok = radio.write( frame_buffer, frame_size );
|
||||
}
|
||||
while ( !ok && --attempts );
|
||||
|
||||
IF_SERIAL_DEBUG(printf_P(PSTR("%lu: MAC Sent on %lx %S\n\r"),millis(),(uint32_t)out_pipe,ok?PSTR("ok"):PSTR("failed")));
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
const char* RF24NetworkHeader::toString(void) const
|
||||
{
|
||||
static char buffer[45];
|
||||
snprintf(buffer,sizeof(buffer),"id %04x from 0%o to 0%o type %c",id,from_node,to_node,type);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
bool RF24Network::is_direct_child( uint16_t node )
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// A direct child of ours has the same low numbers as us, and only
|
||||
// one higher number.
|
||||
//
|
||||
// e.g. node 0234 is a direct child of 034, and node 01234 is a
|
||||
// descendant but not a direct child
|
||||
|
||||
// First, is it even a descendant?
|
||||
if ( is_descendant(node) )
|
||||
{
|
||||
// Does it only have ONE more level than us?
|
||||
uint16_t child_node_mask = ( ~ node_mask ) << 3;
|
||||
result = ( node & child_node_mask ) == 0 ;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
bool RF24Network::is_descendant( uint16_t node )
|
||||
{
|
||||
return ( node & node_mask ) == node_address;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void RF24Network::setup_address(void)
|
||||
{
|
||||
// First, establish the node_mask
|
||||
uint16_t node_mask_check = 0xFFFF;
|
||||
while ( node_address & node_mask_check )
|
||||
node_mask_check <<= 3;
|
||||
|
||||
node_mask = ~ node_mask_check;
|
||||
|
||||
// parent mask is the next level down
|
||||
uint16_t parent_mask = node_mask >> 3;
|
||||
|
||||
// parent node is the part IN the mask
|
||||
parent_node = node_address & parent_mask;
|
||||
|
||||
// parent pipe is the part OUT of the mask
|
||||
uint16_t i = node_address;
|
||||
uint16_t m = parent_mask;
|
||||
while (m)
|
||||
{
|
||||
i >>= 3;
|
||||
m >>= 3;
|
||||
}
|
||||
parent_pipe = i;
|
||||
|
||||
#ifdef SERIAL_DEBUG
|
||||
printf_P(PSTR("setup_address node=0%o mask=0%o parent=0%o pipe=0%o\n\r"),node_address,node_mask,parent_node,parent_pipe);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint16_t RF24Network::direct_child_route_to( uint16_t node )
|
||||
{
|
||||
// Presumes that this is in fact a child!!
|
||||
|
||||
uint16_t child_mask = ( node_mask << 3 ) | 0B111;
|
||||
return node & child_mask ;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint8_t RF24Network::pipe_to_descendant( uint16_t node )
|
||||
{
|
||||
uint16_t i = node;
|
||||
uint16_t m = node_mask;
|
||||
|
||||
while (m)
|
||||
{
|
||||
i >>= 3;
|
||||
m >>= 3;
|
||||
}
|
||||
|
||||
return i & 0B111;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
bool is_valid_address( uint16_t node )
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
while(node)
|
||||
{
|
||||
uint8_t digit = node & 0B111;
|
||||
if (digit < 1 || digit > 5)
|
||||
{
|
||||
result = false;
|
||||
printf_P(PSTR("*** WARNING *** Invalid address 0%o\n\r"),node);
|
||||
break;
|
||||
}
|
||||
node >>= 3;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
uint64_t pipe_address( uint16_t node, uint8_t pipe )
|
||||
{
|
||||
static uint8_t pipe_segment[] = { 0x3c, 0x5a, 0x69, 0x96, 0xa5, 0xc3 };
|
||||
|
||||
uint64_t result;
|
||||
uint8_t* out = reinterpret_cast<uint8_t*>(&result);
|
||||
|
||||
out[0] = pipe_segment[pipe];
|
||||
|
||||
uint8_t w;
|
||||
short i = 4;
|
||||
short shift = 12;
|
||||
while(i--)
|
||||
{
|
||||
w = ( node >> shift ) & 0xF ;
|
||||
w |= ~w << 4;
|
||||
out[i+1] = w;
|
||||
|
||||
shift -= 4;
|
||||
}
|
||||
|
||||
IF_SERIAL_DEBUG(uint32_t* top = reinterpret_cast<uint32_t*>(out+1);printf_P(PSTR("%lu: NET Pipe %i on node 0%o has address %lx%x\n\r"),millis(),pipe,node,*top,*out));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
350
hardware/digistump/sam/libraries/RF24Network/RF24Network.h
Normal file
350
hardware/digistump/sam/libraries/RF24Network/RF24Network.h
Normal file
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __RF24NETWORK_H__
|
||||
#define __RF24NETWORK_H__
|
||||
|
||||
/**
|
||||
* @file RF24Network.h
|
||||
*
|
||||
* Class declaration for RF24Network
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class RF24;
|
||||
|
||||
/**
|
||||
* Header which is sent with each message
|
||||
*
|
||||
* The frame put over the air consists of this header and a message
|
||||
*/
|
||||
struct RF24NetworkHeader
|
||||
{
|
||||
uint16_t from_node; /**< Logical address where the message was generated */
|
||||
uint16_t to_node; /**< Logical address where the message is going */
|
||||
uint16_t id; /**< Sequential message ID, incremented every message */
|
||||
unsigned char type; /**< Type of the packet. 0-127 are user-defined types, 128-255 are reserved for system */
|
||||
unsigned char reserved; /**< Reserved for future use */
|
||||
|
||||
static uint16_t next_id; /**< The message ID of the next message to be sent */
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* Simply constructs a blank header
|
||||
*/
|
||||
RF24NetworkHeader() {}
|
||||
|
||||
/**
|
||||
* Send constructor
|
||||
*
|
||||
* Use this constructor to create a header and then send a message
|
||||
*
|
||||
* @code
|
||||
* RF24NetworkHeader header(recipient_address,'t');
|
||||
* network.write(header,&message,sizeof(message));
|
||||
* @endcode
|
||||
*
|
||||
* @param _to The logical node address where the message is going
|
||||
* @param _type The type of message which follows. Only 0-127 are allowed for
|
||||
* user messages.
|
||||
*/
|
||||
RF24NetworkHeader(uint16_t _to, unsigned char _type = 0): to_node(_to), id(next_id++), type(_type&0x7f) {}
|
||||
|
||||
/**
|
||||
* Create debugging string
|
||||
*
|
||||
* Useful for debugging. Dumps all members into a single string, using
|
||||
* internal static memory. This memory will get overridden next time
|
||||
* you call the method.
|
||||
*
|
||||
* @return String representation of this object
|
||||
*/
|
||||
const char* toString(void) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Network Layer for RF24 Radios
|
||||
*
|
||||
* This class implements an OSI Network Layer using nRF24L01(+) radios driven
|
||||
* by RF24 library.
|
||||
*/
|
||||
|
||||
class RF24Network
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct the network
|
||||
*
|
||||
* @param _radio The underlying radio driver instance
|
||||
*
|
||||
*/
|
||||
RF24Network( RF24& _radio );
|
||||
|
||||
/**
|
||||
* Bring up the network
|
||||
*
|
||||
* @warning Be sure to 'begin' the radio first.
|
||||
*
|
||||
* @param _channel The RF channel to operate on
|
||||
* @param _node_address The logical address of this node
|
||||
*/
|
||||
void begin(uint8_t _channel, uint16_t _node_address );
|
||||
|
||||
/**
|
||||
* Main layer loop
|
||||
*
|
||||
* This function must be called regularly to keep the layer going. This is where all
|
||||
* the action happens!
|
||||
*/
|
||||
void update(void);
|
||||
|
||||
/**
|
||||
* Test whether there is a message available for this node
|
||||
*
|
||||
* @return Whether there is a message available for this node
|
||||
*/
|
||||
bool available(void);
|
||||
|
||||
/**
|
||||
* Read the next available header
|
||||
*
|
||||
* Reads the next available header without advancing to the next
|
||||
* incoming message. Useful for doing a switch on the message type
|
||||
*
|
||||
* If there is no message available, the header is not touched
|
||||
*
|
||||
* @param[out] header The header (envelope) of the next message
|
||||
*/
|
||||
void peek(RF24NetworkHeader& header);
|
||||
|
||||
/**
|
||||
* Read a message
|
||||
*
|
||||
* @param[out] header The header (envelope) of this message
|
||||
* @param[out] message Pointer to memory where the message should be placed
|
||||
* @param maxlen The largest message size which can be held in @p message
|
||||
* @return The total number of bytes copied into @p message
|
||||
*/
|
||||
size_t read(RF24NetworkHeader& header, void* message, size_t maxlen);
|
||||
|
||||
/**
|
||||
* Send a message
|
||||
*
|
||||
* @param[in,out] header The header (envelope) of this message. The critical
|
||||
* thing to fill in is the @p to_node field so we know where to send the
|
||||
* message. It is then updated with the details of the actual header sent.
|
||||
* @param message Pointer to memory where the message is located
|
||||
* @param len The size of the message
|
||||
* @return Whether the message was successfully received
|
||||
*/
|
||||
bool write(RF24NetworkHeader& header,const void* message, size_t len);
|
||||
|
||||
/**
|
||||
* This node's parent address
|
||||
*
|
||||
* @return This node's parent address, or -1 if this is the base
|
||||
*/
|
||||
uint16_t parent() const;
|
||||
|
||||
protected:
|
||||
void open_pipes(void);
|
||||
uint16_t find_node( uint16_t current_node, uint16_t target_node );
|
||||
bool write(uint16_t);
|
||||
bool write_to_pipe( uint16_t node, uint8_t pipe );
|
||||
bool enqueue(void);
|
||||
|
||||
bool is_direct_child( uint16_t node );
|
||||
bool is_descendant( uint16_t node );
|
||||
uint16_t direct_child_route_to( uint16_t node );
|
||||
uint8_t pipe_to_descendant( uint16_t node );
|
||||
void setup_address(void);
|
||||
|
||||
private:
|
||||
RF24& radio; /**< Underlying radio driver, provides link/physical layers */
|
||||
uint16_t node_address; /**< Logical node address of this unit, 1 .. UINT_MAX */
|
||||
const static int frame_size = 32; /**< How large is each frame over the air */
|
||||
uint8_t frame_buffer[frame_size]; /**< Space to put the frame that will be sent/received over the air */
|
||||
uint8_t frame_queue[5*frame_size]; /**< Space for a small set of frames that need to be delivered to the app layer */
|
||||
uint8_t* next_frame; /**< Pointer into the @p frame_queue where we should place the next received frame */
|
||||
|
||||
uint16_t parent_node; /**< Our parent's node address */
|
||||
uint8_t parent_pipe; /**< The pipe our parent uses to listen to us */
|
||||
uint16_t node_mask; /**< The bits which contain signfificant node address information */
|
||||
};
|
||||
|
||||
/**
|
||||
* @example helloworld_tx.pde
|
||||
*
|
||||
* Simplest possible example of using RF24Network. Put this sketch
|
||||
* on one node, and helloworld_rx.pde on the other. Tx will send
|
||||
* Rx a nice message every 2 seconds which rx will print out for us.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example helloworld_rx.pde
|
||||
*
|
||||
* Simplest possible example of using RF24Network. Put this sketch
|
||||
* on one node, and helloworld_tx.pde on the other. Tx will send
|
||||
* Rx a nice message every 2 seconds which rx will print out for us.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example meshping.pde
|
||||
*
|
||||
* Example of pinging across a mesh network
|
||||
* Using this sketch, each node will send a ping to the base every
|
||||
* few seconds. The RF24Network library will route the message across
|
||||
* the mesh to the correct node.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example sensornet.pde
|
||||
*
|
||||
* Example of a sensor network.
|
||||
* This sketch demonstrates how to use the RF24Network library to
|
||||
* manage a set of low-power sensor nodes which mostly sleep but
|
||||
* awake regularly to send readings to the base.
|
||||
*/
|
||||
/**
|
||||
* @mainpage Network Layer for RF24 Radios
|
||||
*
|
||||
* This class implements an <a href="http://en.wikipedia.org/wiki/Network_layer">OSI Network Layer</a> using nRF24L01(+) radios driven
|
||||
* by the <a href="http://maniacbug.github.com/RF24/">RF24</a> library.
|
||||
*
|
||||
* @section Purpose Purpose/Goal
|
||||
*
|
||||
* Create an alternative to ZigBee radios for Arduino communication.
|
||||
*
|
||||
* Xbees are excellent little radios, backed up by a mature and robust standard
|
||||
* protocol stack. They are also expensive.
|
||||
*
|
||||
* For many Arduino uses, they seem like overkill. So I am working to build
|
||||
* an alternative using nRF24L01 radios. Modules are available for less than
|
||||
* $6 from many sources. With the RF24Network layer, I hope to cover many
|
||||
* common communication scenarios.
|
||||
*
|
||||
* Please see the @ref Zigbee page for a comparison against the ZigBee protocols
|
||||
*
|
||||
* @section Features Features
|
||||
*
|
||||
* The layer provides:
|
||||
* @li Host Addressing. Each node has a logical address on the local network.
|
||||
* @li Message Forwarding. Messages can be sent from one node to any other, and
|
||||
* this layer will get them there no matter how many hops it takes.
|
||||
* @li Ad-hoc Joining. A node can join a network without any changes to any
|
||||
* existing nodes.
|
||||
*
|
||||
* The layer does not (yet) provide:
|
||||
* @li Fragmentation/reassembly. Ability to send longer messages and put them
|
||||
* all back together before exposing them up to the app.
|
||||
* @li Power-efficient listening. It would be useful for nodes who are listening
|
||||
* to sleep for extended periods of time if they could know that they would miss
|
||||
* no traffic.
|
||||
* @li Dynamic address assignment.
|
||||
*
|
||||
* @section More How to learn more
|
||||
*
|
||||
* @li <a href="http://maniacbug.github.com/RF24/">RF24: Underlying radio driver</a>
|
||||
* @li <a href="classRF24Network.html">RF24Network Class Documentation</a>
|
||||
* @li <a href="https://github.com/maniacbug/RF24Network/">Source Code</a>
|
||||
* @li <a href="https://github.com/maniacbug/RF24Network/archives/master">Downloads Page</a>
|
||||
* @li <a href="examples.html">Examples Page</a>. Start with <a href="helloworld_rx_8pde-example.html">helloworld_rx</a> and <a href="helloworld_tx_8pde-example.html">helloworld_tx</a>.
|
||||
*
|
||||
* @section Topology Topology for Mesh Networks using nRF24L01(+)
|
||||
*
|
||||
* This network layer takes advantage of the fundamental capability of the nRF24L01(+) radio to
|
||||
* listen actively to up to 6 other radios at once. The network is arranged in a
|
||||
* <a href="http://en.wikipedia.org/wiki/Network_Topology#Tree">Tree Topology</a>, where
|
||||
* one node is the base, and all other nodes are children either of that node, or of another.
|
||||
* Unlike a true mesh network, multiple nodes are not connected together, so there is only one
|
||||
* path to any given node.
|
||||
*
|
||||
* @section Octal Octal Addressing
|
||||
*
|
||||
* Each node must be assigned an 15-bit address by the administrator. This address exactly
|
||||
* describes the position of the node within the tree. The address is an octal number. Each
|
||||
* digit in the address represents a position in the tree further from the base.
|
||||
*
|
||||
* @li Node 00 is the base node.
|
||||
* @li Nodes 01-05 are nodes whose parent is the base.
|
||||
* @li Node 021 is the second child of node 01.
|
||||
* @li Node 0321 is the third child of node 021, an so on.
|
||||
* @li The largest node address is 05555, so 3,125 nodes are allowed on a single channel.
|
||||
*
|
||||
* @section Routing How routing is handled
|
||||
*
|
||||
* When sending a message using RF24Network::write(), you fill in the header with the logical
|
||||
* node address. The network layer figures out the right path to find that node, and sends
|
||||
* it through the system until it gets to the right place. This works even if the two nodes
|
||||
* are far separated, as it will send the message down to the base node, and then back out
|
||||
* to the final destination.
|
||||
*
|
||||
* All of this work is handled by the RF24Network::update() method, so be sure to call it
|
||||
* regularly or your network will miss packets.
|
||||
*
|
||||
* @section Startup Starting up a node
|
||||
*
|
||||
* When a node starts up, it only has to contact its parent to establish communication.
|
||||
* No direct connection to the Base node is needed. This is useful in situations where
|
||||
* relay nodes are being used to bridge the distance to the base, so leaf nodes are out
|
||||
* of range of the base.
|
||||
*
|
||||
* @section Directionality Directionality
|
||||
*
|
||||
* By default all nodes are always listening, so messages will quickly reach
|
||||
* their destination.
|
||||
*
|
||||
* You may choose to sleep any nodes which do not have any active children on the network
|
||||
* (i.e. leaf nodes). This is useful in a case where
|
||||
* the leaf nodes are operating on batteries and need to sleep.
|
||||
* This is useful for a sensor network. The leaf nodes can sleep most of the time, and wake
|
||||
* every few minutes to send in a reading. However, messages cannot be sent to these
|
||||
* sleeping nodes.
|
||||
*
|
||||
* In the future, I plan to write a system where messages can still be passed upward from
|
||||
* the base, and get delivered when a sleeping node is ready to receive them. The radio
|
||||
* and underlying driver support 'ack payloads', which will be a handy mechanism for this.
|
||||
*
|
||||
* @page Zigbee Comparison to ZigBee
|
||||
*
|
||||
* This network layer is influenced by the design of ZigBee, but does not implement it
|
||||
* directly.
|
||||
*
|
||||
* @section Advantage Which is better?
|
||||
*
|
||||
* ZigBee is a much more robust, feature-rich set of protocols, with many different vendors
|
||||
* providing compatible chips.
|
||||
*
|
||||
* RF24Network is cheap. While ZigBee radios are well over $20, nRF24L01 modules can be found
|
||||
* for under $6. My personal favorite is
|
||||
* <a href="http://www.mdfly.com/index.php?main_page=product_info&products_id=82">MDFly RF-IS2401</a>.
|
||||
*
|
||||
* @section Contrast Similiarities & Differences
|
||||
*
|
||||
* Here are some comparisons between RF24Network and ZigBee.
|
||||
*
|
||||
* @li Both networks support Star and Tree topologies. Only Zigbee supports a true mesh.
|
||||
* @li In both networks, only leaf nodes can sleep (see @ref NodeNames).
|
||||
* @li ZigBee nodes are configured using AT commands, or a separate Windows application.
|
||||
* RF24 nodes are configured by recompiliing the firmware or writing to EEPROM.
|
||||
*
|
||||
* @section NodeNames Node Naming
|
||||
*
|
||||
* @li Leaf node: A node at the outer edge of the network with no children. ZigBee calls it
|
||||
* an End Device node.
|
||||
* @li Relay node: A node which has both parents and children, and relays messages from one
|
||||
* to the other. ZigBee calls it a Router.
|
||||
* @li Base node. The top of the tree node with no parents, only children. Typically this node
|
||||
* will bridge to another kind of network like Ethernet. ZigBee calls it a Co-ordinator node.
|
||||
*/
|
||||
|
||||
#endif // __RF24NETWORK_H__
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __RF24_CONFIG_H__
|
||||
#define __RF24_CONFIG_H__
|
||||
|
||||
#if ARDUINO < 100
|
||||
#include <WProgram.h>
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// Stuff that is normally provided by Arduino
|
||||
#ifndef ARDUINO
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
extern HardwareSPI SPI;
|
||||
#define _BV(x) (1<<(x))
|
||||
#endif
|
||||
|
||||
// Define _BV for non-Arduino platforms and for Arduino DUE
|
||||
#if ! defined(ARDUINO) || (defined(ARDUINO) && defined(__arm__))
|
||||
#define _BV(x) (1<<(x))
|
||||
#endif
|
||||
|
||||
#undef SERIAL_DEBUG
|
||||
#ifdef SERIAL_DEBUG
|
||||
#define IF_SERIAL_DEBUG(x) ({x;})
|
||||
#else
|
||||
#define IF_SERIAL_DEBUG(x)
|
||||
#endif
|
||||
|
||||
// Avoid spurious warnings
|
||||
// Arduino DUE is arm and uses traditional PROGMEM constructs
|
||||
#if ! defined( NATIVE ) && defined( ARDUINO ) && ! defined(__arm__)
|
||||
#undef PROGMEM
|
||||
#define PROGMEM __attribute__(( section(".progmem.data") ))
|
||||
#undef PSTR
|
||||
#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))
|
||||
#endif
|
||||
|
||||
// Progmem is Arduino-specific
|
||||
// Arduino DUE is arm and does not include avr/pgmspace
|
||||
#if defined(ARDUINO) && ! defined(__arm__)
|
||||
#include <avr/pgmspace.h>
|
||||
#define PRIPSTR "%S"
|
||||
#else
|
||||
#if ! defined(ARDUINO) // This doesn't work on Arduino DUE
|
||||
typedef char const char;
|
||||
#else // Fill in pgm_read_byte that is used, but missing from DUE
|
||||
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
|
||||
#endif
|
||||
|
||||
typedef uint16_t prog_uint16_t;
|
||||
#define PSTR(x) (x)
|
||||
#define printf_P printf
|
||||
#define strlen_P strlen
|
||||
#define PROGMEM
|
||||
#define pgm_read_word(p) (*(p))
|
||||
#define PRIPSTR "%s"
|
||||
#endif
|
||||
|
||||
#endif // __RF24_CONFIG_H__
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
93
hardware/digistump/sam/libraries/RF24Network/Sync.cpp
Normal file
93
hardware/digistump/sam/libraries/RF24Network/Sync.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
#include <stdlib.h>
|
||||
// Framework headers
|
||||
// Library headers
|
||||
#include <RF24Network.h>
|
||||
// Project headers
|
||||
// This component's header
|
||||
#include <Sync.h>
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void Sync::update(void)
|
||||
{
|
||||
// Pump the network
|
||||
network.update();
|
||||
|
||||
// Look for changes to the data
|
||||
uint8_t message[32];
|
||||
uint8_t *mptr = message;
|
||||
unsigned at = 0;
|
||||
while ( at < len )
|
||||
{
|
||||
if ( app_data && internal_data && app_data[at] != internal_data[at] )
|
||||
{
|
||||
// Compose a message with the deltas
|
||||
*mptr++ = at + 1;
|
||||
*mptr++ = app_data[at];
|
||||
|
||||
// Update our internal view
|
||||
internal_data[at] = app_data[at];
|
||||
}
|
||||
++at;
|
||||
}
|
||||
// Zero out the remainder
|
||||
while ( at++ < sizeof(message) )
|
||||
*mptr++ = 0;
|
||||
|
||||
// If changes, send a message
|
||||
if ( *message )
|
||||
{
|
||||
// TODO handle the case where this has to be broken into
|
||||
// multiple messages
|
||||
RF24NetworkHeader header(/*to node*/ to_node, /*type*/ 'S' /*Sync*/);
|
||||
network.write(header,message,sizeof(message));
|
||||
}
|
||||
|
||||
// Look for messages from the network
|
||||
// Is there anything ready for us?
|
||||
if ( network.available() )
|
||||
{
|
||||
// If so, take a look at it
|
||||
RF24NetworkHeader header;
|
||||
network.peek(header);
|
||||
|
||||
switch (header.type)
|
||||
{
|
||||
case 'S':
|
||||
IF_SERIAL_DEBUG(printf_P(PSTR("%lu: SYN Received sync message\n\r"),millis()));
|
||||
|
||||
network.read(header,&message,sizeof(message));
|
||||
// Parse the message and update the vars
|
||||
mptr = message;
|
||||
at = 0;
|
||||
while ( mptr < message + sizeof(message) )
|
||||
{
|
||||
// A '0' in the first position means we are done
|
||||
if ( !*mptr )
|
||||
break;
|
||||
uint8_t pos = (*mptr++) - 1;
|
||||
uint8_t val = *mptr++;
|
||||
|
||||
IF_SERIAL_DEBUG(printf_P(PSTR("%lu: SYN Updated position %u to value %u\n\r"),millis(),pos,val));
|
||||
|
||||
app_data[pos] = val;
|
||||
internal_data[pos] = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Leave other messages for the app
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
85
hardware/digistump/sam/libraries/RF24Network/Sync.h
Normal file
85
hardware/digistump/sam/libraries/RF24Network/Sync.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __SYNC_H__
|
||||
#define __SYNC_H__
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
// Framework headers
|
||||
// Library headers
|
||||
#include <RF24Network_config.h>
|
||||
// Project headers
|
||||
|
||||
class RF24Network;
|
||||
|
||||
/**
|
||||
* Synchronizes a shared set of variables between multiple nodes
|
||||
*/
|
||||
|
||||
class Sync
|
||||
{
|
||||
private:
|
||||
RF24Network& network;
|
||||
uint8_t* app_data; /**< Application's copy of the data */
|
||||
uint8_t* internal_data; /**< Our copy of the data */
|
||||
size_t len; /**< Length of the data in bytes */
|
||||
uint16_t to_node; /**< The other node we're syncing with */
|
||||
|
||||
protected:
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param _network Which network to syncrhonize over
|
||||
*/
|
||||
Sync(RF24Network& _network): network(_network), app_data(NULL),
|
||||
internal_data(NULL), len(0), to_node(0)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Begin the object
|
||||
*
|
||||
* @param _to_node Which node we are syncing with
|
||||
*/
|
||||
void begin(uint16_t _to_node)
|
||||
{
|
||||
to_node = _to_node;
|
||||
}
|
||||
/**
|
||||
* Declare the shared data set
|
||||
*
|
||||
* @param _data Location of shared data to be syncrhonized
|
||||
*/
|
||||
template <class T>
|
||||
void register_me(T& _data)
|
||||
{
|
||||
app_data = reinterpret_cast<uint8_t*>(&_data);
|
||||
len = sizeof(_data);
|
||||
internal_data = reinterpret_cast<uint8_t*>(malloc(len));
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the internal copy of the shared data set
|
||||
*/
|
||||
void reset(void)
|
||||
{
|
||||
memcpy(internal_data,app_data,len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the network and the shared data set
|
||||
*/
|
||||
void update(void);
|
||||
};
|
||||
|
||||
#endif // __SYNC_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,6 @@
|
||||
SubDir TOP libraries RF24Network examples sensornet ;
|
||||
|
||||
LOCATE_SOURCE = $(SUBDIR)/$(PINS) ;
|
||||
LOCATE_TARGET = $(SUBDIR)/$(PINS) ;
|
||||
|
||||
ArduinoWithLibs Main : RF24Network RF24 Tictocs SPI ;
|
||||
4
hardware/digistump/sam/libraries/RF24Network/examples/helloworld_rx/.gitignore
vendored
Normal file
4
hardware/digistump/sam/libraries/RF24Network/examples/helloworld_rx/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
version.h
|
||||
output/
|
||||
ojam/
|
||||
.*.swp
|
||||
@@ -0,0 +1,6 @@
|
||||
SubDir TOP libraries RF24Network examples helloworld_rx ;
|
||||
|
||||
LOCATE_SOURCE = $(SUBDIR)/$(PINS) ;
|
||||
LOCATE_TARGET = $(SUBDIR)/$(PINS) ;
|
||||
|
||||
ArduinoWithLibs Main : RF24Network RF24 Tictocs SPI ;
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright (C) 2012 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simplest possible example of using RF24Network,
|
||||
*
|
||||
* RECEIVER NODE
|
||||
* Listens for messages from the transmitter and prints them out.
|
||||
*/
|
||||
|
||||
#include <RF24Network.h>
|
||||
#include <RF24.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// nRF24L01(+) radio attached using Getting Started board
|
||||
RF24 radio(9,10);
|
||||
|
||||
// Network uses that radio
|
||||
RF24Network network(radio);
|
||||
|
||||
// Address of our node
|
||||
const uint16_t this_node = 0;
|
||||
|
||||
// Address of the other node
|
||||
const uint16_t other_node = 1;
|
||||
|
||||
// Structure of our payload
|
||||
struct payload_t
|
||||
{
|
||||
unsigned long ms;
|
||||
unsigned long counter;
|
||||
};
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(57600);
|
||||
Serial.println("RF24Network/examples/helloworld_rx/");
|
||||
|
||||
SPI.begin();
|
||||
radio.begin();
|
||||
network.begin(/*channel*/ 90, /*node address*/ this_node);
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
// Pump the network regularly
|
||||
network.update();
|
||||
|
||||
// Is there anything ready for us?
|
||||
while ( network.available() )
|
||||
{
|
||||
// If so, grab it and print it out
|
||||
RF24NetworkHeader header;
|
||||
payload_t payload;
|
||||
network.read(header,&payload,sizeof(payload));
|
||||
Serial.print("Received packet #");
|
||||
Serial.print(payload.counter);
|
||||
Serial.print(" at ");
|
||||
Serial.println(payload.ms);
|
||||
}
|
||||
}
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
4
hardware/digistump/sam/libraries/RF24Network/examples/helloworld_tx/.gitignore
vendored
Normal file
4
hardware/digistump/sam/libraries/RF24Network/examples/helloworld_tx/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
version.h
|
||||
output/
|
||||
ojam/
|
||||
.*.swp
|
||||
@@ -0,0 +1,6 @@
|
||||
SubDir TOP libraries RF24Network examples helloworld_tx ;
|
||||
|
||||
LOCATE_SOURCE = $(SUBDIR)/$(PINS) ;
|
||||
LOCATE_TARGET = $(SUBDIR)/$(PINS) ;
|
||||
|
||||
ArduinoWithLibs Main : RF24Network RF24 Tictocs SPI ;
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright (C) 2012 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simplest possible example of using RF24Network
|
||||
*
|
||||
* TRANSMITTER NODE
|
||||
* Every 2 seconds, send a payload to the receiver node.
|
||||
*/
|
||||
|
||||
#include <RF24Network.h>
|
||||
#include <RF24.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// nRF24L01(+) radio attached using Getting Started board
|
||||
RF24 radio(9,10);
|
||||
|
||||
// Network uses that radio
|
||||
RF24Network network(radio);
|
||||
|
||||
// Address of our node
|
||||
const uint16_t this_node = 1;
|
||||
|
||||
// Address of the other node
|
||||
const uint16_t other_node = 0;
|
||||
|
||||
// How often to send 'hello world to the other unit
|
||||
const unsigned long interval = 2000; //ms
|
||||
|
||||
// When did we last send?
|
||||
unsigned long last_sent;
|
||||
|
||||
// How many have we sent already
|
||||
unsigned long packets_sent;
|
||||
|
||||
// Structure of our payload
|
||||
struct payload_t
|
||||
{
|
||||
unsigned long ms;
|
||||
unsigned long counter;
|
||||
};
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(57600);
|
||||
Serial.println("RF24Network/examples/helloworld_tx/");
|
||||
|
||||
SPI.begin();
|
||||
radio.begin();
|
||||
network.begin(/*channel*/ 90, /*node address*/ this_node);
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
// Pump the network regularly
|
||||
network.update();
|
||||
|
||||
// If it's time to send a message, send it!
|
||||
unsigned long now = millis();
|
||||
if ( now - last_sent >= interval )
|
||||
{
|
||||
last_sent = now;
|
||||
|
||||
Serial.print("Sending...");
|
||||
payload_t payload = { millis(), packets_sent++ };
|
||||
RF24NetworkHeader header(/*to node*/ other_node);
|
||||
bool ok = network.write(header,&payload,sizeof(payload));
|
||||
if (ok)
|
||||
Serial.println("ok.");
|
||||
else
|
||||
Serial.println("failed.");
|
||||
}
|
||||
}
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,12 @@
|
||||
SubDir TOP ;
|
||||
|
||||
# Set up output directories
|
||||
LOCATE_TARGET = $(SEARCH_SOURCE)/out/$(TOOLSET) ;
|
||||
LOCATE_SOURCE = $(LOCATE_TARGET) ;
|
||||
|
||||
# Pull in local libraries
|
||||
SKETCH_LIBS += RF24Network RF24 ;
|
||||
HDRS += $(HOME)/Source/Arduino/libraries/$(SKETCH_LIBS) ;
|
||||
|
||||
# Main output executable
|
||||
Maple $(SEARCH_SOURCE:B).elf : [ GLOB $(SEARCH_SOURCE) $(HOME)/Source/Arduino/libraries/$(SKETCH_LIBS) : $(MODULE_EXT) ] ;
|
||||
@@ -0,0 +1,237 @@
|
||||
MCU = cortex-m3 ;
|
||||
CHIP = STM32F103ZE ;
|
||||
BOARD = maple_native ;
|
||||
|
||||
#CHIP = at91sam3u4 ;
|
||||
#BOARD = sam3u-ek ;
|
||||
|
||||
if ! $(TOOLSET)
|
||||
{
|
||||
TOOLSET = mix ;
|
||||
Echo "Assuming TOOLSET=mix" ;
|
||||
}
|
||||
else if $(TOOLSET) = cs
|
||||
{
|
||||
TOOLS_PATH = /opt/cs/arm/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
}
|
||||
else if $(TOOLSET) = yagarto
|
||||
{
|
||||
TOOLS_PATH = ~/Source/yagarto-4.6.2/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
}
|
||||
if $(TOOLSET) = yagarto-install
|
||||
{
|
||||
TOOLS_PATH = ~/Source/yagarto/install/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
}
|
||||
else if $(TOOLSET) = devkit
|
||||
{
|
||||
TOOLS_PATH = /opt/devkitARM/bin ;
|
||||
TOOLS_ARCH = arm-eabi- ;
|
||||
}
|
||||
else if $(TOOLSET) = maple
|
||||
{
|
||||
TOOLS_PATH = /opt/Maple/Resources/Java/hardware/tools/arm/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
LINK_DIR = /opt/Maple/Resources/Java/hardware/leaflabs/cores/maple ;
|
||||
MAPLE_DIR = /opt/Maple/Resources/Java/hardware/leaflabs/cores/maple ;
|
||||
MAPLE_SUBDIRS = . ;
|
||||
}
|
||||
else if $(TOOLSET) = mix
|
||||
{
|
||||
TOOLS_PATH = /opt/Maple/Resources/Java/hardware/tools/arm/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
LINKFLAGS += --print-gc-sections ;
|
||||
}
|
||||
else if $(TOOLSET) = ports
|
||||
{
|
||||
TOOLS_PATH = /opt/local/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
}
|
||||
|
||||
# Tool locations
|
||||
|
||||
CC = $(TOOLS_PATH)/$(TOOLS_ARCH)gcc ;
|
||||
C++ = $(TOOLS_PATH)/$(TOOLS_ARCH)g++ ;
|
||||
AS = $(TOOLS_PATH)/$(TOOLS_ARCH)gcc -c ;
|
||||
LINK = $(TOOLS_PATH)/$(TOOLS_ARCH)g++ ;
|
||||
OBJCOPY = $(TOOLS_PATH)/$(TOOLS_ARCH)objcopy ;
|
||||
DFU = dfu-util ;
|
||||
|
||||
# Flags
|
||||
|
||||
DEFINES += VECT_TAB_FLASH BOARD_$(BOARD) MCU_$(CHIP) ERROR_LED_PORT=GPIOC ERROR_LED_PIN=15 STM32_HIGH_DENSITY MAPLE_IDE ;
|
||||
OPTIM = -Os ;
|
||||
MFLAGS = cpu=$(MCU) thumb arch=armv7-m ;
|
||||
CCFLAGS = -Wall -m$(MFLAGS) -g -nostdlib -ffunction-sections -fdata-sections -Wl,--gc-sections ;
|
||||
C++FLAGS = $(CCFLAGS) -fno-rtti -fno-exceptions ;
|
||||
LINKFLAGS += -m$(MFLAGS) -Xlinker --gc-sections ;
|
||||
DFUFLAGS = -a1 -d 0x1eaf:0x0003 -R ;
|
||||
|
||||
# Directories
|
||||
|
||||
MAPLE_DIR ?= /opt/libmaple ;
|
||||
MAPLE_LIBS = Servo LiquidCrystal Wire FreeRTOS ;
|
||||
MAPLE_SUBDIRS ?= libmaple libmaple/usb libmaple/usb/usb_lib wirish wirish/comm wirish/boards ;
|
||||
|
||||
SKETCH_DIR = $(HOME)/Source/Maple ;
|
||||
|
||||
CORE_DIRS = $(MAPLE_DIR)/$(MAPLE_SUBDIRS) $(MAPLE_DIR)/libraries/$(MAPLE_LIBS) ;
|
||||
HDRS = $(CORE_DIRS) ;
|
||||
|
||||
# Modules
|
||||
MODULE_EXT = *.c *.cpp *.S *.pde *.ino *.test ;
|
||||
CORE_MODULES = [ GLOB $(CORE_DIRS) : $(MODULE_EXT) ] ;
|
||||
|
||||
# Unit test framework
|
||||
CXXTEST_DIR = $(HOME)/Source/cxxtest ;
|
||||
#CXXTEST_GEN = $(CXXTEST_DIR)/cxxtestgen.py ;
|
||||
CXXTEST_GEN = $(CXXTEST_DIR)/python/scripts/cxxtestgen ;
|
||||
HDRS += $(CXXTEST_DIR) ;
|
||||
|
||||
# Linker script
|
||||
LINK_DIR ?= $(MAPLE_DIR)/support/ld ;
|
||||
LINKSCRIPT = $(LINK_DIR)/$(BOARD)/flash.ld ;
|
||||
LINKFLAGS += -T$(LINKSCRIPT) -L$(LINK_DIR) ;
|
||||
|
||||
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 TestSuite
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
MakeLocate $(<) : $(LOCATE_SOURCE) ;
|
||||
Clean clean : $(<) ;
|
||||
}
|
||||
|
||||
actions TestSuite
|
||||
{
|
||||
$(CXXTEST_GEN) --part $(>) > $(<)
|
||||
}
|
||||
|
||||
rule TestRoot
|
||||
{
|
||||
MakeLocate $(<) : $(LOCATE_SOURCE) ;
|
||||
}
|
||||
|
||||
actions TestRoot
|
||||
{
|
||||
$(CXXTEST_GEN) --root --error-printer > $(<)
|
||||
}
|
||||
|
||||
rule C++TestSuite
|
||||
{
|
||||
local _CPP = $(>:B).cpp ;
|
||||
TestSuite $(_CPP) : $(>) ;
|
||||
C++ $(<) : $(_CPP) ;
|
||||
}
|
||||
|
||||
rule Hex
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
MakeLocate $(<) : $(LOCATE_TARGET) ;
|
||||
Depends hex : $(<) ;
|
||||
Clean clean : $(<) ;
|
||||
}
|
||||
|
||||
actions Hex
|
||||
{
|
||||
$(OBJCOPY) -O ihex $(>) $(<)
|
||||
}
|
||||
|
||||
rule Binary
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
MakeLocate $(<) : $(LOCATE_TARGET) ;
|
||||
Depends binary : $(<) ;
|
||||
Clean clean : $(<) ;
|
||||
}
|
||||
|
||||
actions Binary
|
||||
{
|
||||
$(OBJCOPY) -O binary $(>) $(<)
|
||||
}
|
||||
|
||||
rule UserObject
|
||||
{
|
||||
switch $(>:S)
|
||||
{
|
||||
case .S : As $(<) : $(>) ;
|
||||
case .ino : C++Pde $(<) : $(>) ;
|
||||
case .pde : C++Pde $(<) : $(>) ;
|
||||
case .test : C++TestSuite $(<) : $(>) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule Upload
|
||||
{
|
||||
Depends up : $(<) ;
|
||||
NotFile up ;
|
||||
Always $(<) ;
|
||||
Always up ;
|
||||
}
|
||||
|
||||
actions Upload
|
||||
{
|
||||
$(DFU) $(DFUFLAGS) -D $(<)
|
||||
}
|
||||
|
||||
# Override base objects rule, so all output can go in the output dir
|
||||
rule Objects
|
||||
{
|
||||
local _i ;
|
||||
|
||||
for _i in [ FGristFiles $(<) ]
|
||||
{
|
||||
local _b = $(_i:B)$(SUFOBJ) ;
|
||||
local _o = $(_b:G=$(SOURCE_GRIST:E)) ;
|
||||
Object $(_o) : $(_i) ;
|
||||
Depends obj : $(_o) ;
|
||||
}
|
||||
}
|
||||
|
||||
# Override base main rule, so all output can go in the output dir
|
||||
rule Main
|
||||
{
|
||||
# Bring in the map
|
||||
LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ;
|
||||
|
||||
MakeLocate $(<) ;
|
||||
MainFromObjects $(<) : $(>:B)$(SUFOBJ) ;
|
||||
Objects $(>) ;
|
||||
}
|
||||
|
||||
rule Maple
|
||||
{
|
||||
Main $(<) : $(>) $(CORE_MODULES) ;
|
||||
Binary $(<:B).bin : $(<) ;
|
||||
Upload $(<:B).bin ;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simplest possible example of using RF24Network
|
||||
*
|
||||
* TRANSMITTER NODE
|
||||
* Every 2 seconds, says hello to the receiver node.
|
||||
*/
|
||||
|
||||
#include <RF24Network.h>
|
||||
#include <RF24.h>
|
||||
#include <SPI.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);
|
||||
|
||||
inline void serial_begin(int _baud)
|
||||
{
|
||||
}
|
||||
#else
|
||||
inline void serial_begin(int _baud)
|
||||
{
|
||||
Serial.begin(_baud);
|
||||
}
|
||||
#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);
|
||||
|
||||
// Network uses that radio
|
||||
RF24Network network(radio);
|
||||
|
||||
// Address of our node
|
||||
const uint16_t this_node = 1;
|
||||
|
||||
// Address of the other node
|
||||
const uint16_t other_node = 0;
|
||||
|
||||
// How often to send 'hello world to the other unit
|
||||
const unsigned long interval = 2000; //ms
|
||||
|
||||
// When did we last send?
|
||||
unsigned long last_sent;
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
serial_begin(57600);
|
||||
board_start("RF24Network/examples/helloworld_tx/");
|
||||
|
||||
SPI.begin();
|
||||
radio.begin();
|
||||
network.begin(/*channel*/ 90, /*node address*/ this_node);
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
// Pump the network regularly
|
||||
network.update();
|
||||
|
||||
// If it's time to send a message, send it!
|
||||
unsigned long now = millis();
|
||||
if ( now - last_sent > interval )
|
||||
{
|
||||
last_sent = now;
|
||||
|
||||
toggleLED();
|
||||
printf("Sending...\r\n");
|
||||
const char* hello = "Hello, world!";
|
||||
RF24NetworkHeader header(/*to node*/ other_node);
|
||||
bool ok = network.write(header,hello,strlen(hello));
|
||||
if (ok)
|
||||
printf("\tok.\r\n");
|
||||
else
|
||||
{
|
||||
printf("\tfailed.\r\n");
|
||||
delay(250); // extra delay on fail to keep light on longer
|
||||
}
|
||||
toggleLED();
|
||||
}
|
||||
}
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,77 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
__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
|
||||
4
hardware/digistump/sam/libraries/RF24Network/examples/meshping/.gitignore
vendored
Normal file
4
hardware/digistump/sam/libraries/RF24Network/examples/meshping/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
version.h
|
||||
output/
|
||||
ojam/
|
||||
.*.swp
|
||||
@@ -0,0 +1,6 @@
|
||||
SubDir TOP libraries RF24Network examples meshping ;
|
||||
|
||||
LOCATE_SOURCE = $(SUBDIR)/$(PINS) ;
|
||||
LOCATE_TARGET = $(SUBDIR)/$(PINS) ;
|
||||
|
||||
ArduinoWithLibs Main : RF24Network RF24 Tictocs SPI ;
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
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 of pinging across a mesh network
|
||||
*
|
||||
* Using this sketch, each node will send a ping to every other node
|
||||
* in the network every few seconds.
|
||||
* The RF24Network library will route the message across
|
||||
* the mesh to the correct node.
|
||||
*
|
||||
* This sketch is greatly complicated by the fact that at startup time, each
|
||||
* node (including the base) has no clue what nodes are alive. So,
|
||||
* each node builds an array of nodes it has heard about. The base
|
||||
* periodically sends out its whole known list of nodes to everyone.
|
||||
*
|
||||
* To see the underlying frames being relayed, compile RF24Network with
|
||||
* #define SERIAL_DEBUG.
|
||||
*
|
||||
* The logical node address of each node is set in EEPROM. The nodeconfig
|
||||
* module handles this by listening for a digit (0-9) on the serial port,
|
||||
* and writing that number to EEPROM.
|
||||
*
|
||||
* To use the sketch, upload it to two or more units. Run each one in
|
||||
* turn. Attach a serial monitor, and send a single-digit address to
|
||||
* each. Make the first one '0', and the following units '1', '2', etc.
|
||||
*/
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <RF24Network.h>
|
||||
#include <RF24.h>
|
||||
#include <SPI.h>
|
||||
#include "nodeconfig.h"
|
||||
#include "printf.h"
|
||||
|
||||
// This is for git version tracking. Safe to ignore
|
||||
#ifdef VERSION_H
|
||||
#include "version.h"
|
||||
#else
|
||||
#define __TAG__ "Unknown"
|
||||
#endif
|
||||
|
||||
// nRF24L01(+) radio using the Getting Started board
|
||||
RF24 radio(9,10);
|
||||
RF24Network network(radio);
|
||||
|
||||
// Our node address
|
||||
uint16_t this_node;
|
||||
|
||||
// Delay manager to send pings regularly
|
||||
const unsigned long interval = 2000; // ms
|
||||
unsigned long last_time_sent;
|
||||
|
||||
// Array of nodes we are aware of
|
||||
const short max_active_nodes = 10;
|
||||
uint16_t active_nodes[max_active_nodes];
|
||||
short num_active_nodes = 0;
|
||||
short next_ping_node_index = 0;
|
||||
|
||||
// Prototypes for functions to send & handle messages
|
||||
bool send_T(uint16_t to);
|
||||
bool send_N(uint16_t to);
|
||||
void handle_T(RF24NetworkHeader& header);
|
||||
void handle_N(RF24NetworkHeader& header);
|
||||
void add_node(uint16_t node);
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
//
|
||||
// Print preamble
|
||||
//
|
||||
|
||||
Serial.begin(57600);
|
||||
printf_begin();
|
||||
printf_P(PSTR("\n\rRF24Network/examples/meshping/\n\r"));
|
||||
printf_P(PSTR("VERSION: " __TAG__ "\n\r"));
|
||||
|
||||
//
|
||||
// Pull node address out of eeprom
|
||||
//
|
||||
|
||||
// Which node are we?
|
||||
this_node = nodeconfig_read();
|
||||
|
||||
//
|
||||
// Bring up the RF network
|
||||
//
|
||||
|
||||
SPI.begin();
|
||||
radio.begin();
|
||||
network.begin(/*channel*/ 100, /*node address*/ this_node );
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
// Pump the network regularly
|
||||
network.update();
|
||||
|
||||
// Is there anything ready for us?
|
||||
while ( network.available() )
|
||||
{
|
||||
// If so, take a look at it
|
||||
RF24NetworkHeader header;
|
||||
network.peek(header);
|
||||
|
||||
// Dispatch the message to the correct handler.
|
||||
switch (header.type)
|
||||
{
|
||||
case 'T':
|
||||
handle_T(header);
|
||||
break;
|
||||
case 'N':
|
||||
handle_N(header);
|
||||
break;
|
||||
default:
|
||||
printf_P(PSTR("*** WARNING *** Unknown message type %c\n\r"),header.type);
|
||||
network.read(header,0,0);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
// Send a ping to the next node every 'interval' ms
|
||||
unsigned long now = millis();
|
||||
if ( now - last_time_sent >= interval )
|
||||
{
|
||||
last_time_sent = now;
|
||||
|
||||
// Who should we send to?
|
||||
// By default, send to base
|
||||
uint16_t to = 00;
|
||||
|
||||
// Or if we have active nodes,
|
||||
if ( num_active_nodes )
|
||||
{
|
||||
// Send to the next active node
|
||||
to = active_nodes[next_ping_node_index++];
|
||||
|
||||
// Have we rolled over?
|
||||
if ( next_ping_node_index > num_active_nodes )
|
||||
{
|
||||
// Next time start at the beginning
|
||||
next_ping_node_index = 0;
|
||||
|
||||
// This time, send to node 00.
|
||||
to = 00;
|
||||
}
|
||||
}
|
||||
|
||||
bool ok;
|
||||
|
||||
// Normal nodes send a 'T' ping
|
||||
if ( this_node > 00 || to == 00 )
|
||||
ok = send_T(to);
|
||||
|
||||
// Base node sends the current active nodes out
|
||||
else
|
||||
ok = send_N(to);
|
||||
|
||||
// Notify us of the result
|
||||
if (ok)
|
||||
{
|
||||
printf_P(PSTR("%lu: APP Send ok\n\r"),millis());
|
||||
}
|
||||
else
|
||||
{
|
||||
printf_P(PSTR("%lu: APP Send failed\n\r"),millis());
|
||||
|
||||
// Try sending at a different time next time
|
||||
last_time_sent -= 100;
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for a new node address
|
||||
nodeconfig_listen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a 'T' message, the current time
|
||||
*/
|
||||
bool send_T(uint16_t to)
|
||||
{
|
||||
RF24NetworkHeader header(/*to node*/ to, /*type*/ 'T' /*Time*/);
|
||||
|
||||
// The 'T' message that we send is just a ulong, containing the time
|
||||
unsigned long message = millis();
|
||||
printf_P(PSTR("---------------------------------\n\r"));
|
||||
printf_P(PSTR("%lu: APP Sending %lu to 0%o...\n\r"),millis(),message,to);
|
||||
return network.write(header,&message,sizeof(unsigned long));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an 'N' message, the active node list
|
||||
*/
|
||||
bool send_N(uint16_t to)
|
||||
{
|
||||
RF24NetworkHeader header(/*to node*/ to, /*type*/ 'N' /*Time*/);
|
||||
|
||||
printf_P(PSTR("---------------------------------\n\r"));
|
||||
printf_P(PSTR("%lu: APP Sending active nodes to 0%o...\n\r"),millis(),to);
|
||||
return network.write(header,active_nodes,sizeof(active_nodes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a 'T' message
|
||||
*
|
||||
* Add the node to the list of active nodes
|
||||
*/
|
||||
void handle_T(RF24NetworkHeader& header)
|
||||
{
|
||||
// The 'T' message is just a ulong, containing the time
|
||||
unsigned long message;
|
||||
network.read(header,&message,sizeof(unsigned long));
|
||||
printf_P(PSTR("%lu: APP Received %lu from 0%o\n\r"),millis(),message,header.from_node);
|
||||
|
||||
// If this message is from ourselves or the base, don't bother adding it to the active nodes.
|
||||
if ( header.from_node != this_node || header.from_node > 00 )
|
||||
add_node(header.from_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an 'N' message, the active node list
|
||||
*/
|
||||
void handle_N(RF24NetworkHeader& header)
|
||||
{
|
||||
static uint16_t incoming_nodes[max_active_nodes];
|
||||
|
||||
network.read(header,&incoming_nodes,sizeof(incoming_nodes));
|
||||
printf_P(PSTR("%lu: APP Received nodes from 0%o\n\r"),millis(),header.from_node);
|
||||
|
||||
int i = 0;
|
||||
while ( i < max_active_nodes && incoming_nodes[i] > 00 )
|
||||
add_node(incoming_nodes[i++]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a particular node to the current list of active nodes
|
||||
*/
|
||||
void add_node(uint16_t node)
|
||||
{
|
||||
// Do we already know about this node?
|
||||
short i = num_active_nodes;
|
||||
while (i--)
|
||||
{
|
||||
if ( active_nodes[i] == node )
|
||||
break;
|
||||
}
|
||||
// If not, add it to the table
|
||||
if ( i == -1 && num_active_nodes < max_active_nodes )
|
||||
{
|
||||
active_nodes[num_active_nodes++] = node;
|
||||
printf_P(PSTR("%lu: APP Added 0%o to list of active nodes.\n\r"),millis(),node);
|
||||
}
|
||||
}
|
||||
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
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 "RF24Network_config.h"
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "nodeconfig.h"
|
||||
|
||||
// Where in EEPROM is the address stored?
|
||||
uint8_t* address_at_eeprom_location = (uint8_t*)10;
|
||||
|
||||
// What flag value is stored there so we know the value is valid?
|
||||
const uint8_t valid_eeprom_flag = 0xdf;
|
||||
|
||||
// What are the actual node values that we want to use?
|
||||
// EEPROM locations are actually just indices into this array
|
||||
const uint16_t node_address_set[10] = { 00, 02, 05, 012, 015, 022, 025, 032, 035, 045 };
|
||||
|
||||
uint8_t nodeconfig_read(void)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
|
||||
// Look for the token in EEPROM to indicate the following value is
|
||||
// a validly set node address
|
||||
if ( eeprom_read_byte(address_at_eeprom_location) == valid_eeprom_flag )
|
||||
{
|
||||
// Read the address from EEPROM
|
||||
result = node_address_set[ eeprom_read_byte(address_at_eeprom_location+1) ];
|
||||
printf_P(PSTR("ADDRESS: %u\n\r"),result);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf_P(PSTR("*** No valid address found. Send 0-9 via serial to set node address\n\r"));
|
||||
while(1)
|
||||
{
|
||||
nodeconfig_listen();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void nodeconfig_listen(void)
|
||||
{
|
||||
//
|
||||
// Listen for serial input, which is how we set the address
|
||||
//
|
||||
if (Serial.available())
|
||||
{
|
||||
// If the character on serial input is in a valid range...
|
||||
char c = Serial.read();
|
||||
if ( c >= '0' && c <= '9' )
|
||||
{
|
||||
// It is our address
|
||||
eeprom_write_byte(address_at_eeprom_location,valid_eeprom_flag);
|
||||
eeprom_write_byte(address_at_eeprom_location+1,c-'0');
|
||||
|
||||
// And we are done right now (no easy way to soft reset)
|
||||
printf_P(PSTR("\n\rManually reset index to: %c, address 0%o\n\rPress RESET to continue!"),c,node_address_set[c-'0']);
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __NODECONFIG_H__
|
||||
#define __NODECONFIG_H__
|
||||
|
||||
uint8_t nodeconfig_read(void);
|
||||
void nodeconfig_listen(void);
|
||||
|
||||
#endif // __NODECONFIG_H__
|
||||
@@ -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__
|
||||
4
hardware/digistump/sam/libraries/RF24Network/examples/sensornet/.gitignore
vendored
Normal file
4
hardware/digistump/sam/libraries/RF24Network/examples/sensornet/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
version.h
|
||||
output/
|
||||
ojam/
|
||||
.*.swp
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef __DUINODE_V3_H__
|
||||
#define __DUINODE_V3_H__
|
||||
|
||||
/**
|
||||
* @file DuinodeV1.h
|
||||
*
|
||||
* Contains hardware definitions for RF Duinode V1 (3V3)
|
||||
*/
|
||||
|
||||
#define PINS_DEFINED 1
|
||||
#define __PLATFORM__ "RF Duinode V1 (3V3)"
|
||||
|
||||
const int rf_irq = 0;
|
||||
|
||||
const int led_red = 0;
|
||||
const int led_yellow = 0;
|
||||
const int led_green = 0;
|
||||
const int button_a = 0;
|
||||
|
||||
const int rf_ce = 8;
|
||||
const int rf_csn = 9;
|
||||
|
||||
const int temp_pin = 2; // analog
|
||||
const int voltage_pin = 3; // analog
|
||||
|
||||
// 1.1V internal reference after 1M/470k divider, in 8-bit fixed point
|
||||
const unsigned voltage_reference = 0x371;
|
||||
|
||||
#endif // __DUINODE_V3_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef __DUINODE_V3_H__
|
||||
#define __DUINODE_V3_H__
|
||||
|
||||
/**
|
||||
* @file DuinodeV3.h
|
||||
*
|
||||
* Contains hardware definitions for RF Duinode V3 (2V4)
|
||||
*/
|
||||
|
||||
#define PINS_DEFINED 1
|
||||
#define __PLATFORM__ "RF Duinode V3/V4 (2V4)"
|
||||
|
||||
const int rf_irq = 0;
|
||||
|
||||
const int led_red = 3;
|
||||
const int led_yellow = 4;
|
||||
const int led_green = 5;
|
||||
const int button_a = 6;
|
||||
|
||||
const int rf_ce = 8;
|
||||
const int rf_csn = 7;
|
||||
|
||||
const int temp_pin = 2; // analog
|
||||
const int voltage_pin = 3; // analog
|
||||
|
||||
// 1.1V internal reference after 1M/470k divider, in 8-bit fixed point
|
||||
const unsigned voltage_reference = 0x371;
|
||||
|
||||
#endif // __DUINODE_V3_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef __DUINODE_V5_H__
|
||||
#define __DUINODE_V5_H__
|
||||
|
||||
/**
|
||||
* @file DuinodeV3.h
|
||||
*
|
||||
* Contains hardware definitions for RF Duinode V5 (2V4)
|
||||
*/
|
||||
|
||||
#define PINS_DEFINED 1
|
||||
#define __PLATFORM__ "RF Duinode V5 (2V4)"
|
||||
|
||||
const int rf_irq = 0;
|
||||
|
||||
const int led_red = 3;
|
||||
const int led_yellow = 4;
|
||||
const int led_green = 5;
|
||||
const int button_a = 6;
|
||||
|
||||
const int rf_ce = 14;
|
||||
const int rf_csn = 15;
|
||||
|
||||
const int temp_pin = 2; // analog
|
||||
const int voltage_pin = 3; // analog
|
||||
|
||||
// 1.1V internal reference after 1M/470k divider, in 8-bit fixed point
|
||||
const unsigned voltage_reference = 0x371;
|
||||
|
||||
#endif // __DUINODE_V5_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,6 @@
|
||||
SubDir TOP libraries RF24Network examples sensornet ;
|
||||
|
||||
LOCATE_SOURCE = $(SUBDIR)/$(PINS) ;
|
||||
LOCATE_TARGET = $(SUBDIR)/$(PINS) ;
|
||||
|
||||
ArduinoWithLibs Main : RF24Network RF24 Tictocs SPI ;
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
// Framework headers
|
||||
// Library headers
|
||||
#include "RF24Network_config.h"
|
||||
// Project headers
|
||||
// This component's header
|
||||
#include "S_message.h"
|
||||
|
||||
char S_message::buffer[32];
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
char* S_message::toString(void)
|
||||
{
|
||||
snprintf(buffer,sizeof(buffer),"%2u.%02uC /%2u.%02uV",
|
||||
temp_reading >> 8,
|
||||
( temp_reading & 0xFF ) * 100 / 256,
|
||||
voltage_reading >> 8,
|
||||
( voltage_reading & 0xFF ) * 100 / 256
|
||||
);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __S_MESSAGE_H__
|
||||
#define __S_MESSAGE_H__
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
// Framework headers
|
||||
// Library headers
|
||||
// Project headers
|
||||
|
||||
/**
|
||||
* Sensor message (type 'S')
|
||||
*/
|
||||
|
||||
struct S_message
|
||||
{
|
||||
uint16_t temp_reading;
|
||||
uint16_t voltage_reading;
|
||||
static char buffer[];
|
||||
S_message(void): temp_reading(0), voltage_reading(0) {}
|
||||
char* toString(void);
|
||||
};
|
||||
|
||||
#endif // __S_MESSAGE_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1 @@
|
||||
jam F_CPU=16000000 "CCFLAGS=-include DuinodeV1.h" -dx UPLOAD_SPEED=115200 u1 && screen /dev/ttyUSB1 57600
|
||||
@@ -0,0 +1,3 @@
|
||||
AVR_BIN=/usr/local/avr/bin AVR_ETC=/usr/local/avr/etc jam F_CPU=8000000 sensornet.elf
|
||||
touch sensornet.pde
|
||||
AVR_BIN=/usr/local/avr/bin AVR_ETC=/usr/local/avr/etc jam F_CPU=8000000 "CCFLAGS=-include DuinodeV3.h" -dx UPLOAD_SPEED=57600 u1 && screen /dev/ttyUSB1 57600
|
||||
@@ -0,0 +1 @@
|
||||
jam F_CPU=8000000 "CCFLAGS=-include DuinodeV5.h" -dx UPLOAD_SPEED=57600 u0 && picocom -b 57600 /dev/ttyUSB0
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
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 "RF24Network_config.h"
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "nodeconfig.h"
|
||||
|
||||
// Where in EEPROM is the address stored?
|
||||
uint8_t* address_at_eeprom_location = (uint8_t*)10;
|
||||
|
||||
eeprom_info_t eeprom_info;
|
||||
|
||||
const eeprom_info_t& nodeconfig_read(void)
|
||||
{
|
||||
eeprom_read_block(&eeprom_info,address_at_eeprom_location,sizeof(eeprom_info));
|
||||
|
||||
// Look for the token in EEPROM to indicate the following value is
|
||||
// a validly set node address
|
||||
if ( eeprom_info.isValid() )
|
||||
{
|
||||
printf_P(PSTR("ADDRESS: %o\n\r"),eeprom_info.address);
|
||||
printf_P(PSTR("ROLE: %S\n\r"),eeprom_info.relay ? PSTR("Relay") : PSTR("Leaf") );
|
||||
printf_P(PSTR("TEMP: %04x\n\r"),eeprom_info.temp_calibration);
|
||||
}
|
||||
else
|
||||
{
|
||||
eeprom_info.clear();
|
||||
|
||||
printf_P(PSTR("*** No valid address found. Send node address via serial of the form 011<cr>\n\r"));
|
||||
while(1)
|
||||
{
|
||||
nodeconfig_listen();
|
||||
}
|
||||
}
|
||||
|
||||
return eeprom_info;
|
||||
}
|
||||
|
||||
char serialdata[10];
|
||||
char* nextserialat = serialdata;
|
||||
const char* maxserial = serialdata + sizeof(serialdata) - 1;
|
||||
|
||||
void nodeconfig_listen(void)
|
||||
{
|
||||
//
|
||||
// Listen for serial input, which is how we set the address
|
||||
//
|
||||
if (Serial.available())
|
||||
{
|
||||
// If the character on serial input is in a valid range...
|
||||
char c = tolower(Serial.read());
|
||||
if ( (c >= '0' && c <= '9' ) || (c >= 'a' && c <= 'f' ) )
|
||||
{
|
||||
*nextserialat++ = c;
|
||||
if ( nextserialat == maxserial )
|
||||
{
|
||||
*nextserialat = 0;
|
||||
printf_P(PSTR("\r\n*** Unknown serial command: %s\r\n"),serialdata);
|
||||
nextserialat = serialdata;
|
||||
}
|
||||
}
|
||||
else if ( tolower(c) == 'r' )
|
||||
{
|
||||
eeprom_info.relay = true;
|
||||
printf_P(PSTR("ROLE: %S\n\r"),eeprom_info.relay ? PSTR("Relay") : PSTR("Leaf") );
|
||||
eeprom_update_block(&eeprom_info,address_at_eeprom_location,sizeof(eeprom_info));
|
||||
printf_P(PSTR("RESET NODE before changes take effect\r\n"));
|
||||
if ( ! eeprom_info.isValid() )
|
||||
printf_P(PSTR("Please assign an address\r\n"));
|
||||
}
|
||||
else if ( tolower(c) == 'l' )
|
||||
{
|
||||
eeprom_info.relay = false;
|
||||
printf_P(PSTR("ROLE: %S\n\r"),eeprom_info.relay ? PSTR("Relay") : PSTR("Leaf") );
|
||||
eeprom_update_block(&eeprom_info,address_at_eeprom_location,sizeof(eeprom_info));
|
||||
printf_P(PSTR("RESET NODE before changes take effect\r\n"));
|
||||
if ( ! eeprom_info.isValid() )
|
||||
printf_P(PSTR("Please assign an address\r\n"));
|
||||
}
|
||||
else if ( tolower(c) == 't' )
|
||||
{
|
||||
// Send temperature calibration as 2-digit 4.4-fixed decimal signed degrees
|
||||
// celcius--followed by a 't'. So, for -1.5 degrees, send "e8t". Or for +2 degrees
|
||||
// send "20t"
|
||||
|
||||
*nextserialat = 0;
|
||||
int8_t val = strtol(serialdata,NULL,16);
|
||||
nextserialat = serialdata;
|
||||
|
||||
set_temp_calibration( val * 0x10 );
|
||||
|
||||
printf_P(PSTR("RESET NODE before changes take effect\r\n"));
|
||||
if ( ! eeprom_info.isValid() )
|
||||
printf_P(PSTR("Please assign an address\r\n"));
|
||||
}
|
||||
else if ( c == 13 )
|
||||
{
|
||||
// Convert to octal
|
||||
char *pc = serialdata;
|
||||
uint16_t address = 0;
|
||||
while ( pc < nextserialat )
|
||||
{
|
||||
address <<= 3;
|
||||
address |= (*pc++ - '0');
|
||||
}
|
||||
|
||||
// It is our address
|
||||
eeprom_info.address = address;
|
||||
eeprom_update_block(&eeprom_info,address_at_eeprom_location,sizeof(eeprom_info));
|
||||
|
||||
// And we are done right now (no easy way to soft reset)
|
||||
printf_P(PSTR("\n\rManually set to address 0%o\n\rPress RESET to continue!"),address);
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_temp_calibration(int16_t val)
|
||||
{
|
||||
eeprom_info.temp_calibration = val;
|
||||
printf_P(PSTR("TEMP: %02x\n\r"),eeprom_info.temp_calibration);
|
||||
eeprom_update_block(&eeprom_info,address_at_eeprom_location,sizeof(eeprom_info));
|
||||
}
|
||||
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __NODECONFIG_H__
|
||||
#define __NODECONFIG_H__
|
||||
|
||||
// Additional info
|
||||
struct eeprom_info_t
|
||||
{
|
||||
uint8_t flag;
|
||||
uint16_t address;
|
||||
int16_t temp_calibration; // sensor adjustment in signed fixed-8.8 degrees, e.g. 0xFE80 is -1.5
|
||||
bool relay:1;
|
||||
|
||||
static const uint8_t valid_flag = 0xdd;
|
||||
|
||||
eeprom_info_t()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return (flag == valid_flag) && (address != 0xffff);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
flag = valid_flag;
|
||||
address = 0xffff;
|
||||
relay = false;
|
||||
temp_calibration = 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const eeprom_info_t& nodeconfig_read(void);
|
||||
void nodeconfig_listen(void);
|
||||
void set_temp_calibration(int16_t val);
|
||||
|
||||
#endif // __NODECONFIG_H__
|
||||
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file printf.h
|
||||
*
|
||||
* Setup necessary to direct stdout to the Arduino Serial library, which
|
||||
* enables 'printf'
|
||||
*/
|
||||
|
||||
#ifndef __PRINTF_H__
|
||||
#define __PRINTF_H__
|
||||
|
||||
#ifdef ARDUINO
|
||||
|
||||
int serial_putc( char c, FILE * )
|
||||
{
|
||||
Serial.write( c );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void printf_begin(void)
|
||||
{
|
||||
fdevopen( &serial_putc, 0 );
|
||||
}
|
||||
|
||||
#else
|
||||
#error This example is only for use on Arduino.
|
||||
#endif // ARDUINO
|
||||
|
||||
#endif // __PRINTF_H__
|
||||
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
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 of a sensor network
|
||||
*
|
||||
* This sketch demonstrates how to use the RF24Network library to
|
||||
* manage a set of low-power sensor nodes which mostly sleep but
|
||||
* awake regularly to send readings to the base.
|
||||
*
|
||||
* The example uses TWO sensors, a 'temperature' sensor and a 'voltage'
|
||||
* sensor.
|
||||
*
|
||||
* To see the underlying frames being relayed, compile RF24Network with
|
||||
* #define SERIAL_DEBUG.
|
||||
*
|
||||
* The logical node address of each node is set in EEPROM. The nodeconfig
|
||||
* module handles this by listening for a digit (0-9) on the serial port,
|
||||
* and writing that number to EEPROM.
|
||||
*/
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <RF24Network.h>
|
||||
#include <RF24.h>
|
||||
#include <SPI.h>
|
||||
#include <Tictocs.h>
|
||||
#include <Button.h>
|
||||
#include <TictocTimer.h>
|
||||
#include "nodeconfig.h"
|
||||
#include "sleep.h"
|
||||
#include "S_message.h"
|
||||
#include "printf.h"
|
||||
|
||||
// This is for git version tracking. Safe to ignore
|
||||
#ifdef VERSION_H
|
||||
#include "version.h"
|
||||
#else
|
||||
#define __TAG__ "Unknown"
|
||||
#endif
|
||||
|
||||
// Pin definitions
|
||||
#ifndef PINS_DEFINED
|
||||
#define __PLATFORM__ "Getting Started board"
|
||||
|
||||
// Pins for radio
|
||||
const int rf_ce = 9;
|
||||
const int rf_csn = 10;
|
||||
|
||||
// Pins for sensors
|
||||
const int temp_pin = A2;
|
||||
const int voltage_pin = A3;
|
||||
|
||||
// Pins for status LED, or '0' for no LED connected
|
||||
const int led_red = 0;
|
||||
const int led_yellow = 0;
|
||||
const int led_green = 0;
|
||||
|
||||
// Button to control modes
|
||||
const int button_a = 4;
|
||||
|
||||
// What voltage is a reading of 1023?
|
||||
const unsigned voltage_reference = 5 * 256; // 5.0V
|
||||
#endif
|
||||
|
||||
RF24 radio(rf_ce,rf_csn);
|
||||
RF24Network network(radio);
|
||||
|
||||
// Our node configuration
|
||||
eeprom_info_t this_node;
|
||||
|
||||
// Sleep constants. In this example, the watchdog timer wakes up
|
||||
// every 4s, and every single wakeup we power up the radio and send
|
||||
// a reading. In real use, these numbers which be much higher.
|
||||
// Try wdt_8s and 7 cycles for one reading per minute.> 1
|
||||
const wdt_prescalar_e wdt_prescalar = wdt_8s;
|
||||
const int sleep_cycles_per_transmission = 1;
|
||||
|
||||
// Non-sleeping nodes need a timer to regulate their sending interval
|
||||
Timer send_timer(8000);
|
||||
|
||||
// Button controls functionality of the unit
|
||||
Button ButtonA(button_a);
|
||||
|
||||
// Long-press button
|
||||
Button ButtonLong(button_a,1000);
|
||||
|
||||
/**
|
||||
* Convenience class for handling LEDs. Handles the case where the
|
||||
* LED may not be populated on the board, so always checks whether
|
||||
* the pin is valid before setting a value.
|
||||
*/
|
||||
|
||||
class LED
|
||||
{
|
||||
private:
|
||||
int pin;
|
||||
public:
|
||||
LED(int _pin): pin(_pin)
|
||||
{
|
||||
if (pin > 0)
|
||||
{
|
||||
pinMode(pin,OUTPUT);
|
||||
digitalWrite(pin,LOW);
|
||||
}
|
||||
}
|
||||
void write(bool state) const
|
||||
{
|
||||
if (pin > 0)
|
||||
digitalWrite(pin,state?HIGH:LOW);
|
||||
}
|
||||
void operator=(bool state)
|
||||
{
|
||||
write(state);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Startup LED sequence. Lights up the LEDs in sequence first, then dims
|
||||
* them in the same sequence.
|
||||
*/
|
||||
|
||||
class StartupLEDs: public Timer
|
||||
{
|
||||
private:
|
||||
const LED** leds;
|
||||
const LED** current;
|
||||
const LED** end;
|
||||
bool state;
|
||||
protected:
|
||||
virtual void onFired(void)
|
||||
{
|
||||
(*current)->write(state);
|
||||
++current;
|
||||
if ( current >= end )
|
||||
{
|
||||
if ( state )
|
||||
{
|
||||
state = false;
|
||||
current = leds;
|
||||
}
|
||||
else
|
||||
disable();
|
||||
}
|
||||
}
|
||||
public:
|
||||
StartupLEDs(const LED** _leds, int _num): Timer(250), leds(_leds), current(_leds), end(_leds+_num), state(true)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Calibration LED sequence. Flashes all 3 in unison
|
||||
*/
|
||||
class CalibrationLEDs: public Timer
|
||||
{
|
||||
const LED** leds;
|
||||
const LED** end;
|
||||
bool state;
|
||||
protected:
|
||||
void write()
|
||||
{
|
||||
const LED** current = end;
|
||||
while (current-- > leds)
|
||||
(*current)->write(state);
|
||||
}
|
||||
virtual void onFired()
|
||||
{
|
||||
state = ! state;
|
||||
write();
|
||||
}
|
||||
public:
|
||||
CalibrationLEDs(const LED** _leds, int _num, unsigned long duration = 500): Timer(duration), leds(_leds), end(_leds+_num), state(false)
|
||||
{
|
||||
Timer::disable();
|
||||
}
|
||||
void begin()
|
||||
{
|
||||
Updatable::begin();
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
state = true;
|
||||
write();
|
||||
Timer::reset();
|
||||
}
|
||||
void disable()
|
||||
{
|
||||
state = false;
|
||||
write();
|
||||
Timer::disable();
|
||||
}
|
||||
};
|
||||
|
||||
LED Red(led_red), Yellow(led_yellow), Green(led_green);
|
||||
|
||||
const LED* leds[] = { &Red, &Yellow, &Green };
|
||||
const int num_leds = sizeof(leds)/sizeof(leds[0]);
|
||||
StartupLEDs startup_leds(leds,num_leds);
|
||||
CalibrationLEDs calibration_leds(leds,num_leds);
|
||||
|
||||
// Nodes in test mode do not sleep, but instead constantly try to send
|
||||
bool test_mode = false;
|
||||
|
||||
// Nodes in calibration mode are looking for temperature calibration
|
||||
bool calibration_mode = false;
|
||||
|
||||
// Helper functions to take readings
|
||||
|
||||
// How many measurements to take. 64*1024 = 65536, so 64 is the max we can fit in a uint16_t.
|
||||
const int num_measurements = 64;
|
||||
|
||||
uint32_t measure_temp()
|
||||
{
|
||||
int i = num_measurements;
|
||||
uint32_t reading = 0;
|
||||
while(i--)
|
||||
reading += analogRead(temp_pin);
|
||||
|
||||
// Convert the reading to celcius*256
|
||||
// This is the formula for MCP9700.
|
||||
// C = reading * 1.1
|
||||
// C = ( V - 1/2 ) * 100
|
||||
//
|
||||
// Then adjust for the calibation value on this sensor
|
||||
return ( ( ( ( reading * 0x120 ) - 0x800000 ) * 0x64 ) >> 16 ) + this_node.temp_calibration;
|
||||
}
|
||||
|
||||
uint32_t measure_voltage()
|
||||
{
|
||||
// Take the voltage reading
|
||||
int i = num_measurements;
|
||||
uint32_t reading = 0;
|
||||
while(i--)
|
||||
reading += analogRead(voltage_pin);
|
||||
|
||||
// Convert the voltage reading to volts*256
|
||||
return ( reading * voltage_reference ) >> 16;
|
||||
}
|
||||
|
||||
struct CalibrationData
|
||||
{
|
||||
uint8_t measurements_remaining;
|
||||
static const uint8_t measurements_needed = 16;
|
||||
int16_t accumulator;
|
||||
|
||||
CalibrationData()
|
||||
{
|
||||
measurements_remaining = measurements_needed;
|
||||
accumulator = 0;
|
||||
}
|
||||
void add(int16_t reading)
|
||||
{
|
||||
accumulator += reading / measurements_needed;
|
||||
if ( measurements_remaining )
|
||||
--measurements_remaining;
|
||||
}
|
||||
bool done() const
|
||||
{
|
||||
return measurements_remaining == 0;
|
||||
}
|
||||
int16_t result() const
|
||||
{
|
||||
return accumulator;
|
||||
}
|
||||
};
|
||||
|
||||
CalibrationData calibration_data;
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
//
|
||||
// Print preamble
|
||||
//
|
||||
|
||||
Serial.begin(57600);
|
||||
printf_begin();
|
||||
printf_P(PSTR("\n\rRF24Network/examples/sensornet/\n\r"));
|
||||
printf_P(PSTR("PLATFORM: " __PLATFORM__ "\n\r"));
|
||||
printf_P(PSTR("VERSION: " __TAG__ "\n\r"));
|
||||
|
||||
//
|
||||
// Pull node address out of eeprom
|
||||
//
|
||||
|
||||
// Which node are we?
|
||||
this_node = nodeconfig_read();
|
||||
|
||||
//
|
||||
// Prepare sleep parameters
|
||||
//
|
||||
|
||||
// Only the leaves sleep. Nodes 01-05 are presumed to be relay nodes.
|
||||
if ( ! this_node.relay )
|
||||
Sleep.begin(wdt_prescalar,sleep_cycles_per_transmission);
|
||||
|
||||
//
|
||||
// Set up board hardware
|
||||
//
|
||||
ButtonA.begin();
|
||||
ButtonLong.begin();
|
||||
|
||||
// Sensors use the stable internal 1.1V voltage
|
||||
#ifdef INTERNAL1V1
|
||||
analogReference(INTERNAL1V1);
|
||||
#else
|
||||
analogReference(INTERNAL);
|
||||
#endif
|
||||
|
||||
// Prepare the startup sequence
|
||||
send_timer.begin();
|
||||
startup_leds.begin();
|
||||
calibration_leds.begin();
|
||||
|
||||
//
|
||||
// Bring up the RF network
|
||||
//
|
||||
|
||||
SPI.begin();
|
||||
radio.begin();
|
||||
network.begin(/*channel*/ 92, /*node address*/ this_node.address);
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
// Update objects
|
||||
theUpdater.update();
|
||||
|
||||
// Pump the network regularly
|
||||
network.update();
|
||||
|
||||
// Is there anything ready for us?
|
||||
while ( network.available() )
|
||||
{
|
||||
// If so, grab it and print it out
|
||||
RF24NetworkHeader header;
|
||||
S_message message;
|
||||
network.read(header,&message,sizeof(message));
|
||||
printf_P(PSTR("%lu: APP Received #%u type %c %s from 0%o\n\r"),millis(),header.id,header.type,message.toString(),header.from_node);
|
||||
|
||||
// If we get a message, that's a little odd, because this sketch doesn't run on the
|
||||
// base node. Possibly it's a test message from a child node. Possibly it's a sensor
|
||||
// calibration message from a parent node.
|
||||
//
|
||||
// Either way, it only matters if we're NOT sleeping, and also only useful it we have
|
||||
// a temp sensor
|
||||
|
||||
// If we have a temp sensor AND we are not sleeping
|
||||
if ( temp_pin > -1 && ( ! Sleep || test_mode ) )
|
||||
{
|
||||
// if the received message is a test message, we can respond with a 'C' message in return
|
||||
if ( header.type == 'c' )
|
||||
{
|
||||
// Take a reading
|
||||
S_message response;
|
||||
response.temp_reading = measure_temp();
|
||||
response.voltage_reading = measure_voltage();
|
||||
|
||||
// Send it back as a calibration message
|
||||
RF24NetworkHeader response_header(/*to node*/ header.from_node, /*type*/ 'C');
|
||||
network.write(response_header,&response,sizeof(response));
|
||||
}
|
||||
else if ( header.type == 'C' )
|
||||
{
|
||||
// This is a calibration message. Calculate the diff
|
||||
uint16_t diff = message.temp_reading - measure_temp();
|
||||
printf_P(PSTR("%lu: APP Calibration received %04x diff %04x\n\r"),millis(),message.temp_reading,diff);
|
||||
calibration_data.add(diff);
|
||||
|
||||
if ( calibration_data.done() )
|
||||
{
|
||||
calibration_mode = false;
|
||||
calibration_leds.disable();
|
||||
printf_P(PSTR("%lu: APP Stop calibration mode. Calibrate by %04x\n\r"),millis(),calibration_data.result());
|
||||
|
||||
// Now apply the calibration
|
||||
this_node.temp_calibration += calibration_data.result();
|
||||
// And save it to eeprom...
|
||||
set_temp_calibration( this_node.temp_calibration );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we are the kind of node that sends readings,
|
||||
// AND we have a temp sensor
|
||||
// AND it's time to send a reading
|
||||
// AND we're in the mode where we send readings...
|
||||
if ( this_node.address > 0 && temp_pin > -1 && ( ( Sleep && ! test_mode ) || send_timer.wasFired() ) && ! startup_leds )
|
||||
{
|
||||
// Transmission beginning, TX LED ON
|
||||
Yellow = true;
|
||||
if ( test_mode && ! calibration_mode )
|
||||
{
|
||||
Green = false;
|
||||
Red = false;
|
||||
}
|
||||
|
||||
S_message message;
|
||||
message.temp_reading = measure_temp();
|
||||
message.voltage_reading = measure_voltage();
|
||||
|
||||
char message_type = 'S';
|
||||
if ( calibration_mode )
|
||||
message_type = 'c';
|
||||
else if (test_mode )
|
||||
message_type = 't';
|
||||
|
||||
// By default send to the base
|
||||
uint16_t to_node = 0;
|
||||
if ( test_mode )
|
||||
// In test mode, sent to our parent.
|
||||
to_node = network.parent();
|
||||
|
||||
printf_P(PSTR("---------------------------------\n\r"));
|
||||
printf_P(PSTR("%lu: APP Sending type-%c %s to 0%o...\n\r"),millis(),message_type,message.toString(),to_node);
|
||||
|
||||
RF24NetworkHeader header(to_node,message_type);
|
||||
bool ok = network.write(header,&message,sizeof(message));
|
||||
if (ok)
|
||||
{
|
||||
if ( test_mode && ! calibration_mode )
|
||||
Green = true;
|
||||
printf_P(PSTR("%lu: APP Send ok\n\r"),millis());
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( test_mode && ! calibration_mode )
|
||||
Red = true;
|
||||
printf_P(PSTR("%lu: APP Send failed\n\r"),millis());
|
||||
}
|
||||
|
||||
// Transmission complete, TX LED OFF
|
||||
Yellow = false;
|
||||
|
||||
if ( Sleep && ! test_mode )
|
||||
{
|
||||
// Power down the radio. Note that the radio will get powered back up
|
||||
// on the next write() call.
|
||||
radio.powerDown();
|
||||
|
||||
// Be sure to flush the serial first before sleeping, so everything
|
||||
// gets printed properly
|
||||
Serial.flush();
|
||||
|
||||
// Sleep the MCU. The watchdog timer will awaken in a short while, and
|
||||
// continue execution here.
|
||||
Sleep.go();
|
||||
}
|
||||
}
|
||||
|
||||
// Button
|
||||
unsigned a = ButtonA.wasReleased();
|
||||
if ( a && a < 500 )
|
||||
{
|
||||
// Pressing the button during startup sequences engages test mode.
|
||||
// Pressing it after turns off test mode.
|
||||
if ( startup_leds )
|
||||
{
|
||||
test_mode = true;
|
||||
send_timer.setInterval(1000);
|
||||
printf_P(PSTR("%lu: APP Start test mode\n\r"),millis());
|
||||
}
|
||||
else if ( calibration_mode )
|
||||
{
|
||||
calibration_mode = false;
|
||||
calibration_leds.disable();
|
||||
printf_P(PSTR("%lu: APP Stop calibration mode\n\r"),millis());
|
||||
}
|
||||
else if ( test_mode )
|
||||
{
|
||||
test_mode = false;
|
||||
Green = false;
|
||||
Red = false;
|
||||
send_timer.setInterval(8000);
|
||||
printf_P(PSTR("%lu: APP Stop test mode\n\r"),millis());
|
||||
}
|
||||
}
|
||||
|
||||
// Long press
|
||||
if ( ButtonLong.wasPressed() && test_mode )
|
||||
{
|
||||
calibration_mode = true;
|
||||
calibration_leds.reset();
|
||||
calibration_data = CalibrationData();
|
||||
printf_P(PSTR("%lu: APP Start calibration mode\n\r"),millis());
|
||||
}
|
||||
|
||||
// Listen for a new node address
|
||||
nodeconfig_listen();
|
||||
}
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
/*
|
||||
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 sleep.cpp
|
||||
*
|
||||
* Sleep helpers, definitions
|
||||
*/
|
||||
|
||||
#include "RF24Network_config.h"
|
||||
#include <avr/sleep.h>
|
||||
#include "sleep.h"
|
||||
|
||||
sleep_c Sleep;
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void sleep_c::begin(wdt_prescalar_e prescalar_in,short cycles)
|
||||
{
|
||||
sleep_cycles_remaining = cycles;
|
||||
sleep_cycles_per_transmission = cycles;
|
||||
|
||||
uint8_t prescalar = min(9,(uint8_t)prescalar_in);
|
||||
uint8_t wdtcsr = prescalar & 7;
|
||||
if ( prescalar & 8 )
|
||||
wdtcsr |= _BV(WDP3);
|
||||
|
||||
MCUSR &= ~_BV(WDRF);
|
||||
WDTCSR = _BV(WDCE) | _BV(WDE);
|
||||
WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
void sleep_c::go(void)
|
||||
{
|
||||
while( sleep_cycles_remaining-- )
|
||||
{
|
||||
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
||||
sleep_mode();
|
||||
}
|
||||
|
||||
sleep_cycles_remaining = sleep_cycles_per_transmission;
|
||||
}
|
||||
|
||||
ISR(WDT_vect) {
|
||||
}
|
||||
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
/*
|
||||
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 sleep.h
|
||||
*
|
||||
* Declaration of the sleep_c class.
|
||||
*/
|
||||
|
||||
#ifndef __SLEEP_H__
|
||||
#define __SLEEP_H__
|
||||
|
||||
/**
|
||||
* Enums for the duration of the watchdog timer
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Simplified sleeping handler
|
||||
*/
|
||||
|
||||
class sleep_c
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Enable the system to be able to sleep
|
||||
*
|
||||
* Does not actually do any sleeping.
|
||||
*
|
||||
* For example, to do something roughly evert minute, configure
|
||||
* it like this:
|
||||
*
|
||||
* @code
|
||||
* Sleep.begin(wdt_8s,7);
|
||||
* @endcode
|
||||
*
|
||||
* @param prescalar Duration of the watchdog timer interrupt.
|
||||
* The system will actually sleep for this long.
|
||||
* @param cycles Number of times the system will wake up before
|
||||
* returning from @p go().
|
||||
*/
|
||||
void begin(wdt_prescalar_e prescalar,short cycles);
|
||||
|
||||
/**
|
||||
* Go to sleep
|
||||
*
|
||||
* This will return after the watchdog has awoken for the number
|
||||
* of times specified in begin().
|
||||
*/
|
||||
void go(void);
|
||||
|
||||
/**
|
||||
* Test whether the node sleeps
|
||||
*
|
||||
* @retval true if the node will sleep
|
||||
*/
|
||||
operator bool(void) const
|
||||
{
|
||||
return sleep_cycles_per_transmission;
|
||||
}
|
||||
|
||||
private:
|
||||
volatile short sleep_cycles_remaining;
|
||||
short sleep_cycles_per_transmission;
|
||||
};
|
||||
|
||||
/**
|
||||
* Singleton instance for general use
|
||||
*
|
||||
* @warning: This class is hard-coded to ONLY work with this singleton.
|
||||
* Any other instances will fail.
|
||||
*/
|
||||
|
||||
extern sleep_c Sleep;
|
||||
|
||||
#endif // __SLEEP_H__
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __TIMER_H__
|
||||
#define __TIMER_H__
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
// Framework headers
|
||||
// Library headers
|
||||
// Project headers
|
||||
|
||||
/**
|
||||
* Simple timer
|
||||
*/
|
||||
|
||||
struct timer_t
|
||||
{
|
||||
unsigned long last;
|
||||
unsigned long interval;
|
||||
timer_t(unsigned long _interval): interval(_interval) {}
|
||||
operator bool(void)
|
||||
{
|
||||
unsigned long now = millis();
|
||||
bool result = now - last >= interval;
|
||||
if ( result )
|
||||
last = now;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __TEMPLATE_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
19
hardware/digistump/sam/libraries/RF24Network/tests/README
Normal file
19
hardware/digistump/sam/libraries/RF24Network/tests/README
Normal file
@@ -0,0 +1,19 @@
|
||||
This is the 'receiver' for the unit tests. Run it on a node which
|
||||
is NOT under test.
|
||||
|
||||
TODO
|
||||
|
||||
Send finder request needs a re-think. It needs to be re-implemented as a Tictocs::Timer, so it
|
||||
doesn't block the loop().
|
||||
|
||||
I could also make Tictocs objects which monitor the RF24network and pull off messages that are just
|
||||
for them. Likewise, the network can raise a signal when there is a new message. Although I would not
|
||||
want to put that into the library for fear of adding a dependency.
|
||||
|
||||
so the finder needs to maintain state
|
||||
- Waiting: Waiting for a finder request
|
||||
- Sending: In the midst of looping through children
|
||||
|
||||
Needs to have some delay between each send. So the finder has a timer component.
|
||||
|
||||
Also... Reset should also reset the internal copy of the sync data. Sync may need a 'reset' method.
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
// Framework headers
|
||||
// Library headers
|
||||
#include <RF24.h>
|
||||
#include <RF24Network.h>
|
||||
// Project headers
|
||||
// This component's header
|
||||
#include <Globals.h>
|
||||
|
||||
#include "WProgram.h"
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
HardwareSPI SPI(2);
|
||||
|
||||
// Radio on Maple Native w/ Getting Started board
|
||||
RF24 radio(7,6);
|
||||
RF24Network network(radio);
|
||||
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __GLOBALS_H__
|
||||
#define __GLOBALS_H__
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
// Framework headers
|
||||
// Library headers
|
||||
// Project headers
|
||||
|
||||
class RF24;
|
||||
class RF24Network;
|
||||
|
||||
extern RF24 radio;
|
||||
extern RF24Network network;
|
||||
|
||||
/**
|
||||
* Example for how classes should be declared
|
||||
*/
|
||||
|
||||
class Template
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
public:
|
||||
};
|
||||
|
||||
#endif // __GLOBALS_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,12 @@
|
||||
SubDir TOP ;
|
||||
|
||||
# Set up output directories
|
||||
LOCATE_TARGET = $(SEARCH_SOURCE)/out/$(TOOLSET) ;
|
||||
LOCATE_SOURCE = $(LOCATE_TARGET) ;
|
||||
|
||||
# Pull in local libraries
|
||||
SKETCH_LIBS += RF24Network RF24 ;
|
||||
HDRS += $(HOME)/Source/Arduino/libraries/$(SKETCH_LIBS) ;
|
||||
|
||||
# Main output executable
|
||||
Maple $(SEARCH_SOURCE:B).elf : [ GLOB $(SEARCH_SOURCE) $(HOME)/Source/Arduino/libraries/$(SKETCH_LIBS) : $(MODULE_EXT) ] ;
|
||||
251
hardware/digistump/sam/libraries/RF24Network/tests/unit/Jamrules
Normal file
251
hardware/digistump/sam/libraries/RF24Network/tests/unit/Jamrules
Normal file
@@ -0,0 +1,251 @@
|
||||
MCU = cortex-m3 ;
|
||||
CHIP = STM32F103ZE ;
|
||||
BOARD = maple_native ;
|
||||
|
||||
#CHIP = at91sam3u4 ;
|
||||
#BOARD = sam3u-ek ;
|
||||
|
||||
if ! $(TOOLSET)
|
||||
{
|
||||
TOOLSET = mix ;
|
||||
Echo "Assuming TOOLSET=mix" ;
|
||||
}
|
||||
else if $(TOOLSET) = cs
|
||||
{
|
||||
TOOLS_PATH = /opt/cs/arm/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
}
|
||||
else if $(TOOLSET) = yagarto
|
||||
{
|
||||
TOOLS_PATH = ~/Source/yagarto-4.6.2/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
}
|
||||
if $(TOOLSET) = yagarto-install
|
||||
{
|
||||
TOOLS_PATH = ~/Source/yagarto/install/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
}
|
||||
else if $(TOOLSET) = devkit
|
||||
{
|
||||
TOOLS_PATH = /opt/devkitARM/bin ;
|
||||
TOOLS_ARCH = arm-eabi- ;
|
||||
}
|
||||
else if $(TOOLSET) = maple
|
||||
{
|
||||
TOOLS_PATH = /opt/Maple/Resources/Java/hardware/tools/arm/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
LINK_DIR = /opt/Maple/Resources/Java/hardware/leaflabs/cores/maple ;
|
||||
MAPLE_DIR = /opt/Maple/Resources/Java/hardware/leaflabs/cores/maple ;
|
||||
MAPLE_SUBDIRS = . ;
|
||||
}
|
||||
else if $(TOOLSET) = mix
|
||||
{
|
||||
TOOLS_PATH = /opt/Maple/Resources/Java/hardware/tools/arm/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
LINKFLAGS += --print-gc-sections ;
|
||||
}
|
||||
else if $(TOOLSET) = ports
|
||||
{
|
||||
TOOLS_PATH = /opt/local/bin ;
|
||||
TOOLS_ARCH = arm-none-eabi- ;
|
||||
}
|
||||
|
||||
# Tool locations
|
||||
|
||||
CC = $(TOOLS_PATH)/$(TOOLS_ARCH)gcc ;
|
||||
C++ = $(TOOLS_PATH)/$(TOOLS_ARCH)g++ ;
|
||||
AS = $(TOOLS_PATH)/$(TOOLS_ARCH)gcc -c ;
|
||||
LINK = $(TOOLS_PATH)/$(TOOLS_ARCH)g++ ;
|
||||
OBJCOPY = $(TOOLS_PATH)/$(TOOLS_ARCH)objcopy ;
|
||||
DFU = dfu-util ;
|
||||
|
||||
# Flags
|
||||
|
||||
DEFINES += VECT_TAB_FLASH BOARD_$(BOARD) MCU_$(CHIP) ERROR_LED_PORT=GPIOC ERROR_LED_PIN=15 STM32_HIGH_DENSITY MAPLE_IDE ;
|
||||
OPTIM = -Os ;
|
||||
MFLAGS = cpu=$(MCU) thumb arch=armv7-m ;
|
||||
CCFLAGS = -Wall -Wno-strict-aliasing -Wno-format -m$(MFLAGS) -g -nostdlib -ffunction-sections -fdata-sections -Wl,--gc-sections ;
|
||||
C++FLAGS = $(CCFLAGS) -fno-rtti -fno-exceptions ;
|
||||
LINKFLAGS += -m$(MFLAGS) -Xlinker --gc-sections ;
|
||||
DFUFLAGS = -a1 -d 0x1eaf:0x0003 -R ;
|
||||
|
||||
# Directories
|
||||
|
||||
MAPLE_DIR ?= /opt/libmaple ;
|
||||
MAPLE_LIBS = Servo LiquidCrystal Wire FreeRTOS ;
|
||||
MAPLE_SUBDIRS ?= libmaple libmaple/usb libmaple/usb/usb_lib wirish wirish/comm wirish/boards ;
|
||||
|
||||
SKETCH_DIR = $(HOME)/Source/Maple ;
|
||||
|
||||
CORE_DIRS = $(MAPLE_DIR)/$(MAPLE_SUBDIRS) $(MAPLE_DIR)/libraries/$(MAPLE_LIBS) $(MAPLE_DIR)/libraries/$(MAPLE_LIBS)/utility ;
|
||||
HDRS = $(CORE_DIRS) ;
|
||||
|
||||
# Modules
|
||||
MODULE_EXT = *.c *.cpp *.S *.pde *.ino *.test ;
|
||||
CORE_MODULES = [ GLOB $(CORE_DIRS) : $(MODULE_EXT) ] ;
|
||||
|
||||
# Unit test framework
|
||||
CXXTEST_DIR = $(HOME)/Source/cxxtest ;
|
||||
CXXTEST_GEN = $(CXXTEST_DIR)/bin/cxxtestgen ;
|
||||
HDRS += $(CXXTEST_DIR) ;
|
||||
|
||||
# Linker script
|
||||
LINK_DIR ?= $(MAPLE_DIR)/support/ld ;
|
||||
LINKSCRIPT = $(LINK_DIR)/$(BOARD)/flash.ld ;
|
||||
LINKFLAGS += -T$(LINKSCRIPT) -L$(LINK_DIR) ;
|
||||
|
||||
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 TestSuite
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
MakeLocate $(<) : $(LOCATE_SOURCE) ;
|
||||
Clean clean : $(<) ;
|
||||
}
|
||||
|
||||
actions TestSuite
|
||||
{
|
||||
$(CXXTEST_GEN) --part $(>) > $(<)
|
||||
}
|
||||
|
||||
rule TestRoot
|
||||
{
|
||||
MakeLocate $(<) : $(LOCATE_SOURCE) ;
|
||||
}
|
||||
|
||||
actions TestRoot
|
||||
{
|
||||
$(CXXTEST_GEN) --root --error-printer > $(<)
|
||||
}
|
||||
|
||||
rule C++TestSuite
|
||||
{
|
||||
local _CPP = $(>:B).cpp ;
|
||||
TestSuite $(_CPP) : $(>) ;
|
||||
C++ $(<) : $(_CPP) ;
|
||||
}
|
||||
|
||||
rule Hex
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
MakeLocate $(<) : $(LOCATE_TARGET) ;
|
||||
Depends hex : $(<) ;
|
||||
Clean clean : $(<) ;
|
||||
}
|
||||
|
||||
actions Hex
|
||||
{
|
||||
$(OBJCOPY) -O ihex $(>) $(<)
|
||||
}
|
||||
|
||||
rule Binary
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
MakeLocate $(<) : $(LOCATE_TARGET) ;
|
||||
Depends binary : $(<) ;
|
||||
Clean clean : $(<) ;
|
||||
}
|
||||
|
||||
actions Binary
|
||||
{
|
||||
$(OBJCOPY) -O binary $(>) $(<)
|
||||
}
|
||||
|
||||
rule UserObject
|
||||
{
|
||||
switch $(>:S)
|
||||
{
|
||||
case .S : As $(<) : $(>) ;
|
||||
case .ino : C++Pde $(<) : $(>) ;
|
||||
case .pde : C++Pde $(<) : $(>) ;
|
||||
case .test : C++TestSuite $(<) : $(>) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule Upload
|
||||
{
|
||||
Depends up : $(<) ;
|
||||
NotFile up ;
|
||||
Always $(<) ;
|
||||
}
|
||||
|
||||
actions Upload
|
||||
{
|
||||
$(MAPLE_DIR)/support/scripts/reset.py
|
||||
sleep 1
|
||||
$(DFU) $(DFUFLAGS) -D $(<)
|
||||
sleep 5
|
||||
}
|
||||
|
||||
rule Login
|
||||
{
|
||||
MakeLocate $(<) : $(LOCATE_TARGET) ;
|
||||
Always $(<) ;
|
||||
}
|
||||
|
||||
actions Login
|
||||
{
|
||||
ls > $(<)
|
||||
screen $(>)
|
||||
}
|
||||
|
||||
# Override base objects rule, so all output can go in the output dir
|
||||
rule Objects
|
||||
{
|
||||
local _i ;
|
||||
|
||||
for _i in [ FGristFiles $(<) ]
|
||||
{
|
||||
local _b = $(_i:B)$(SUFOBJ) ;
|
||||
local _o = $(_b:G=$(SOURCE_GRIST:E)) ;
|
||||
Object $(_o) : $(_i) ;
|
||||
Depends obj : $(_o) ;
|
||||
}
|
||||
}
|
||||
|
||||
# Override base main rule, so all output can go in the output dir
|
||||
rule Main
|
||||
{
|
||||
# Bring in the map
|
||||
LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ;
|
||||
|
||||
MakeLocate $(<) ;
|
||||
MainFromObjects $(<) : $(>:B)$(SUFOBJ) ;
|
||||
Objects $(>) ;
|
||||
}
|
||||
|
||||
rule Maple
|
||||
{
|
||||
Main $(<) : $(>) $(CORE_MODULES) ;
|
||||
Binary $(<:B).bin : $(<) ;
|
||||
Upload $(<:B).bin ;
|
||||
Login login : /dev/tty.usbmodemfa441 ;
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// STL headers
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
// C headers
|
||||
#include <stdlib.h>
|
||||
// Framework headers
|
||||
// Library headers
|
||||
#include <cxxtest/TestSuite.h>
|
||||
// Project headers
|
||||
#include <RF24Network.h>
|
||||
#include <RF24.h>
|
||||
// This component's header
|
||||
#include <Sync.h>
|
||||
|
||||
#include "WProgram.h"
|
||||
#include "Globals.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class PingTestSuite: public CxxTest::TestSuite
|
||||
{
|
||||
|
||||
public:
|
||||
// 'Delay' but update the network for a bit
|
||||
void net_delay(unsigned long amount)
|
||||
{
|
||||
unsigned long start = millis();
|
||||
while ( millis() - start < amount )
|
||||
{
|
||||
network.update();
|
||||
#if 0
|
||||
// Is there anything ready for us?
|
||||
if ( network.available() )
|
||||
{
|
||||
// If so, take a look at it
|
||||
RF24NetworkHeader header;
|
||||
network.read(header,0,0);
|
||||
|
||||
cout << millis() << ": net_delay got " << header.type << " from " << header.from_node << "\r\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void setUp()
|
||||
{
|
||||
// Reset remote to initial state
|
||||
RF24NetworkHeader header(/*to node*/ 1, /*type*/ 'R' /*Reset*/);
|
||||
network.write(header,0,0);
|
||||
|
||||
// Wait a bit for the message to take
|
||||
net_delay(50);
|
||||
}
|
||||
|
||||
void tearDown()
|
||||
{
|
||||
net_delay(100);
|
||||
//cout << "\r\n Complete. Press any key \r\n";
|
||||
//SerialUSB.read();
|
||||
}
|
||||
|
||||
void testNothing()
|
||||
{
|
||||
cout << "\r\n STARTING " << __FUNCTION__ << "\r\n";
|
||||
}
|
||||
|
||||
void testPing()
|
||||
{
|
||||
cout << "\r\n STARTING " << __FUNCTION__ << "\r\n";
|
||||
|
||||
// Send an echo ping to the other unit
|
||||
RF24NetworkHeader header(/*to node*/ 1, /*type*/ 'E' /*Echo*/);
|
||||
uint32_t testval = 0x12345678, gotval = 0;
|
||||
network.write(header,&testval,sizeof(testval));
|
||||
|
||||
const unsigned long timeout = 1000;
|
||||
unsigned long sent_at = millis();
|
||||
while ( millis() - sent_at < timeout && ! gotval )
|
||||
{
|
||||
net_delay(100);
|
||||
|
||||
// Is there anything ready for us?
|
||||
if ( network.available() )
|
||||
{
|
||||
// If so, take a look at it
|
||||
RF24NetworkHeader header;
|
||||
network.peek(header);
|
||||
|
||||
switch (header.type)
|
||||
{
|
||||
case 'E':
|
||||
network.read(header,&gotval,sizeof(gotval));
|
||||
break;
|
||||
default:
|
||||
// Anything else is unexpected, and ergo a test failure
|
||||
network.read(header,0,0);
|
||||
gotval = -1;
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
TS_ASSERT_EQUALS( gotval, testval );
|
||||
}
|
||||
|
||||
void testFinder()
|
||||
{
|
||||
cout << "\r\n STARTING " << __FUNCTION__ << "\r\n";
|
||||
|
||||
// Send a child finder to the other unit
|
||||
RF24NetworkHeader header(/*to node*/ 1, /*type*/ 'F' /*Echo*/);
|
||||
uint32_t testval = 0x12345678, gotval = 0;
|
||||
network.write(header,&testval,sizeof(testval));
|
||||
|
||||
const unsigned long timeout = 3000;
|
||||
unsigned long sent_at = millis();
|
||||
while ( millis() - sent_at < timeout ) // && ! gotval )
|
||||
{
|
||||
network.update();
|
||||
|
||||
// Is there anything ready for us?
|
||||
if ( network.available() )
|
||||
{
|
||||
// If so, take a look at it
|
||||
RF24NetworkHeader header;
|
||||
network.peek(header);
|
||||
network.read(header,&gotval,sizeof(gotval));
|
||||
|
||||
cout << millis() << ": FINDER " << header.type << " from " << header.from_node << " " << hex << gotval << dec << "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
TS_ASSERT_EQUALS( gotval, testval );
|
||||
}
|
||||
|
||||
};
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,12 @@
|
||||
These unit tests only work on Maple. This test runs on a Maple,
|
||||
as node #00. One other node is expected on node #01, running the
|
||||
"unit_rx" sketch, which runs on Arduino.
|
||||
|
||||
In the future, it would be interesting to write a test which enumerated
|
||||
the entire tree. Each node could implement a "child finder", where it
|
||||
sends a message to each child. Upon receiving the message, each child
|
||||
sends the message out to ITS children, AND sends a "Hello" to the base node.
|
||||
|
||||
This requires a 'F' finder request. For the response, we can re-use
|
||||
the 'E' echo response. The 'E' echo system presumes that the base is
|
||||
the requestor and the RX nodes are the responder.
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// STL headers
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
// C headers
|
||||
#include <stdlib.h>
|
||||
// Framework headers
|
||||
// Library headers
|
||||
#include <cxxtest/TestSuite.h>
|
||||
// Project headers
|
||||
#include <RF24Network.h>
|
||||
#include <RF24.h>
|
||||
// This component's header
|
||||
#include <Sync.h>
|
||||
|
||||
#include "WProgram.h"
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class SyncTestSuite: public CxxTest::TestSuite
|
||||
{
|
||||
struct sync_data_t
|
||||
{
|
||||
uint16_t first;
|
||||
uint16_t second;
|
||||
|
||||
sync_data_t(void): first(1), second(2) {}
|
||||
};
|
||||
|
||||
sync_data_t* p_sync_data;
|
||||
|
||||
Sync* pSync;
|
||||
|
||||
public:
|
||||
// 'Delay' but update the network for a bit
|
||||
void net_delay(unsigned long amount)
|
||||
{
|
||||
unsigned long start = millis();
|
||||
while ( millis() - start < amount )
|
||||
{
|
||||
pSync->update();
|
||||
// Is there anything ready for us?
|
||||
if ( network.available() )
|
||||
{
|
||||
// If so, take a look at it
|
||||
RF24NetworkHeader header;
|
||||
network.read(header,0,0);
|
||||
|
||||
cout << millis() << ": net_delay got " << header.type << " from " << header.from_node << "\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
void setUp()
|
||||
{
|
||||
pSync = new Sync(network);
|
||||
pSync->begin(/* other node*/ 1);
|
||||
p_sync_data = new(sync_data_t);
|
||||
|
||||
// Reset remote to initial state
|
||||
RF24NetworkHeader header(/*to node*/ 1, /*type*/ 'R' /*Reset*/);
|
||||
network.write(header,0,0);
|
||||
|
||||
// Wait a bit for the message to take
|
||||
net_delay(200);
|
||||
}
|
||||
|
||||
void tearDown()
|
||||
{
|
||||
net_delay(100);
|
||||
//cout << "\r\n Complete. Press any key \r\n";
|
||||
//SerialUSB.read();
|
||||
|
||||
delete p_sync_data;
|
||||
delete pSync;
|
||||
}
|
||||
|
||||
void testNoUpdate( void )
|
||||
{
|
||||
cout << "\r\n STARTING " << __FUNCTION__ << "\r\n";
|
||||
|
||||
pSync->register_me(*p_sync_data);
|
||||
|
||||
int i = 10;
|
||||
while (i--)
|
||||
pSync->update();
|
||||
|
||||
TS_ASSERT_EQUALS(p_sync_data->first,1);
|
||||
}
|
||||
void testSync( void )
|
||||
{
|
||||
cout << "\r\n STARTING " << __FUNCTION__ << "\r\n";
|
||||
pSync->register_me(*p_sync_data);
|
||||
|
||||
int i = 10;
|
||||
while (i--)
|
||||
pSync->update();
|
||||
|
||||
const uint16_t testval = 10;
|
||||
p_sync_data->first = testval;
|
||||
|
||||
// wait a little while. During this time, the 'first' value will be propagated
|
||||
// out to the other unit, it will set the value onto 'second', and it should get
|
||||
// propagated back.
|
||||
|
||||
const unsigned long interval = 1000;
|
||||
unsigned long sent_at = millis();
|
||||
while ( millis() - sent_at < interval && p_sync_data->second != testval )
|
||||
pSync->update();
|
||||
|
||||
TS_ASSERT_EQUALS(p_sync_data->second,testval);
|
||||
}
|
||||
};
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,77 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
__attribute__((constructor)) __attribute__ ((weak)) void premain()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
__attribute__((weak)) void setup(void)
|
||||
{
|
||||
board_start("No program defined");
|
||||
}
|
||||
|
||||
__attribute__((weak)) void loop(void)
|
||||
{
|
||||
}
|
||||
|
||||
__attribute__((weak)) int main(void)
|
||||
{
|
||||
setup();
|
||||
|
||||
while (true)
|
||||
{
|
||||
loop();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif // ifdef MAPLE_IDE
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,43 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef CXXTEST_RUNNING
|
||||
#define CXXTEST_RUNNING
|
||||
#endif
|
||||
|
||||
#define _CXXTEST_HAVE_STD
|
||||
#define _CXXTEST_LONGLONG long long
|
||||
#include <cxxtest/TestListener.h>
|
||||
#include <cxxtest/TestTracker.h>
|
||||
#include <cxxtest/TestRunner.h>
|
||||
#include <cxxtest/RealDescriptions.h>
|
||||
#include <cxxtest/TestMain.h>
|
||||
#include <cxxtest/ErrorPrinter.h>
|
||||
#include <cxxtest/Root.cpp>
|
||||
|
||||
#include <RF24Network_config.h>
|
||||
#include <RF24Network.h>
|
||||
#include <RF24.h>
|
||||
|
||||
extern void board_start(const char*);
|
||||
extern RF24Network network;
|
||||
extern RF24 radio;
|
||||
|
||||
int main( void )
|
||||
{
|
||||
CxxTest::ErrorPrinter tmp;
|
||||
|
||||
while(1)
|
||||
{
|
||||
board_start(__FILE__);
|
||||
|
||||
SPI.begin();
|
||||
radio.begin();
|
||||
network.begin(/* channel */100,/* this node */0);
|
||||
|
||||
CxxTest::Main<CxxTest::ErrorPrinter>( tmp, 0, NULL );
|
||||
|
||||
printf("Tests complete. Restarting...\r\n");
|
||||
}
|
||||
}
|
||||
const char* CxxTest::RealWorldDescription::_worldName = "cxxtest";
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
// Framework headers
|
||||
// Library headers
|
||||
#include "RF24Network.h"
|
||||
|
||||
// Project headers
|
||||
// This component's header
|
||||
#include <Finder.h>
|
||||
|
||||
extern RF24Network network;
|
||||
|
||||
// Message buffer space
|
||||
static uint8_t message[32];
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
Finder::Finder(void): this_node(0), state(state_waiting),
|
||||
last_sent(millis()-interval), child_increment(-1)
|
||||
{
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void Finder::begin(uint16_t _this_node)
|
||||
{
|
||||
this_node = _this_node;
|
||||
|
||||
if ( ! ( this_node & 07000 ) )
|
||||
{
|
||||
// Figure out the address of the first child. e.g. if our node is 045, our
|
||||
// first child is 0145. So we need to shift 01 up enough places to be the
|
||||
// highest digit
|
||||
child_increment = 01;
|
||||
uint16_t temp = this_node;
|
||||
while ( temp )
|
||||
{
|
||||
child_increment <<= 3;
|
||||
temp >>= 3;
|
||||
}
|
||||
}
|
||||
|
||||
printf_P(PSTR("%lu: Node %o increment %o\r\n"),millis(),this_node,child_increment);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void Finder::update(void)
|
||||
{
|
||||
// Check the network for traffic
|
||||
|
||||
// If we got a new finder request, launch!
|
||||
if ( network.available() )
|
||||
{
|
||||
RF24NetworkHeader header;
|
||||
network.peek(header);
|
||||
if ( header.type == 'F' )
|
||||
{
|
||||
network.read(header,message,sizeof(message));
|
||||
uint16_t from = header.from_node;
|
||||
printf_P(PSTR("%lu: APP Received FINDER request from %o\r\n"),millis(),from);
|
||||
|
||||
if ( state == state_sending )
|
||||
{
|
||||
printf_P(PSTR("%lu: APP ERROR, already sending a finder request\r\n"),millis());
|
||||
}
|
||||
else if ( child_increment == 0xffff )
|
||||
{
|
||||
printf_P(PSTR("%lu: APP This app has no children, done.\r\n"),millis());
|
||||
last_sent = millis() - interval;
|
||||
state = state_done;
|
||||
goto finish;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_sent = millis() - interval;
|
||||
to_node = this_node + child_increment;
|
||||
state = state_sending;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we're working but not ready, continue
|
||||
if ( state != state_waiting && millis() - last_sent <= interval )
|
||||
return;
|
||||
|
||||
// If we're working, send!
|
||||
if ( state == state_sending )
|
||||
{
|
||||
RF24NetworkHeader header(to_node,'F');
|
||||
/*bool ok = */ network.write(header,message,sizeof(message));
|
||||
last_sent = millis();
|
||||
|
||||
to_node += child_increment;
|
||||
|
||||
// Done?
|
||||
if ( to_node > this_node + 5 * child_increment )
|
||||
{
|
||||
state = state_done;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're now done, send the final 'E' back
|
||||
if ( state == state_done )
|
||||
{
|
||||
// Send an 'E' Echo response back to the BASE
|
||||
RF24NetworkHeader header(00,'E');
|
||||
network.write(header,message,sizeof(message));
|
||||
|
||||
state = state_waiting;
|
||||
goto finish;
|
||||
}
|
||||
finish:
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#ifndef __FINDER_H__
|
||||
#define __FINDER_H__
|
||||
|
||||
// STL headers
|
||||
// C headers
|
||||
// Framework headers
|
||||
#include <Arduino.h>
|
||||
// Library headers
|
||||
// Project headers
|
||||
|
||||
/**
|
||||
* Manage a child-finder request
|
||||
*/
|
||||
|
||||
class Finder
|
||||
{
|
||||
private:
|
||||
uint16_t this_node;
|
||||
enum state_e { state_none = 0, state_waiting, state_sending, state_done, state_invalid };
|
||||
state_e state;
|
||||
static const unsigned long interval = 50;
|
||||
unsigned long last_sent;
|
||||
uint16_t to_node;
|
||||
uint16_t child_increment;
|
||||
protected:
|
||||
|
||||
public:
|
||||
Finder(void);
|
||||
void begin(uint16_t);
|
||||
void update(void);
|
||||
};
|
||||
|
||||
#endif // __FINDER_H__
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,210 @@
|
||||
# (1) Project Information
|
||||
|
||||
PROJECT_LIBS = SPI RF24 RF24Network ;
|
||||
|
||||
# (2) Board Information
|
||||
|
||||
UPLOAD_PROTOCOL ?= stk500v1 ;
|
||||
UPLOAD_SPEED ?= 57600 ;
|
||||
MCU ?= atmega328p ;
|
||||
F_CPU ?= 16000000 ;
|
||||
CORE ?= arduino ;
|
||||
VARIANT ?= standard ;
|
||||
ARDUINO_VERSION ?= 100 ;
|
||||
|
||||
# (3) USB Ports
|
||||
|
||||
PORTS = p4 p6 p9 u0 u1 u2 ;
|
||||
PORT_p6 = /dev/tty.usbserial-A600eHIs ;
|
||||
PORT_p4 = /dev/tty.usbserial-A40081RP ;
|
||||
PORT_p9 = /dev/tty.usbserial-A9007LmI ;
|
||||
PORT_u0 = /dev/ttyUSB0 ;
|
||||
PORT_u1 = /dev/ttyUSB1 ;
|
||||
PORT_u2 = /dev/ttyUSB2 ;
|
||||
|
||||
# (4) Location of AVR tools
|
||||
#
|
||||
# This configuration assumes using avr-tools that were obtained separate from the Arduino
|
||||
# distribution.
|
||||
|
||||
if $(OS) = MACOSX
|
||||
{
|
||||
AVR_BIN = /usr/local/avrtools/bin ;
|
||||
AVR_ETC = /usr/local/avrtools/etc ;
|
||||
AVR_INCLUDE = /usr/local/avrtools/include ;
|
||||
}
|
||||
else
|
||||
{
|
||||
AVR_BIN = /usr/bin ;
|
||||
AVR_INCLUDE = /usr/lib/avr/include ;
|
||||
AVR_ETC = /etc ;
|
||||
}
|
||||
|
||||
# (5) Directories where Arduino core and libraries are located
|
||||
|
||||
ARDUINO_DIR ?= /opt/Arduino ;
|
||||
ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ;
|
||||
ARDUINO_LIB = $(ARDUINO_DIR)/libraries ;
|
||||
SKETCH_LIB = $(HOME)/Source/Arduino/libraries ;
|
||||
|
||||
#
|
||||
# --------------------------------------------------
|
||||
# Below this line usually never needs to be modified
|
||||
#
|
||||
|
||||
# Tool locations
|
||||
|
||||
CC = $(AVR_BIN)/avr-gcc ;
|
||||
C++ = $(AVR_BIN)/avr-g++ ;
|
||||
LINK = $(AVR_BIN)/avr-gcc ;
|
||||
OBJCOPY = $(AVR_BIN)/avr-objcopy ;
|
||||
AVRDUDE = $(AVR_BIN)/avrdude ;
|
||||
|
||||
# Flags
|
||||
|
||||
DEFINES += NODE=$(NODE) F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ;
|
||||
OPTIM = -Os ;
|
||||
CCFLAGS = -Wall -Wextra -mmcu=$(MCU) -ffunction-sections -fdata-sections ;
|
||||
C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ;
|
||||
LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ;
|
||||
AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ;
|
||||
|
||||
# Search everywhere for headers
|
||||
|
||||
HDRS = $(PWD) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ;
|
||||
|
||||
# Output locations
|
||||
|
||||
LOCATE_TARGET = $(F_CPU) ;
|
||||
LOCATE_SOURCE = $(F_CPU) ;
|
||||
|
||||
#
|
||||
# Custom rules
|
||||
#
|
||||
|
||||
rule GitVersion
|
||||
{
|
||||
Always $(<) ;
|
||||
Depends all : $(<) ;
|
||||
}
|
||||
|
||||
actions GitVersion
|
||||
{
|
||||
echo "const char program_version[] = \"\\" > $(<)
|
||||
git log -1 --pretty=format:%h >> $(<)
|
||||
echo "\";" >> $(<)
|
||||
}
|
||||
|
||||
GitVersion version.h ;
|
||||
|
||||
rule Pde
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
MakeLocate $(<) : $(LOCATE_SOURCE) ;
|
||||
Clean clean : $(<) ;
|
||||
}
|
||||
|
||||
if ( $(ARDUINO_VERSION) < 100 )
|
||||
{
|
||||
ARDUINO_H = WProgram.h ;
|
||||
}
|
||||
else
|
||||
{
|
||||
ARDUINO_H = Arduino.h ;
|
||||
}
|
||||
|
||||
actions Pde
|
||||
{
|
||||
echo "#include <$(ARDUINO_H)>" > $(<)
|
||||
echo "#line 1 \"$(>)\"" >> $(<)
|
||||
cat $(>) >> $(<)
|
||||
}
|
||||
|
||||
rule C++Pde
|
||||
{
|
||||
local _CPP = $(>:B).cpp ;
|
||||
Pde $(_CPP) : $(>) ;
|
||||
C++ $(<) : $(_CPP) ;
|
||||
}
|
||||
|
||||
rule UserObject
|
||||
{
|
||||
switch $(>:S)
|
||||
{
|
||||
case .ino : C++Pde $(<) : $(>) ;
|
||||
case .pde : C++Pde $(<) : $(>) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule Objects
|
||||
{
|
||||
local _i ;
|
||||
|
||||
for _i in [ FGristFiles $(<) ]
|
||||
{
|
||||
local _b = $(_i:B)$(SUFOBJ) ;
|
||||
local _o = $(_b:G=$(SOURCE_GRIST:E)) ;
|
||||
Object $(_o) : $(_i) ;
|
||||
Depends obj : $(_o) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule Main
|
||||
{
|
||||
MainFromObjects $(<) : $(>:B)$(SUFOBJ) ;
|
||||
Objects $(>) ;
|
||||
}
|
||||
|
||||
rule Hex
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
MakeLocate $(<) : $(LOCATE_TARGET) ;
|
||||
Depends hex : $(<) ;
|
||||
Clean clean : $(<) ;
|
||||
}
|
||||
|
||||
actions Hex
|
||||
{
|
||||
$(OBJCOPY) -O ihex -R .eeprom $(>) $(<)
|
||||
}
|
||||
|
||||
rule Upload
|
||||
{
|
||||
Depends $(1) : $(2) ;
|
||||
Depends $(2) : $(3) ;
|
||||
NotFile $(1) ;
|
||||
Always $(1) ;
|
||||
Always $(2) ;
|
||||
UploadAction $(2) : $(3) ;
|
||||
}
|
||||
|
||||
actions UploadAction
|
||||
{
|
||||
$(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i
|
||||
}
|
||||
|
||||
#
|
||||
# Targets
|
||||
#
|
||||
|
||||
# Grab everything from the core directory
|
||||
CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ;
|
||||
|
||||
# Grab everything from libraries. To avoid this "grab everything" behaviour, you
|
||||
# can specify specific modules to pick up in PROJECT_MODULES
|
||||
LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ;
|
||||
|
||||
# Grab everything from the current dir
|
||||
PROJECT_MODULES += [ GLOB $(PWD) : *.c *.cpp *.pde *.ino ] ;
|
||||
|
||||
# Main output executable
|
||||
MAIN = $(PWD:B).elf ;
|
||||
|
||||
Main $(MAIN) : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ;
|
||||
Hex $(MAIN:B).hex : $(MAIN) ;
|
||||
|
||||
# Upload targets
|
||||
for _p in $(PORTS)
|
||||
{
|
||||
Upload $(_p) : $(PORT_$(_p)) : $(MAIN:B).hex ;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
This is the 'receiver' for the unit tests. Run it on a node which
|
||||
is NOT under test.
|
||||
|
||||
TODO
|
||||
|
||||
Send finder request needs a re-think. It needs to be re-implemented as a Tictocs::Timer, so it
|
||||
doesn't block the loop().
|
||||
|
||||
I could also make Tictocs objects which monitor the RF24network and pull off messages that are just
|
||||
for them. Likewise, the network can raise a signal when there is a new message. Although I would not
|
||||
want to put that into the library for fear of adding a dependency.
|
||||
|
||||
so the finder needs to maintain state
|
||||
- Waiting: Waiting for a finder request
|
||||
- Sending: In the midst of looping through children
|
||||
|
||||
Needs to have some delay between each send. So the finder has a timer component.
|
||||
|
||||
Also... Reset should also reset the internal copy of the sync data. Sync may need a 'reset' method.
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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__
|
||||
|
||||
int serial_putc( char c, FILE * )
|
||||
{
|
||||
Serial.write( c );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void printf_begin(void)
|
||||
{
|
||||
fdevopen( &serial_putc, 0 );
|
||||
}
|
||||
|
||||
#endif // __PRINTF_H__
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Receiver for unit tests.
|
||||
*/
|
||||
|
||||
#include <RF24Network.h>
|
||||
#include <RF24.h>
|
||||
#include <SPI.h>
|
||||
#include <Sync.h>
|
||||
#include "Finder.h"
|
||||
#include "printf.h"
|
||||
|
||||
// nRF24L01(+) radio attached to SPI and pins 8 & 9
|
||||
RF24 radio(8,9);
|
||||
|
||||
// Network uses that radio
|
||||
RF24Network network(radio);
|
||||
|
||||
// Syncronizer
|
||||
Sync sync(network);
|
||||
|
||||
// Address of our node
|
||||
#if NODE > 0
|
||||
const uint16_t this_node = NODE;
|
||||
#else
|
||||
const uint16_t this_node = 1;
|
||||
#endif
|
||||
|
||||
// Address of the other node
|
||||
const uint16_t other_node = 0;
|
||||
|
||||
// Data to be synchronized
|
||||
struct sync_data_t
|
||||
{
|
||||
uint16_t first;
|
||||
uint16_t second;
|
||||
|
||||
sync_data_t(void): first(1), second(2) {}
|
||||
};
|
||||
|
||||
sync_data_t sync_data;
|
||||
|
||||
// Old value of 'first'
|
||||
uint16_t old_first;
|
||||
|
||||
// Message buffer space
|
||||
uint8_t message[32];
|
||||
|
||||
void send_finder_request(void);
|
||||
void net_delay(unsigned long amount);
|
||||
|
||||
Finder finder;
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(57600);
|
||||
Serial.println("RF24Network/test/unit_rx/");
|
||||
printf_begin();
|
||||
|
||||
SPI.begin();
|
||||
radio.begin();
|
||||
network.begin(/*channel*/ 100, /*node address*/ this_node);
|
||||
finder.begin(this_node);
|
||||
|
||||
sync.register_me(sync_data);
|
||||
old_first = sync_data.first;
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
// Pump the network regularly
|
||||
sync.update();
|
||||
|
||||
// Stay on the lookout for finder messages
|
||||
finder.update();
|
||||
|
||||
// Have the values changed?
|
||||
if ( old_first != sync_data.first )
|
||||
{
|
||||
printf_P(PSTR("%lu: APP Updated first to %u\n\r"),millis(),sync_data.first);
|
||||
|
||||
// Move the first value over to the second
|
||||
sync_data.second = sync_data.first;
|
||||
|
||||
// And remember the change for next time
|
||||
old_first = sync_data.first;
|
||||
}
|
||||
|
||||
// Are there any messages for us?
|
||||
while ( network.available() )
|
||||
{
|
||||
uint16_t from;
|
||||
|
||||
// If so, take a look at it
|
||||
RF24NetworkHeader header;
|
||||
network.peek(header);
|
||||
|
||||
// Dispatch the message to the correct handler.
|
||||
switch (header.type)
|
||||
{
|
||||
// Reset to initial state
|
||||
case 'R':
|
||||
network.read(header,0,0);
|
||||
printf_P(PSTR("%lu: APP Reset to initial state\n\r"),millis());
|
||||
|
||||
sync_data = sync_data_t();
|
||||
old_first = sync_data.first;
|
||||
sync.reset();
|
||||
break;
|
||||
|
||||
// Echo back to the sender.
|
||||
case 'E':
|
||||
network.read(header,message,sizeof(message));
|
||||
from = header.from_node;
|
||||
printf_P(PSTR("%lu: APP Received ECHO request from %o\n\r"),millis(),from);
|
||||
network.write(header = RF24NetworkHeader(from,'E'),message,sizeof(message));
|
||||
break;
|
||||
|
||||
// Unrecognized message type
|
||||
default:
|
||||
printf_P(PSTR("*** WARNING *** Unknown message type %c\n\r"),header.type);
|
||||
network.read(header,0,0);
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// vim:ai:cin:sts=2 sw=2 ft=cpp
|
||||
Reference in New Issue
Block a user