mirror of
https://github.com/digistump/DigistumpArduino.git
synced 2025-04-28 23:59:01 -07:00
261 lines
6.5 KiB
Plaintext
261 lines
6.5 KiB
Plaintext
![]() |
/*
|
||
|
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
|