Skip to content

Commit

Permalink
Major conversion to octal addressing
Browse files Browse the repository at this point in the history
  • Loading branch information
maniacbug committed Jun 13, 2011
1 parent 6e16fc0 commit c4fb0dc
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 95 deletions.
223 changes: 188 additions & 35 deletions RF24Network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <RF24Network.h>
#include <RF24.h>

#undef SERIAL_DEBUG
#define SERIAL_DEBUG
#ifdef SERIAL_DEBUG
#define IF_SERIAL_DEBUG(x) (x)
#else
Expand All @@ -26,33 +26,35 @@

uint16_t RF24NetworkHeader::next_id = 1;

uint64_t pipe_address( uint16_t node, uint8_t pipe );

/******************************************************************/

RF24Network::RF24Network( RF24& _radio, const RF24NodeLine* _topology ): radio(_radio), topology(_topology), next_frame(frame_queue), bidirectional(true)
RF24Network::RF24Network( RF24& _radio ): radio(_radio), next_frame(frame_queue), bidirectional(true)
{
// Find out how many nodes are defined
num_nodes = 0;
const RF24NodeLine* i = topology;
while ( (i++)->parent_node != 0xFFFF )
++num_nodes;
}

/******************************************************************/

void RF24Network::begin(uint8_t _channel, uint16_t _node_address, rf24_direction_e _direction )
{
if ( _node_address < num_nodes )
node_address = _node_address;
node_address = _node_address;

if ( _direction == RF24_NET_UNIDIRECTIONAL )
bidirectional = false;

// 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_pipes();
// Open up our listening pipe
radio.openReadingPipe(0,pipe_address(_node_address,0));

// Spew debugging state about the radio
radio.printDetails();
}

Expand Down Expand Up @@ -88,6 +90,16 @@ void RF24Network::update(void)
else
// Relay it
write(header.to_node);

// 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));
}
}
}
}
Expand Down Expand Up @@ -186,34 +198,58 @@ bool RF24Network::write(uint16_t to_node)
// First, stop listening so we can talk.
radio.stopListening();

// Which pipe should we use to get the message to the "to_node"?
// We need to find a node who is OUR CHILD that either IS the to_node
// or has the to_node as one of ITS children. Failing that, we'll just
// send it back to the parent to deal with.
uint8_t out_node = find_node(node_address,to_node);
// 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;

// If we get '0' as a node, there is a problem
if ( ! out_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) )
{
IF_SERIAL_DEBUG(printf_P(PSTR("%lu: NET Cannot send to node %u, discarded\n\r"),millis(),to_node));
return ok;
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();

// Determine which pipe we should be sending this on
uint64_t out_pipe;
// Put the frame on the pipe
ok = write_to_pipe( send_node, send_pipe );

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

// In Bidirectional mode, if this node is our child, we talk on it's listening pipe.
if ( bidirectional && topology[out_node].parent_node == node_address )
out_pipe = topology[out_node].listening_pipe;
if ( !ok && send_node == parent_node )
ok = write_to_pipe( parent_node, 0 );

// Otherwise, it's our parent so we talk on OUR talking pipe
// (In uni-directional mode, we can ONLY talk to our parent)
else
out_pipe = topology[node_address].talking_pipe;
// 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);

Expand All @@ -225,16 +261,13 @@ bool RF24Network::write(uint16_t to_node)
}
while ( !ok && --attempts );

// Now, continue listening
radio.startListening();

IF_SERIAL_DEBUG(printf_P(PSTR("%lu: MAC Sent on %x %s\n\r"),millis(),(uint16_t)out_pipe,ok?"ok":"failed"));
IF_SERIAL_DEBUG(printf_P(PSTR("%lu: MAC Sent on %lx %s\n\r"),millis(),(uint32_t)out_pipe,ok?"ok":"failed"));

return ok;
}

/******************************************************************/

#if 0
void RF24Network::open_pipes(void)
{
// In order to open the right pipes, we need to know whether the node has parents
Expand Down Expand Up @@ -283,7 +316,6 @@ void RF24Network::open_pipes(void)
//if ( bidirectional || has_children )
radio.startListening();
}

/******************************************************************/

/**
Expand Down Expand Up @@ -320,7 +352,7 @@ uint16_t RF24Network::find_node( uint16_t current_node, uint16_t target_node )
}
return out_node;
}

#endif
/******************************************************************/

const char* RF24NetworkHeader::toString(void) const
Expand All @@ -330,4 +362,125 @@ const char* RF24NetworkHeader::toString(void) const
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;
}

/******************************************************************/

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

#ifdef SERIAL_DEBUG

uint32_t* top = reinterpret_cast<uint32_t*>(out+1);
printf_P(PSTR("pipe_address(%x,%u)=%lx%x\n\r"),node,pipe,*top,*out);

#endif

return result;
}

// vim:ai:cin:sts=2 sw=2 ft=cpp
40 changes: 12 additions & 28 deletions RF24Network.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,6 @@ struct RF24NodeLine
uint16_t parent_node; /**< Logical address of our parent node */
};

/**
* Marker for the start of a topology list
*/
#define RF24NODELINE_LIST_BEGIN { 0xFFFFFFFFFFLL, 0xFFFFFFFFFFLL, 0 },

/**
* Marker for the end of a topology list
*/
#define RF24NODELINE_LIST_END { 0xFFFFFFFFFFLL, 0xFFFFFFFFFFLL, -1 }

/**
* Header which is sent with each message
*
Expand Down Expand Up @@ -120,27 +110,10 @@ class RF24Network
/**
* Construct the network
*
* This requires a static topology. Send in @p _topology as a pointer to a
* terminated array of RF24NodeLines, one node line for each valid node address.
* Adding a new node to the network requires adding/changing the entry in this
* table and re-flashing the entire network. Yes it would be nice to manage
* this dynamically! Someday.
*
* @code
* RF24NodeLine topology[] =
* {
* RF24NODELINE_LIST_BEGIN
* { 0xE7E7E7E7F1LL, 0xE7E7E7E701LL, 0 }, // Node 1: Base, has no parent
* { 0xE7E7E7E7FELL, 0xE7E7E7E70ELL, 1 }, // Node 2: Leaf, child of #1
* RF24NODELINE_LIST_END
* };
* @endcode
*
* @param _radio The underlying radio driver instance
* @param _topology Terminated array of node addresses / pipe mappings.
*
*/
RF24Network( RF24& _radio, const RF24NodeLine* _topology);
RF24Network( RF24& _radio );

/**
* Bring up the network
Expand Down Expand Up @@ -203,8 +176,15 @@ class RF24Network
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 */
Expand All @@ -215,6 +195,10 @@ class RF24Network
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 */
bool bidirectional; /**< Whether we are in bi-dir (true) or uni-dir (false) mode */

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

/**
Expand Down
2 changes: 1 addition & 1 deletion examples/meshping/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ;

DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) ;
CTUNING = -ffunction-sections -fdata-sections ;
CXXTUNING = -fno-exceptions ;
CXXTUNING = -fno-exceptions -fno-strict-aliasing ;
CFLAGS = -Os -Wall -mmcu=$(MCU) $(CTUNING) ;
CXXFLAGS = $(CFLAGS) $(CXXTUNING) ;
LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ;
Expand Down
Loading

0 comments on commit c4fb0dc

Please sign in to comment.