261 lines
6.5 KiB
Plaintext
Raw Normal View History

/*
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