pieter Berteloot / RF24Network

Dependents:   xtoff3 CYS_Receiver

Fork of RF24Network by Akash Vibhute

Files at this revision

API Documentation at this revision

Comitter:
akashvibhute
Date:
Thu Nov 05 05:40:44 2015 +0000
Parent:
1:caf146ffe8b0
Child:
3:dfc8da7ac18c
Commit message:
Updated with TMRh20's RF24 library on Nov/04/2015 from https://github.com/TMRh20; Porting completed on Nov/05/2015

Changed in this revision

RF24Network.cpp Show annotated file Show diff for this revision Revisions of this file
RF24Network.h Show annotated file Show diff for this revision Revisions of this file
RF24Network_config.h Show annotated file Show diff for this revision Revisions of this file
--- a/RF24Network.cpp	Mon Jul 06 05:18:22 2015 +0000
+++ b/RF24Network.cpp	Thu Nov 05 05:40:44 2015 +0000
@@ -7,279 +7,1031 @@
  */
 
 #include "RF24Network_config.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 #include <RF24.h>
 #include "RF24Network.h"
 
-uint16_t RF24NetworkHeader::next_id = 1;
+
+
+
+
+
+
+
 
+uint16_t RF24NetworkHeader::next_id = 1;
+#if defined ENABLE_NETWORK_STATS
+uint32_t RF24Network::nFails = 0;
+uint32_t RF24Network::nOK = 0;
+#endif
 uint64_t pipe_address( uint16_t node, uint8_t pipe );
+#if defined (RF24NetworkMulticast)
+uint16_t levelToAddress( uint8_t level );
+#endif
 bool is_valid_address( uint16_t node );
 
 /******************************************************************/
 
-RF24Network::RF24Network( RF24& _radio ): radio(_radio), next_frame(frame_queue)
+
+
+
+
+
+
+
+#if !defined (DUAL_HEAD_RADIO)
+RF24Network::RF24Network( RF24& _radio ): radio(_radio), next_frame(frame_queue) 
 {
+  #if !defined ( DISABLE_FRAGMENTATION )
+  frag_queue.message_buffer=&frag_queue_message_buffer[0];
+  frag_ptr = &frag_queue;
+  #endif
 }
-
+#else
+RF24Network::RF24Network( RF24& _radio, RF24& _radio1 ): radio(_radio), radio1(_radio1), next_frame(frame_queue)
+{
+  #if !defined ( DISABLE_FRAGMENTATION )
+  frag_queue.message_buffer=&frag_queue_message_buffer[0];
+  frag_ptr = &frag_queue;
+  #endif
+}
+#endif
 /******************************************************************/
 
 void RF24Network::begin(uint8_t _channel, uint16_t _node_address )
 {
-  if (! is_valid_address(_node_address) )
+rf24netTimer.start();
+if (! is_valid_address(_node_address) )
     return;
+    
+  node_address = _node_address;
 
-  node_address = _node_address;
+  if ( ! radio.isValid() ){
+    return;
+  }
 
   // Set up the radio the way we want it to look
-  radio.setChannel(_channel);
-  radio.setDataRate(RF24_1MBPS);
-  radio.setCRCLength(RF24_CRC_16);
-    
-  // Setup Auto ack enabled as it is required by nodes  
-  radio.setAutoAck(1);
-    
+  if(_channel != USE_CURRENT_CHANNEL){
+    radio.setChannel(_channel);
+  }
+  //radio.enableDynamicAck();
+  radio.setAutoAck(0,0);
+  
+  #if defined (ENABLE_DYNAMIC_PAYLOADS)
+  radio.enableDynamicPayloads();
+  #endif
+  
+  // Use different retry periods to reduce data collisions
+  uint8_t retryVar = (((node_address % 6)+1) *2) + 3;
+  radio.setRetries(retryVar, 5);
+  txTimeout = 25;
+  routeTimeout = txTimeout*9; // Adjust for max delay per node
+
+
+#if defined (DUAL_HEAD_RADIO)
+  radio1.setChannel(_channel);
+  radio1.enableDynamicAck();
+  radio1.enableDynamicPayloads();
+#endif
+
   // 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));
+  uint8_t 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 defined ENABLE_NETWORK_STATS
+void RF24Network::failures(uint32_t *_fails, uint32_t *_ok){
+    *_fails = nFails;
+    *_ok = nOK;
+}
+#endif
+
+/******************************************************************/
+
+uint8_t 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
-    bool done = false;
-    while (!done)
-    {
-      // Fetch the payload, and see if this was the last one.
-      done = radio.read( frame_buffer, sizeof(frame_buffer) );
+  uint8_t returnVal = 0;
+  
+  // If bypass is enabled, continue although incoming user data may be dropped
+  // Allows system payloads to be read while user cache is full
+  // Incoming Hold prevents data from being read from the radio, preventing incoming payloads from being acked
+  
+
+  if(!(networkFlags & FLAG_BYPASS_HOLDS)){
+    if( (networkFlags & FLAG_HOLD_INCOMING) || (next_frame-frame_queue) + 34 > MAIN_BUFFER_SIZE ){
+      if(!available()){
+        networkFlags &= ~FLAG_HOLD_INCOMING;
+      }else{
+        return 0;
+      }
+    }
+  }
+
+  
+  while ( radio.isValid() && radio.available(&pipe_num) ){
 
+    #if defined (ENABLE_DYNAMIC_PAYLOADS)
+      if( (frame_size = radio.getDynamicPayloadSize() ) < sizeof(RF24NetworkHeader)){
+        wait_ms(10);
+        continue;
+      }
+    #else
+      frame_size=32;
+    #endif
+      // Dump the payloads until we've gotten everything
+      // Fetch the payload, and see if this was the last one.
+      radio.read( frame_buffer, frame_size );
+      
       // Read the beginning of the frame as the header
-      const RF24NetworkHeader& header = * reinterpret_cast<RF24NetworkHeader*>(frame_buffer);
+      RF24NetworkHeader *header = (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));
+      
+      
+      
+      
+      
+      
+      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;
+      if ( !is_valid_address(header->to_node) ){
+        continue;
+      }
+      
+      uint8_t returnVal = header->type;
 
       // 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   ){
+            
+            if(header->type == NETWORK_PING){
+               continue;
+            }
+            if(header->type == NETWORK_ADDR_RESPONSE ){ 
+                uint16_t requester = frame_buffer[8];   
+                requester |= frame_buffer[9] << 8;
+                if(requester != node_address){
+                    header->to_node = requester;
+                    write(header->to_node,USER_TX_TO_PHYSICAL_ADDRESS);
+                    wait_ms(10);
+                    write(header->to_node,USER_TX_TO_PHYSICAL_ADDRESS);
+                    //printf("Fwd add response to 0%o\n",requester);
+                    continue;
+                }
+            }
+            if(header->type == NETWORK_REQ_ADDRESS && node_address){
+                //printf("Fwd add req to 0\n");
+                header->from_node = node_address;
+                header->to_node = 0;
+                write(header->to_node,TX_NORMAL);
+                continue;
+            }
+            
+            if( (returnSysMsgs && header->type > 127) || header->type == NETWORK_ACK ){ 
+                //IF_SERIAL_DEBUG_ROUTING( printf_P(PSTR("%lu MAC: System payload rcvd %d\n"),millis(),returnVal); );
+                //if( (header->type < 148 || header->type > 150) && header->type != NETWORK_MORE_FRAGMENTS_NACK && header->type != EXTERNAL_DATA_TYPE && header->type!= NETWORK_LAST_FRAGMENT){
+                if( header->type != NETWORK_FIRST_FRAGMENT && header->type != NETWORK_MORE_FRAGMENTS && header->type != NETWORK_MORE_FRAGMENTS_NACK && header->type != EXTERNAL_DATA_TYPE && header->type!= NETWORK_LAST_FRAGMENT){
+                    return returnVal;
+                }
+            }
 
-      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));
+            if( enqueue(header) == 2 ){ //External data received            
+                #if defined (SERIAL_DEBUG_MINIMAL)
+                  printf("ret ext\n");
+                #endif
+                return EXTERNAL_DATA_TYPE;              
+            }
+      }else{      
+
+      #if defined   (RF24NetworkMulticast)  
+
+            if( header->to_node == 0100){
+            
 
-    // 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));
+                if(header->type == NETWORK_POLL ){
+                    //Serial.println("Send poll");
+                    header->to_node = header->from_node;
+                    header->from_node = node_address;           
+                    //delay((node_address%5)*3);
+                    write(header->to_node,USER_TX_TO_PHYSICAL_ADDRESS);
+                    continue;
+                }
+                uint8_t val = enqueue(header);
+                
+                if(multicastRelay){                 
+                    //IF_SERIAL_DEBUG_ROUTING( printf_P(PSTR("%u MAC: FWD multicast frame from 0%o to level %u\n"),millis(),header->from_node,multicast_level+1); );
+                    write(levelToAddress(multicast_level)<<3,4);
+                }
+                if( val == 2 ){ //External data received            
+                  //Serial.println("ret ext multicast");
+                    return EXTERNAL_DATA_TYPE;
+                }
+
+            }else{
+                write(header->to_node,1);   //Send it on, indicate it is a routed payload
+            }
+        #else
+        write(header->to_node,1);   //Send it on, indicate it is a routed payload
+        #endif
       }
-#endif
-    }
+      
   }
+  return returnVal;
 }
 
+
+
 /******************************************************************/
 
-bool RF24Network::enqueue(void)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/******************************************************************/
+/******************************************************************/
+
+ // Not defined RF24_Linux:
+
+/******************************************************************/
+/******************************************************************/
+
+uint8_t RF24Network::enqueue(RF24NetworkHeader* header)
 {
   bool result = false;
+  uint8_t message_size = frame_size - sizeof(RF24NetworkHeader);
   
-  //IF_SERIAL_DEBUG(printf_P(PSTR("%lu: NET Enqueue @%x "),millis(),next_frame-frame_queue));
+  IF_SERIAL_DEBUG(printf_P(PSTR("%lu: NET Enqueue @%x "),millis(),next_frame-frame_queue));
+  
+#if !defined ( DISABLE_FRAGMENTATION ) 
+
+  bool isFragment = header->type == NETWORK_FIRST_FRAGMENT || header->type == NETWORK_MORE_FRAGMENTS || header->type == NETWORK_LAST_FRAGMENT || header->type == NETWORK_MORE_FRAGMENTS_NACK ;
+
+  if(isFragment){
+
+    if(header->type == NETWORK_FIRST_FRAGMENT){
+        // Drop frames exceeding max size and duplicates (MAX_PAYLOAD_SIZE needs to be divisible by 24)
+        if(header->reserved > (MAX_PAYLOAD_SIZE / max_frame_payload_size) ){
+
+  #if defined (SERIAL_DEBUG_FRAGMENTATION) || defined (SERIAL_DEBUG_MINIMAL)
+            printf_P(PSTR("Frag frame with %d frags exceeds MAX_PAYLOAD_SIZE or out of sequence\n"),header->reserved);
+  #endif
+            frag_queue.header.reserved = 0;
+            return false;
+        }else
+        if(frag_queue.header.id == header->id && frag_queue.header.from_node == header->from_node){
+            return true;
+        }
+        
+        if( (header->reserved * 24) > (MAX_PAYLOAD_SIZE - (next_frame-frame_queue)) ){
+          networkFlags |= FLAG_HOLD_INCOMING;
+          radio.stopListening();
+        }
+          
+        memcpy(&frag_queue,&frame_buffer,8);
+        memcpy(frag_queue.message_buffer,frame_buffer+sizeof(RF24NetworkHeader),message_size);
+        
+//IF_SERIAL_DEBUG_FRAGMENTATION( Serial.print(F("queue first, total frags ")); Serial.println(header->reserved); );
+        //Store the total size of the stored frame in message_size
+        frag_queue.message_size = message_size;
+        --frag_queue.header.reserved;
+          
+IF_SERIAL_DEBUG_FRAGMENTATION_L2(  for(int i=0; i<frag_queue.message_size;i++){  Serial.println(frag_queue.message_buffer[i],HEX);  } );
+        
+        return true;        
+
+    }else // NETWORK_MORE_FRAGMENTS 
+    if(header->type == NETWORK_LAST_FRAGMENT || header->type == NETWORK_MORE_FRAGMENTS || header->type == NETWORK_MORE_FRAGMENTS_NACK){
+        
+        if(frag_queue.message_size + message_size > MAX_PAYLOAD_SIZE){
+          #if defined (SERIAL_DEBUG_FRAGMENTATION) || defined (SERIAL_DEBUG_MINIMAL)
+          Serial.print(F("Drop frag ")); Serial.print(header->reserved);          
+          Serial.println(F(" Size exceeds max"));
+          #endif
+          frag_queue.header.reserved=0;
+          return false;
+        }
+        if(  frag_queue.header.reserved == 0 || (header->type != NETWORK_LAST_FRAGMENT && header->reserved != frag_queue.header.reserved ) || frag_queue.header.id != header->id ){
+            #if defined (SERIAL_DEBUG_FRAGMENTATION) || defined (SERIAL_DEBUG_MINIMAL)
+            Serial.print(F("Drop frag ")); Serial.print(header->reserved);
+            //Serial.print(F(" header id ")); Serial.print(header->id);
+            Serial.println(F(" Out of order "));
+            #endif
+            return false;
+        }
+        
+        memcpy(frag_queue.message_buffer+frag_queue.message_size,frame_buffer+sizeof(RF24NetworkHeader),message_size);
+        frag_queue.message_size += message_size;
+        
+        if(header->type != NETWORK_LAST_FRAGMENT){
+          --frag_queue.header.reserved;
+          return true;
+        }
+        frag_queue.header.reserved = 0;
+        frag_queue.header.type = header->reserved;
+        
+IF_SERIAL_DEBUG_FRAGMENTATION( printf(PSTR("fq 3: %d\n"),frag_queue.message_size); );
+IF_SERIAL_DEBUG_FRAGMENTATION_L2(for(int i=0; i< frag_queue.message_size;i++){ Serial.println(frag_queue.message_buffer[i],HEX); }  );      
+    
+        //Frame assembly complete, copy to main buffer if OK        
+        if(frag_queue.header.type == EXTERNAL_DATA_TYPE){
+           return 2;
+        }
+        #if defined (DISABLE_USER_PAYLOADS)
+          return 0;
+        #endif
+            
+        if(MAX_PAYLOAD_SIZE - (next_frame-frame_queue) >= frag_queue.message_size){
+          memcpy(next_frame,&frag_queue,10);
+          memcpy(next_frame+10,frag_queue.message_buffer,frag_queue.message_size);
+          next_frame += (10+frag_queue.message_size);
+          IF_SERIAL_DEBUG_FRAGMENTATION( printf(PSTR("enq size %d\n"),frag_queue.message_size); );
+          return true;
+        }else{
+          radio.stopListening();
+          networkFlags |= FLAG_HOLD_INCOMING;          
+        }
+        IF_SERIAL_DEBUG_FRAGMENTATION( printf(PSTR("Drop frag payload, queue full\n")); );
+        return false;
+    }//If more or last fragments
+
+  }else //else is not a fragment
+ #endif // End fragmentation enabled
 
   // 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; 
+
+#if !defined( DISABLE_FRAGMENTATION )
 
+    if(header->type == EXTERNAL_DATA_TYPE){
+        memcpy(&frag_queue,&frame_buffer,8);
+        frag_queue.message_buffer = frame_buffer+sizeof(RF24NetworkHeader);
+        frag_queue.message_size = message_size;
+        return 2;
+    }
+#endif      
+#if defined (DISABLE_USER_PAYLOADS)
+    return 0;
+ }
+#else
+  if(message_size + (next_frame-frame_queue) <= MAIN_BUFFER_SIZE){
+    memcpy(next_frame,&frame_buffer,8);
+    RF24NetworkFrame *f = (RF24NetworkFrame*)next_frame;
+    f->message_size = message_size;
+    memcpy(next_frame+10,frame_buffer+sizeof(RF24NetworkHeader),message_size);
+
+    IF_SERIAL_DEBUG_FRAGMENTATION( for(int i=0; i<message_size;i++){ Serial.print(next_frame[i],HEX); Serial.print(" : "); } Serial.println(""); );
+    
+    next_frame += (message_size + 10);
+  IF_SERIAL_DEBUG_FRAGMENTATION( Serial.print("Enq "); Serial.println(next_frame-frame_queue); );//printf_P(PSTR("enq %d\n"),next_frame-frame_queue); );
+  
     result = true;
-    //IF_SERIAL_DEBUG(printf_P(PSTR("ok\n\r")));
+  }else{
+    result = false;
+    IF_SERIAL_DEBUG(printf_P(PSTR("NET **Drop Payload** Buffer Full")));
   }
-  else
-  {
-    //IF_SERIAL_DEBUG(printf_P(PSTR("failed\n\r")));
-  }
-
   return result;
 }
+#endif //USER_PAYLOADS_ENABLED
+
 
 /******************************************************************/
 
 bool RF24Network::available(void)
 {
+
+
+
   // Are there frames on the queue for us?
   return (next_frame > frame_queue);
-}
-
-/******************************************************************/
-
-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)
+uint16_t RF24Network::parent() const
 {
-  size_t bufsize = 0;
+  if ( node_address == 0 )
+    return -1;
+  else
+    return parent_node;
+}
 
+/******************************************************************/
+/*uint8_t RF24Network::peekData(){
+        
+        return frame_queue[0];
+}*/
+
+uint16_t RF24Network::peek(RF24NetworkHeader& header)
+{
   if ( available() )
   {
-    // Move the pointer back one in the queue 
-    next_frame -= frame_size;
-    uint8_t* frame = next_frame;
+
+  
+  
+  
+  
+    RF24NetworkFrame *frame = (RF24NetworkFrame*)(frame_queue);
+    memcpy(&header,&frame->header,sizeof(RF24NetworkHeader));
+    return frame->message_size;
+
+  }
+  return 0;
+}
+
+/******************************************************************/
+
+uint16_t RF24Network::read(RF24NetworkHeader& header,void* message, uint16_t maxlen)
+{
+  uint16_t bufsize = 0;
+
+
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  if ( available() )
+  {
+    
+    memcpy(&header,frame_queue,8);
+    RF24NetworkFrame *f = (RF24NetworkFrame*)frame_queue;
+    bufsize = f->message_size;
+
+    if (maxlen > 0)
+    {       
+        maxlen = min(maxlen,bufsize);
+        memcpy(message,frame_queue+10,maxlen);
+        IF_SERIAL_DEBUG(printf("%lu: NET message size %d\n",millis(),bufsize););
+
+    
+    IF_SERIAL_DEBUG( uint16_t len = maxlen; printf_P(PSTR("%lu: NET r message "),millis());const uint8_t* charPtr = reinterpret_cast<const uint8_t*>(message);while(len--){ printf("%02x ",charPtr[len]);} printf_P(PSTR("\n\r") ) );      
       
-    // How much buffer size should we actually copy?
-    bufsize = min(maxlen,frame_size-sizeof(RF24NetworkHeader));
+    }
+    memmove(frame_queue,frame_queue+bufsize+10,sizeof(frame_queue)- bufsize);
+    next_frame-=bufsize+10;
 
-    // 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;
 }
 
+
+#if defined RF24NetworkMulticast
+/******************************************************************/
+bool RF24Network::multicast(RF24NetworkHeader& header,const void* message, uint16_t len, uint8_t level){
+    // Fill out the header
+  header.to_node = 0100;
+  header.from_node = node_address;
+  return write(header, message, len, levelToAddress(level));
+}
+#endif
+
+/******************************************************************/
+bool RF24Network::write(RF24NetworkHeader& header,const void* message, uint16_t len){    
+    return write(header,message,len,070);
+}
+/******************************************************************/
+bool RF24Network::write(RF24NetworkHeader& header,const void* message, uint16_t len, uint16_t writeDirect){
+    
+    //Allows time for requests (RF24Mesh) to get through between failed writes on busy nodes
+    while(rf24netTimer.read_ms()-txTime < 25){ if(update() > 127){break;} }
+    wait_us(200);
+
+#if defined (DISABLE_FRAGMENTATION)
+    frame_size = rf24_min(len+sizeof(RF24NetworkHeader),MAX_FRAME_SIZE);
+    return _write(header,message,rf24_min(len,max_frame_payload_size),writeDirect);
+#else  
+  if(len <= max_frame_payload_size){
+    //Normal Write (Un-Fragmented)
+    frame_size = len + sizeof(RF24NetworkHeader);
+    if(_write(header,message,len,writeDirect)){
+      return 1;
+    }
+    txTime = rf24netTimer.read_ms();
+    return 0;
+  }
+  //Check payload size
+  if (len > MAX_PAYLOAD_SIZE) {
+    IF_SERIAL_DEBUG(printf("%u: NET write message failed. Given 'len' %d is bigger than the MAX Payload size %i\n\r",millis(),len,MAX_PAYLOAD_SIZE););
+    return false;
+  }
+
+  //Divide the message payload into chunks of max_frame_payload_size
+  uint8_t fragment_id = (len % max_frame_payload_size != 0) + ((len ) / max_frame_payload_size);  //the number of fragments to send = ceil(len/max_frame_payload_size)
+
+  uint8_t msgCount = 0;
+
+  IF_SERIAL_DEBUG_FRAGMENTATION(printf("%lu: FRG Total message fragments %d\n\r",millis(),fragment_id););
+  
+  if(header.to_node != 0100){
+    networkFlags |= FLAG_FAST_FRAG;
+    #if !defined (DUAL_HEAD_RADIO)
+    radio.stopListening();
+    #endif
+  }
+
+  uint8_t retriesPerFrag = 0;
+  uint8_t type = header.type;
+
+  while (fragment_id > 0) {
+
+    //Copy and fill out the header
+    //RF24NetworkHeader fragmentHeader = header;
+   header.reserved = fragment_id;
+
+    if (fragment_id == 1) {
+      header.type = NETWORK_LAST_FRAGMENT;  //Set the last fragment flag to indicate the last fragment
+      header.reserved = type; //The reserved field is used to transmit the header type
+    } else {
+      if (msgCount == 0) {
+        header.type = NETWORK_FIRST_FRAGMENT;
+      }else{
+        header.type = NETWORK_MORE_FRAGMENTS; //Set the more fragments flag to indicate a fragmented frame
+      }
+    }
+    
+    uint16_t offset = msgCount*max_frame_payload_size;
+    uint16_t fragmentLen = rf24_min((uint16_t)(len-offset),max_frame_payload_size);
+
+    //Try to send the payload chunk with the copied header
+    frame_size = sizeof(RF24NetworkHeader)+fragmentLen;
+    bool ok = _write(header,((char *)message)+offset,fragmentLen,writeDirect);
+    
+    if (!ok) {
+       wait_ms(2);
+       ++retriesPerFrag;
+
+    }else{
+      retriesPerFrag = 0;
+      fragment_id--;
+      msgCount++;
+    }
+    
+    if(writeDirect != 070){ wait_ms(2); } //Delay 2ms between sending multicast payloads
+ 
+    if (!ok && retriesPerFrag >= 3) {
+        IF_SERIAL_DEBUG_FRAGMENTATION(printf("%lu: FRG TX with fragmentID '%d' failed after %d fragments. Abort.\n\r",millis(),fragment_id,msgCount););
+        break;
+    }
+
+    
+    //Message was successful sent
+    #if defined SERIAL_DEBUG_FRAGMENTATION_L2 
+      printf("%lu: FRG message transmission with fragmentID '%d' sucessfull.\n\r",millis(),fragment_id);
+    #endif
+
+  }
+
+  #if !defined (DUAL_HEAD_RADIO)
+  if(networkFlags & FLAG_FAST_FRAG){
+    radio.startListening();
+  }
+  #endif
+  networkFlags &= ~FLAG_FAST_FRAG
+  //int frag_delay = uint8_t(len/48);
+  //delay( rf24_min(len/48,20));
+
+  //Return true if all the chunks where sent successfully
+ 
+  IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: FRG total message fragments sent %i. \n",millis(),msgCount); );
+  if(fragment_id > 0){
+    txTime = rf24netTimer.read_ms();
+    return false;
+  }
+  return true;
+  
+#endif //Fragmentation enabled
+}
 /******************************************************************/
 
-bool RF24Network::write(RF24NetworkHeader& header,const void* message, size_t len)
+bool RF24Network::_write(RF24NetworkHeader& header,const void* message, uint16_t len, uint16_t writeDirect)
 {
   // 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(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));
+  
+  
+  
+  
+    
+    memcpy(frame_buffer + sizeof(RF24NetworkHeader),message,len);
+    
+    IF_SERIAL_DEBUG(uint16_t tmpLen = len;printf_P(PSTR("%lu: NET message "),millis());const uint8_t* charPtr = reinterpret_cast<const uint8_t*>(message);while(tmpLen--){ printf("%02x ",charPtr[tmpLen]);} printf_P(PSTR("\n\r") ) );
+
   }
 
   // If the user is trying to send it to himself
-  if ( header.to_node == node_address )
+  /*if ( header.to_node == node_address ){
+    #if defined (RF24_LINUX)
+      RF24NetworkFrame frame = RF24NetworkFrame(header,message,rf24_min(MAX_FRAME_SIZE-sizeof(RF24NetworkHeader),len)); 
+    #else
+      RF24NetworkFrame frame(header,len);
+    #endif
     // Just queue it in the received queue
-    return enqueue();
-  else
-    // Otherwise send it out over the air
-    return write(header.to_node);
+    return enqueue(frame);
+  }*/
+    // Otherwise send it out over the air   
+    
+    
+    if(writeDirect != 070){     
+        uint8_t sendType = USER_TX_TO_LOGICAL_ADDRESS; // Payload is multicast to the first node, and routed normally to the next
+        
+        if(header.to_node == 0100){
+          sendType = USER_TX_MULTICAST;
+        }
+        if(header.to_node == writeDirect){
+          sendType = USER_TX_TO_PHYSICAL_ADDRESS; // Payload is multicast to the first node, which is the recipient
+        }
+        return write(writeDirect,sendType);             
+    }
+    return write(header.to_node,TX_NORMAL);
+    
 }
 
 /******************************************************************/
 
-bool RF24Network::write(uint16_t to_node)
+bool RF24Network::write(uint16_t to_node, uint8_t directTo)  // Direct To: 0 = First Payload, standard routing, 1=routed payload, 2=directRoute to host, 3=directRoute to Route
 {
   bool ok = false;
+  bool isAckType = false;
+  if(frame_buffer[6] > 64 && frame_buffer[6] < 192 ){ isAckType=true; }
+  
+  /*if( ( (frame_buffer[7] % 2) && frame_buffer[6] == NETWORK_MORE_FRAGMENTS) ){
+    isAckType = 0;
+  }*/
   
   // Throw it away if it's not a valid address
   if ( !is_valid_address(to_node) )
-    return false;
+    return false;  
+  
+  //Load info into our conversion structure, and get the converted address info
+  logicalToPhysicalStruct conversion = { to_node,directTo,0};
+  logicalToPhysicalAddress(&conversion);
+  
+
+  
+  
+  IF_SERIAL_DEBUG(printf_P(PSTR("%lu: MAC Sending to 0%o via 0%o on pipe %x\n\r"),millis(),to_node,conversion.send_node,conversion.send_pipe));
+
+  /**Write it*/
+  ok=write_to_pipe(conversion.send_node, conversion.send_pipe, conversion.multicast);   
+  
+  
+    if(!ok){    
 
-  // First, stop listening so we can talk.
-  //radio.stopListening();
+    
+    
+    
+    IF_SERIAL_DEBUG_ROUTING( printf_P(PSTR("%lu: MAC Send fail to 0%o via 0%o on pipe %x\n\r"),millis(),to_node,conversion.send_node,conversion.send_pipe););
+    }
+
+ 
+    if( directTo == TX_ROUTED && ok && conversion.send_node == to_node && isAckType){
+            
+            RF24NetworkHeader* header = (RF24NetworkHeader*)&frame_buffer;
+            header->type = NETWORK_ACK;                 // Set the payload type to NETWORK_ACK          
+            header->to_node = header->from_node;          // Change the 'to' address to the 'from' address          
+
+            conversion.send_node = header->from_node;
+            conversion.send_pipe = TX_ROUTED;
+            conversion.multicast = 0;
+            logicalToPhysicalAddress(&conversion);
+            
+            //Write the data using the resulting physical address
+            frame_size = sizeof(RF24NetworkHeader);
+            write_to_pipe(conversion.send_node, conversion.send_pipe, conversion.multicast);
+            
+            //dynLen=0;
 
-  // 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_SERIAL_DEBUG_ROUTING( printf_P(PSTR("%lu MAC: Route OK to 0%o ACK sent to 0%o\n"),millis(),to_node,header->from_node); );
+
+    }
+ 
+
+
+    if( ok && conversion.send_node != to_node && (directTo==0 || directTo==3) && isAckType){
+        #if !defined (DUAL_HEAD_RADIO)
+          // Now, continue listening
+          if(networkFlags & FLAG_FAST_FRAG){
+             radio.txStandBy(txTimeout);
+             networkFlags &= ~FLAG_FAST_FRAG;
+          }
+          radio.startListening();
+        #endif
+        uint32_t reply_time = rf24netTimer.read_ms(); 
 
-    // To its listening pipe
-    send_pipe = 0;
+        while( update() != NETWORK_ACK){
+            wait_us(900);
+            if(rf24netTimer.read_ms() - reply_time > routeTimeout){
+
+            
+            
+                  IF_SERIAL_DEBUG_ROUTING( printf_P(PSTR("%lu: MAC Network ACK fail from 0%o via 0%o on pipe %x\n\r"),millis(),to_node,conversion.send_node,conversion.send_pipe); );
+
+                ok=false;
+                break;                  
+            }
+        }
+    }
+    if( !(networkFlags & FLAG_FAST_FRAG) ){
+       #if !defined (DUAL_HEAD_RADIO)
+         // Now, continue listening
+         radio.startListening();
+       #endif   
+    }
+
+#if defined ENABLE_NETWORK_STATS
+  if(ok == true){
+            ++nOK;
+  }else{    ++nFails;
   }
-  // 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 )
+    // Provided the to_node and directTo option, it will return the resulting node and pipe
+bool RF24Network::logicalToPhysicalAddress(logicalToPhysicalStruct *conversionInfo){
+
+  //Create pointers so this makes sense.. kind of
+  //We take in the to_node(logical) now, at the end of the function, output the send_node(physical) address, etc.
+  //back to the original memory address that held the logical information.
+  uint16_t *to_node = &conversionInfo->send_node;
+  uint8_t *directTo = &conversionInfo->send_pipe;
+  bool *multicast = &conversionInfo->multicast;    
+  
+  // Where do we send this?  By default, to our parent
+  uint16_t pre_conversion_send_node = parent_node; 
+
+  // On which pipe
+  uint8_t pre_conversion_send_pipe = parent_pipe %5;
+  
+ if(*directTo > TX_ROUTED ){    
+    pre_conversion_send_node = *to_node;
+    *multicast = 1;
+    //if(*directTo == USER_TX_MULTICAST || *directTo == USER_TX_TO_PHYSICAL_ADDRESS){
+        pre_conversion_send_pipe=0;
+    //} 
+  }     
+  // If the node is a direct child,
+  else
+  if ( is_direct_child(*to_node) )
+  {   
+    // Send directly
+    pre_conversion_send_node = *to_node;
+    // To its listening pipe
+    pre_conversion_send_pipe = 5;
+  }
+  // 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) )
+  {
+    pre_conversion_send_node = direct_child_route_to(*to_node);
+    pre_conversion_send_pipe = 5;
+  }
+  
+  *to_node = pre_conversion_send_node;
+  *directTo = pre_conversion_send_pipe;
+  
+  return 1;
+  
+}
+
+/********************************************************/
+
+
+bool RF24Network::write_to_pipe( uint16_t node, uint8_t pipe, bool multicast )
 {
   bool ok = false;
+  uint64_t out_pipe = pipe_address( node, pipe );
   
-  uint64_t out_pipe = pipe_address( node, pipe );
- 
-  // Open the correct pipe for writing.  
-  radio.openWritingPipe(out_pipe);
+  #if !defined (DUAL_HEAD_RADIO)
+  // Open the correct pipe for writing.
+  // First, stop listening so we can talk
 
-  // Retry a few times
-  short attempts = 5;
-  do
-  {
-    ok = radio.write( frame_buffer, frame_size );
+  if(!(networkFlags & FLAG_FAST_FRAG)){
+    radio.stopListening();
   }
-  while ( !ok && --attempts );
+  
+  if(multicast){ radio.setAutoAck(0,0);}else{radio.setAutoAck(0,1);}
+  
+  radio.openWritingPipe(out_pipe);
+  radio.writeFast(frame_buffer, frame_size,multicast);
+  ok = radio.txStandBy(txTimeout);
+  
+  radio.setAutoAck(0,0);
+  
+#else
+  radio1.openWritingPipe(out_pipe);
+  radio1.writeFast(frame_buffer, frame_size);
+  ok = radio1.txStandBy(txTimeout,multicast);
 
-  //IF_SERIAL_DEBUG(printf_P(PSTR("%lu: MAC Sent on %lx %S\n\r"),millis(),(uint32_t)out_pipe,ok?PSTR("ok"):PSTR("failed")));
+#endif
+
+
 
+
+  IF_SERIAL_DEBUG(printf_P(PSTR("%lu: MAC Sent on %lx %S\n\r"),rf24netTimer.read_ms(),(uint32_t)out_pipe,ok?PSTR("ok"):PSTR("failed")));
+
+  
   return ok;
 }
 
@@ -288,7 +1040,8 @@
 const char* RF24NetworkHeader::toString(void) const
 {
   static char buffer[45];
-  //snprintf_P(buffer,sizeof(buffer),("id %04x from 0%o to 0%o type %c"),id,from_node,to_node,type);
+  //snprintf_P(buffer,sizeof(buffer),PSTR("id %04x from 0%o to 0%o type %c"),id,from_node,to_node,type);
+  sprintf(buffer,PSTR("id %u from 0%o to 0%o type %d"),id,from_node,to_node,type);
   return buffer;
 }
 
@@ -311,7 +1064,6 @@
     uint16_t child_node_mask = ( ~ node_mask ) << 3;
     result = ( node & child_node_mask ) == 0 ;
   }
-
   return result;
 }
 
@@ -327,9 +1079,20 @@
 void RF24Network::setup_address(void)
 {
   // First, establish the node_mask
-  uint16_t node_mask_check = 0xFFFF;
-  while ( node_address & node_mask_check )
+  uint16_t node_mask_check = 0xFFFF;  
+  #if defined (RF24NetworkMulticast)
+  uint8_t count = 0;
+  #endif
+  
+  while ( node_address & node_mask_check ){
     node_mask_check <<= 3;
+  #if defined (RF24NetworkMulticast)
+      count++;
+  }
+  multicast_level = count;
+  #else
+  }
+  #endif
   
   node_mask = ~ node_mask_check;
 
@@ -349,9 +1112,24 @@
   }
   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
+  IF_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););
+
+}
+
+/******************************************************************/
+uint16_t RF24Network::addressOfPipe( uint16_t node, uint8_t pipeNo )
+{
+        //Say this node is 013 (1011), mask is 077 or (00111111)
+        //Say we want to use pipe 3 (11)
+        //6 bits in node mask, so shift pipeNo 6 times left and | into address      
+    uint16_t m = node_mask >> 3;
+    uint8_t i=0;
+    
+    while (m){     //While there are bits left in the node mask
+        m>>=1;     //Shift to the right
+        i++;       //Count the # of increments
+    }
+    return node | (pipeNo << i);    
 }
 
 /******************************************************************/
@@ -359,40 +1137,44 @@
 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 ) | 7;
-  return node & child_mask ;
+  return node & child_mask;
+  
 }
 
 /******************************************************************/
-
+/*
 uint8_t RF24Network::pipe_to_descendant( uint16_t node )
 {
-  uint16_t i = node;
+  uint16_t i = node;       
   uint16_t m = node_mask;
-  
+
   while (m)
   {
     i >>= 3;
     m >>= 3;
   }
 
-  return i & 7;
-}
+  return i & 0B111;
+}*/
 
 /******************************************************************/
 
-bool is_valid_address( uint16_t node )
+bool RF24Network::is_valid_address( uint16_t node )
 {
   bool result = true;
 
   while(node)
   {
     uint8_t digit = node & 7;
+    #if !defined (RF24NetworkMulticast)
     if (digit < 1 || digit > 5)
+    #else
+    if (digit < 0 || digit > 5) //Allow our out of range multicast address
+    #endif
     {
       result = false;
-      //printf_P(("*** WARNING *** Invalid address 0%o\n\r"),node);
+      IF_SERIAL_DEBUG_MINIMAL(printf_P(PSTR("*** WARNING *** Invalid address 0%o\n\r"),node););
       break;
     }
     node >>= 3;
@@ -402,39 +1184,133 @@
 }
 
 /******************************************************************/
+#if defined (RF24NetworkMulticast)
+void RF24Network::multicastLevel(uint8_t level){
+  multicast_level = level;
+  //radio.stopListening();  
+  radio.openReadingPipe(0,pipe_address(levelToAddress(level),0));
+  //radio.startListening();
+  }
+  
+uint16_t levelToAddress(uint8_t level){
+    
+    uint16_t levelAddr = 1;
+    if(level){
+        levelAddr = levelAddr << ((level-1) * 3);
+    }else{
+        return 0;       
+    }
+    return levelAddr;
+}  
+#endif
+/******************************************************************/
 
 uint64_t pipe_address( uint16_t node, uint8_t pipe )
 {
-  static uint8_t pipe_segment[] = { 0x3c, 0x5a, 0x69, 0x96, 0xa5, 0xc3 };
-
-  uint64_t result;
+  
+  static uint8_t address_translation[] = { 0xc3,0x3c,0x33,0xce,0x3e,0xe3,0xec };
+  uint64_t result = 0xCCCCCCCCCCLL;
   uint8_t* out = reinterpret_cast<uint8_t*>(&result);
-
-  out[0] = pipe_segment[pipe];
+  
+  // Translate the address to use our optimally chosen radio address bytes
+    uint8_t count = 1; uint16_t dec = node;
 
-  uint8_t w; 
-  short i = 4;
-  short shift = 12;
-  while(i--)
-  {
-    w = ( node >> shift ) & 0xF ; 
-    w |= ~w << 4;
-    out[i+1] = w;
+    while(dec){
+      #if defined (RF24NetworkMulticast)
+      if(pipe != 0 || !node)
+      #endif
+        out[count]=address_translation[(dec % 8)];      // Convert our decimal values to octal, translate them to address bytes, and set our address
+      
+      dec /= 8; 
+      count++;
+    }
+    
+    #if defined (RF24NetworkMulticast)
+    if(pipe != 0 || !node)
+    #endif
+      out[0] = address_translation[pipe];
+    #if defined (RF24NetworkMulticast)
+    else
+      out[1] = address_translation[count-1];
+    #endif
 
-    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));
+  
+  
+  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
+
+/************************ Sleep Mode ******************************************/
+
+
+#if defined ENABLE_SLEEP_MODE
+
+#if !defined(__arm__) && !defined(__ARDUINO_X86__)
+
+void wakeUp(){
+  wasInterrupted=true;
+  sleep_cycles_remaining = 0;
+}
+
+ISR(WDT_vect){
+  --sleep_cycles_remaining;
+}
+
+
+bool RF24Network::sleepNode( unsigned int cycles, int interruptPin ){
+
+
+  sleep_cycles_remaining = cycles;
+  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
+  sleep_enable();
+  if(interruptPin != 255){
+    wasInterrupted = false; //Reset Flag
+    attachInterrupt(interruptPin,wakeUp, LOW);
+  }    
+
+
+  
+  
+  WDTCSR |= _BV(WDIE);
+
 
-uint8_t RF24Network::min(uint8_t a, uint8_t b)
-{
-    if(a < b)
-        return a;
-    else
-        return b;
-}
\ No newline at end of file
+  while(sleep_cycles_remaining){
+    sleep_mode();                        // System sleeps here
+  }                                     // The WDT_vect interrupt wakes the MCU from here
+  sleep_disable();                     // System continues execution here when watchdog timed out
+  detachInterrupt(interruptPin);
+
+
+  
+  
+  
+    WDTCSR &= ~_BV(WDIE);
+
+  
+  return !wasInterrupted;
+}
+
+void RF24Network::setup_watchdog(uint8_t prescalar){
+
+  uint8_t wdtcsr = prescalar & 7;
+  if ( prescalar & 8 )
+    wdtcsr |= _BV(WDP3);
+  MCUSR &= ~_BV(WDRF);                      // Clear the WD System Reset Flag
+
+
+  
+  
+  WDTCSR = _BV(WDCE) | _BV(WDE);            // Write the WD Change enable bit to enable changing the prescaler and enable system reset
+  WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE);  // Write the prescalar bits (how long to sleep, enable the interrupt to wake the MCU
+
+}
+
+
+#endif // not ATTiny
+#endif // Enable sleep mode
--- a/RF24Network.h	Mon Jul 06 05:18:22 2015 +0000
+++ b/RF24Network.h	Thu Nov 05 05:40:44 2015 +0000
@@ -14,9 +14,172 @@
  *
  * Class declaration for RF24Network
  */
-
+#define min(a,b) (a<b?a:b)
 #include <stddef.h>
 #include <stdint.h>
+#include "RF24Network_config.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* Header types range */
+#define MIN_USER_DEFINED_HEADER_TYPE 0
+#define MAX_USER_DEFINED_HEADER_TYPE 127
+
+/** 
+
+ */
+ 
+// ACK Response Types
+/**
+ * **Reserved network message types**
+ *
+ * The network will determine whether to automatically acknowledge payloads based on their general type <br>
+ * 
+ * **User types** (1-127) 1-64 will NOT be acknowledged <br>
+ * **System types** (128-255) 192 through 255 will NOT be acknowledged<br>
+ *
+ * @defgroup DEFINED_TYPES Reserved System Message Types
+ *
+ * System types can also contain message data.
+ *
+ * @{
+ */
+
+/**
+* A NETWORK_ADDR_RESPONSE type is utilized to manually route custom messages containing a single RF24Network address
+* 
+* Used by RF24Mesh
+* 
+* If a node receives a message of this type that is directly addressed to it, it will read the included message, and forward the payload
+* on to the proper recipient. <br>
+* This allows nodes to forward multicast messages to the master node, receive a response, and forward it back to the requester.
+*/
+#define NETWORK_ADDR_RESPONSE 128 
+//#define NETWORK_ADDR_CONFIRM 129
+
+/**
+* Messages of type NETWORK_PING will be dropped automatically by the recipient. A NETWORK_ACK or automatic radio-ack will indicate to the sender whether the 
+* payload was successful. The time it takes to successfully send a NETWORK_PING is the round-trip-time.
+*/
+#define NETWORK_PING 130
+
+/**
+ * External data types are used to define messages that will be passed to an external data system. This allows RF24Network to route and pass any type of data, such 
+ * as TCP/IP frames, while still being able to utilize standard RF24Network messages etc.
+ *
+ * **Linux**
+ * Linux devices (defined RF24_LINUX) will buffer all data types in the user cache. 
+ *
+ * **Arduino/AVR/Etc:** Data transmitted with the type set to EXTERNAL_DATA_TYPE will not be loaded into the user cache. <br>
+ * External systems can extract external data using the following process, while internal data types are cached in the user buffer, and accessed using network.read() :
+ * @code
+ * uint8_t return_type = network.update();
+ * if(return_type == EXTERNAL_DATA_TYPE){
+ *     uint16_t size = network.frag_ptr->message_size;  
+ *     memcpy(&myDataBuffer,network.frag_ptr->message_buffer,network.frag_ptr->message_size);
+ * }        
+ * @endcode
+ */
+#define EXTERNAL_DATA_TYPE 131
+
+/**
+ * Messages of this type designate the first of two or more message fragments, and will be re-assembled automatically.
+ */
+#define NETWORK_FIRST_FRAGMENT 148
+
+/**
+ * Messages of this type indicate a fragmented payload with two or more message fragments.
+ */
+#define NETWORK_MORE_FRAGMENTS 149
+
+/**
+ * Messages of this type indicate the last fragment in a sequence of message fragments.
+ * Messages of this type do not receive a NETWORK_ACK
+ */
+#define NETWORK_LAST_FRAGMENT 150 
+//#define NETWORK_LAST_FRAGMENT 201
+
+// NO ACK Response Types
+//#define NETWORK_ACK_REQUEST 192
+
+/**
+ * Messages of this type are used internally, to signal the sender that a transmission has been completed.
+ * RF24Network does not directly have a built-in transport layer protocol, so message delivery is not 100% guaranteed.<br>
+ * Messages can be lost via corrupted dynamic payloads, or a NETWORK_ACK can fail, while the message was actually successful.
+ * 
+ * NETWORK_ACK messages can be utilized as a traffic/flow control mechanism, since transmitting nodes will be forced to wait until
+ * the payload is transmitted across the network and acknowledged, before sending additional data. 
+ *
+ * In the event that the transmitting device will be waiting for a direct response, manually sent by the recipient, a NETWORK_ACK is not required. <br>
+ * User messages utilizing a 'type' with a decimal value of 64 or less will not be acknowledged across the network via NETWORK_ACK messages.
+ */
+#define NETWORK_ACK 193
+
+/**
+ * Used by RF24Mesh
+ *
+ * Messages of this type are used with multi-casting , to find active/available nodes.
+ * Any node receiving a NETWORK_POLL sent to a multicast address will respond directly to the sender with a blank message, indicating the
+ * address of the available node via the header.
+ */ 
+#define NETWORK_POLL 194
+
+/**
+ * Used by RF24Mesh
+ *
+ * Messages of this type are used to request information from the master node, generally via a unicast (direct) write.
+ * Any (non-master) node receiving a message of this type will manually forward it to the master node using an normal network write.
+ */
+#define NETWORK_REQ_ADDRESS 195
+//#define NETWORK_ADDR_LOOKUP 196
+//#define NETWORK_ADDR_RELEASE 197
+/** @} */
+
+#define NETWORK_MORE_FRAGMENTS_NACK 200
+
+
+/** Internal defines for handling written payloads */
+#define TX_NORMAL 0
+#define TX_ROUTED 1
+#define USER_TX_TO_PHYSICAL_ADDRESS 2  //no network ACK
+#define USER_TX_TO_LOGICAL_ADDRESS 3   // network ACK
+#define USER_TX_MULTICAST 4
+
+#define MAX_FRAME_SIZE 32   //Size of individual radio frames
+#define FRAME_HEADER_SIZE 10 //Size of RF24Network frames - data
+
+#define USE_CURRENT_CHANNEL 255 // Use current radio channel when setting up the network
+
+/** Internal defines for handling internal payloads - prevents reading additional data from the radio
+ * when buffers are full */
+ #define FLAG_HOLD_INCOMING 1
+ /** FLAG_BYPASS_HOLDS is mainly for use with RF24Mesh as follows:
+  * a: Ensure no data in radio buffers, else exit
+  * b: Address is changed to multicast address for renewal
+  * c: Holds Cleared (bypass flag is set)
+  * d: Address renewal takes place and is set
+  * e: Holds Enabled (bypass flag off)
+  */
+ #define FLAG_BYPASS_HOLDS 2
+ 
+ #define FLAG_FAST_FRAG 4
 
 class RF24;
 
@@ -24,40 +187,62 @@
  * Header which is sent with each message
  *
  * The frame put over the air consists of this header and a message
+ *
+ * Headers are addressed to the appropriate node, and the network forwards them on to their final destination.
  */
 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 */
+  uint16_t id; /**< Sequential message ID, incremented every time a new frame is constructed */
+  /**
+   * Message Types:
+   * User message types 1 through 64 will NOT be acknowledged by the network, while message types 65 through 127 will receive a network ACK.  
+   * System message types 192 through 255 will NOT be acknowledged by the network. Message types 128 through 192 will receive a network ACK. <br>
+   * <br><br>
+   */
+  unsigned char type; /**< <b>Type of the packet. </b> 0-127 are user-defined types, 128-255 are reserved for system */
+  
+  /**
+  * During fragmentation, it carries the fragment_id, and on the last fragment
+  * it carries the header_type.<br>
+  */
+  unsigned char reserved; /**< *Reserved for system use* */
 
-  static uint16_t next_id; /**< The message ID of the next message to be sent */
+  static uint16_t next_id; /**< The message ID of the next message to be sent (unused)*/
 
   /**
    * Default constructor
    *
+
    * Simply constructs a blank header
    */
   RF24NetworkHeader() {}
 
   /**
-   * Send constructor
+   * Send constructor  
+   *  
+   * @note Now supports automatic fragmentation for very long messages, which can be sent as usual if fragmentation is enabled. 
    *
-   * Use this constructor to create a header and then send a message
-   *
+   * Fragmentation is enabled by default for all devices except ATTiny <br>
+   * Configure fragmentation and max payload size in RF24Network_config.h
+   *  
+   * Use this constructor to create a header and then send a message  
+   *   
    * @code
+   *  uint16_t recipient_address = 011;
+   *  
    *  RF24NetworkHeader header(recipient_address,'t');
+   *  
    *  network.write(header,&message,sizeof(message));
    * @endcode
    *
-   * @param _to The logical node address where the message is going
+   * @param _to The Octal format, logical node address where the message is going
    * @param _type The type of message which follows.  Only 0-127 are allowed for
-   * user messages.
+   * user messages. Types 1-64 will not receive a network acknowledgement.
    */
-  RF24NetworkHeader(uint16_t _to, unsigned char _type = 0): to_node(_to), id(next_id++), type(_type&0x7f) {}
 
+  RF24NetworkHeader(uint16_t _to, unsigned char _type = 0): to_node(_to), id(next_id++), type(_type) {}
   /**
    * Create debugging string
    *
@@ -70,8 +255,92 @@
   const char* toString(void) const;
 };
 
+
 /**
- * Network Layer for RF24 Radios
+ * Frame structure for internal message handling, and for use by external applications
+ *
+ * The actual frame put over the air consists of a header (8-bytes) and a message payload (Up to 24-bytes)<br>
+ * When data is received, it is stored using the RF24NetworkFrame structure, which includes:
+ * 1. The header 
+ * 2. The size of the included message 
+ * 3. The 'message' or data being received
+ * 
+ *
+ */
+
+
+ struct RF24NetworkFrame
+{
+  RF24NetworkHeader header; /**< Header which is sent with each message */
+  uint16_t message_size; /**< The size in bytes of the payload length */
+  
+  /**
+  * On Arduino, the message buffer is just a pointer, and can be pointed to any memory location.
+  * On Linux the message buffer is a standard byte array, equal in size to the defined MAX_PAYLOAD_SIZE
+  */
+ 
+ 
+ 
+    uint8_t *message_buffer; //< Pointer to the buffer storing the actual message 
+
+  /**
+   * Default constructor
+   *
+   * Simply constructs a blank frame. Frames are generally used internally. See RF24NetworkHeader.
+   */
+  //RF24NetworkFrame() {}
+  
+  RF24NetworkFrame() {}
+  /**
+   * Constructor - create a network frame with data
+   * Frames are constructed and handled differently on Arduino/AVR and Linux devices (defined RF24_LINUX)
+   *
+   * <br>
+   * **Linux:**
+   * @param _header The RF24Network header to be stored in the frame
+   * @param _message The 'message' or data.
+   * @param _len The size of the 'message' or data.
+   *
+   * <br>
+   * **Arduino/AVR/Etc.**
+   * @see RF24Network.frag_ptr
+   * @param _header The RF24Network header to be stored in the frame
+   * @param _message_size The size of the 'message' or data
+   * 
+   *
+   * Frames are used internally and by external systems. See RF24NetworkHeader.
+   */
+
+   
+   
+   
+   
+   
+   
+   
+  RF24NetworkFrame(RF24NetworkHeader &_header, uint16_t _message_size):
+                  header(_header), message_size(_message_size){       
+  }
+
+  
+
+  /**
+   * 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;
+
+};
+
+ 
+
+/**
+ * 2014-2015 - Optimized Network Layer for RF24 Radios
  *
  * This class implements an OSI Network Layer using nRF24L01(+) radios driven
  * by RF24 library.
@@ -79,6 +348,15 @@
 
 class RF24Network
 {
+private:
+  Timer rf24netTimer; 
+  /**@}*/
+  /**
+   * @name Primary Interface
+   *
+   *  These are the main methods you need to operate the network
+   */
+  /**@{*/  
 public:
   /**
    * Construct the network
@@ -86,33 +364,56 @@
    * @param _radio The underlying radio driver instance
    *
    */
+
   RF24Network( RF24& _radio );
 
   /**
-   * Bring up the network
-   *
+   * Bring up the network using the current radio frequency/channel.
+   * Calling begin brings up the network, and configures the address, which designates the location of the node within RF24Network topology.
+   * @note Node addresses are specified in Octal format, see <a href=Addressing.html>RF24Network Addressing</a> for more information.
    * @warning Be sure to 'begin' the radio first.
    *
-   * @param _channel The RF channel to operate on
+   * **Example 1:** Begin on current radio channel with address 0 (master node)
+   * @code
+   * network.begin(00);
+   * @endcode
+   * **Example 2:** Begin with address 01 (child of master)
+   * @code
+   * network.begin(01);
+   * @endcode
+   * **Example 3:** Begin with address 011 (child of 01, grandchild of master)
+   * @code
+   * network.begin(011);
+   * @endcode   
+   *
+   * @see begin(uint8_t _channel, uint16_t _node_address )
    * @param _node_address The logical address of this node
+   *
    */
-  void begin(uint8_t _channel, uint16_t _node_address );
-  
+   
+  inline void begin(uint16_t _node_address){
+      begin(USE_CURRENT_CHANNEL,_node_address);
+  }
+
   /**
    * Main layer loop
    *
-   * This function must be called regularly to keep the layer going.  This is where all
-   * the action happens!
+   * This function must be called regularly to keep the layer going.  This is where payloads are 
+   * re-routed, received, and all the action happens.
+   *
+   * @see
+   * 
+   * @return Returns the type of the last received payload.
    */
-  void update(void);
+  uint8_t 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
    *
@@ -123,59 +424,428 @@
    *
    * @param[out] header The header (envelope) of the next message
    */
-  void peek(RF24NetworkHeader& header);
+  uint16_t peek(RF24NetworkHeader& header);
 
   /**
    * Read a message
    *
+   * @code
+   * while ( network.available() )  {
+   *   RF24NetworkHeader header;
+   *   uint32_t time;
+   *   network.peek(header);
+   *   if(header.type == 'T'){
+   *     network.read(header,&time,sizeof(time));
+   *     Serial.print("Got time: ");
+   *     Serial.println(time);
+   *   }
+   * }
+   * @endcode
    * @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);
-  
+  uint16_t read(RF24NetworkHeader& header, void* message, uint16_t maxlen);
+
   /**
    * Send a message
    *
+   * @note RF24Network now supports fragmentation for very long messages, send as normal. Fragmentation
+   * may need to be enabled or configured by editing the RF24Network_config.h file. Default max payload size is 120 bytes.
+   * 
+   * @code
+   * uint32_t time = millis();
+   * uint16_t to = 00; // Send to master
+   * RF24NetworkHeader header(to, 'T'); // Send header type 'T'
+   * network.write(header,&time,sizeof(time));
+   * @endcode
    * @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 
+   * @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, uint16_t len);
+
+  /**@}*/
+  /**
+   * @name Advanced Configuration
+   *
+   *  For advanced configuration of the network
+   */
+  /**@{*/
+  
+
+   /**
+   * Construct the network in dual head mode using two radio modules.
+   * @note Not working on RPi. Radios will share MISO, MOSI and SCK pins, but require separate CE,CS pins.
+   * @code
+   *    RF24 radio(7,8);
+   *    RF24 radio1(4,5);
+   *    RF24Network(radio.radio1);
+   * @endcode
+   * @param _radio The underlying radio driver instance
+   * @param _radio1 The second underlying radio driver instance
+   */
+   
+  RF24Network( RF24& _radio, RF24& _radio1); 
+  
+    /**
+    * By default, multicast addresses are divided into levels. 
+    *
+    * Nodes 1-5 share a multicast address, nodes n1-n5 share a multicast address, and nodes n11-n55 share a multicast address.<br>
+    *
+    * This option is used to override the defaults, and create custom multicast groups that all share a single
+    * address. <br> 
+    * The level should be specified in decimal format 1-6 <br>
+    * @see multicastRelay
+    * @param level Levels 1 to 6 are available. All nodes at the same level will receive the same
+    * messages if in range. Messages will be routed in order of level, low to high by default, with the
+    * master node (00) at multicast Level 0
+    */
+    
+    void multicastLevel(uint8_t level);
+
+    /**
+    * Enabling this will allow this node to automatically forward received multicast frames to the next highest
+    * multicast level. Duplicate frames are filtered out, so multiple forwarding nodes at the same level should
+    * not interfere. Forwarded payloads will also be received.
+    * @see multicastLevel
+    */
+    
+    bool multicastRelay;
+
+ /**
+   * Set up the watchdog timer for sleep mode using the number 0 through 10 to represent the following time periods:<br>
+   * wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms, wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s
+   * @code
+   *    setup_watchdog(7);   // Sets the WDT to trigger every second
+   * @endcode
+   * @param prescalar The WDT prescaler to define how often the node will wake up. When defining sleep mode cycles, this time period is 1 cycle.
    */
-  bool write(RF24NetworkHeader& header,const void* message, size_t len);
+ void setup_watchdog(uint8_t prescalar);
+
+    /**
+   * @note: This value is automatically assigned based on the node address
+   * to reduce errors and increase throughput of the network.
+   *
+   * Sets the timeout period for individual payloads in milliseconds at staggered intervals.
+   * Payloads will be retried automatically until success or timeout
+   * Set to 0 to use the normal auto retry period defined by radio.setRetries()
+   *
+   */
+
+  uint32_t txTimeout; /**< Network timeout value */
+  
+  /**
+   * This only affects payloads that are routed by one or more nodes.
+   * This specifies how long to wait for an ack from across the network.
+   * Radios sending directly to their parent or children nodes do not
+   * utilize this value.
+   */
+  
+   uint16_t routeTimeout; /**< Timeout for routed payloads */  
+  
+ 
+  /**@}*/
+  /**
+   * @name Advanced Operation
+   *
+   *  For advanced operation of the network
+   */
+  /**@{*/
+
+  /**
+   * Return the number of failures and successes for all transmitted payloads, routed or sent directly  
+   * @note This needs to be enabled via #define ENABLE_NETWORK_STATS in RF24Network_config.h
+   *
+   *   @code  
+   * bool fails, success;  
+   * network.failures(&fails,&success);  
+   * @endcode  
+   *
+   */
+  void failures(uint32_t *_fails, uint32_t *_ok);
+  
+   #if defined (RF24NetworkMulticast)
+  
+  /**
+   * Send a multicast message to multiple nodes at once
+   * Allows messages to be rapidly broadcast through the network  
+   *   
+   * Multicasting is arranged in levels, with all nodes on the same level listening to the same address  
+   * Levels are assigned by network level ie: nodes 01-05: Level 1, nodes 011-055: Level 2
+   * @see multicastLevel
+   * @see multicastRelay
+   * @param message Pointer to memory where the message is located
+   * @param len The size of the message
+   * @param level Multicast level to broadcast to
+   * @return Whether the message was successfully sent
+   */
+   
+   bool multicast(RF24NetworkHeader& header,const void* message, uint16_t len, uint8_t level);
+   
+    
+   #endif
+   
+   /**
+   * Writes a direct (unicast) payload. This allows routing or sending messages outside of the usual routing paths.
+   * The same as write, but a physical address is specified as the last option.
+   * The payload will be written to the physical address, and routed as necessary by the recipient
+   */
+   bool write(RF24NetworkHeader& header,const void* message, uint16_t len, uint16_t writeDirect);
 
-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);
+   /**
+   * Sleep this node - For AVR devices only
+   * @note NEW - Nodes can now be slept while the radio is not actively transmitting. This must be manually enabled by uncommenting
+   * the #define ENABLE_SLEEP_MODE in RF24Network_config.h
+   * @note Setting the interruptPin to 255 will disable interrupt wake-ups
+   * @note The watchdog timer should be configured in setup() if using sleep mode.
+   * This function will sleep the node, with the radio still active in receive mode.
+   *
+   * The node can be awoken in two ways, both of which can be enabled simultaneously:
+   * 1. An interrupt - usually triggered by the radio receiving a payload. Must use pin 2 (interrupt 0) or 3 (interrupt 1) on Uno, Nano, etc.
+   * 2. The watchdog timer waking the MCU after a designated period of time, can also be used instead of delays to control transmission intervals.
+   * @code
+   * if(!network.available()){ network.sleepNode(1,0); }  //Sleeps the node for 1 second or a payload is received
+   *
+   * Other options:
+   * network.sleepNode(0,0);         // Sleep this node for the designated time period, or a payload is received.
+   * network.sleepNode(1,255);       // Sleep this node for 1 cycle. Do not wake up until then, even if a payload is received ( no interrupt )
+   * @endcode
+   * @see setup_watchdog()
+   * @param cycles: The node will sleep in cycles of 1s. Using 2 will sleep 2 WDT cycles, 3 sleeps 3WDT cycles...
+   * @param interruptPin: The interrupt number to use (0,1) for pins two and three on Uno,Nano. More available on Mega etc.
+   * @return True if sleepNode completed normally, after the specified number of cycles. False if sleep was interrupted
+   */
+ bool sleepNode( unsigned int cycles, int interruptPin );
+
+
+  /**
+   * This node's parent address
+   *
+   * @return This node's parent address, or -1 if this is the base
+   */
+  uint16_t parent() const;
+  
+   /**
+   * Provided a node address and a pipe number, will return the RF24Network address of that child pipe for that node
+   */
+   uint16_t addressOfPipe( uint16_t node,uint8_t pipeNo );
+   
+   /**
+    * @note Addresses are specified in octal: 011, 034
+    * @return True if a supplied address is valid
+    */
+   bool is_valid_address( uint16_t node );
+
+ /**@}*/
+  /**
+   * @name Deprecated
+   *
+   *  Maintained for backwards compatibility
+   */
+  /**@{*/  
+  
+  /**
+   * Bring up the network on a specific radio frequency/channel.
+   * @note Use radio.setChannel() to configure the radio channel
+   *
+   * **Example 1:** Begin on channel 90 with address 0 (master node)
+   * @code
+   * network.begin(90,0);
+   * @endcode
+   * **Example 2:** Begin on channel 90 with address 01 (child of master)
+   * @code
+   * network.begin(90,01);
+   * @endcode
+   * **Example 3:** Begin on channel 90 with address 011 (child of 01, grandchild of master)
+   * @code
+   * network.begin(90,011);
+   * @endcode   
+   *
+   * @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 );  
+  
+  /**@}*/
+  /**
+   * @name External Applications/Systems
+   *
+   *  Interface for External Applications and Systems ( RF24Mesh, RF24Ethernet )
+   */
+  /**@{*/
+  
+  /** The raw system frame buffer of received data. */
+  
+  uint8_t frame_buffer[MAX_FRAME_SIZE];   
+
+  /** 
+   * **Linux** <br>
+   * Data with a header type of EXTERNAL_DATA_TYPE will be loaded into a separate queue.
+   * The data can be accessed as follows:
+   * @code
+   * RF24NetworkFrame f;
+   * while(network.external_queue.size() > 0){
+   *   f = network.external_queue.front();
+   *   uint16_t dataSize = f.message_size;
+   *   //read the frame message buffer
+   *   memcpy(&myBuffer,&f.message_buffer,dataSize);
+   *   network.external_queue.pop();
+   * }
+   * @endcode
+   */
+
+   
+   
+  
+  #if !defined ( DISABLE_FRAGMENTATION ) 
+  /**
+  * **ARDUINO** <br>
+  * The frag_ptr is only used with Arduino (not RPi/Linux) and is mainly used for external data systems like RF24Ethernet. When
+  * an EXTERNAL_DATA payload type is received, and returned from network.update(), the frag_ptr will always point to the starting
+  * memory location of the received frame. <br>This is used by external data systems (RF24Ethernet) to immediately copy the received
+  * data to a buffer, without using the user-cache.
+  * 
+  * @see RF24NetworkFrame
+  * 
+ * @code
+ * uint8_t return_type = network.update();
+ * if(return_type == EXTERNAL_DATA_TYPE){
+ *     uint16_t size = network.frag_ptr->message_size;  
+ *     memcpy(&myDataBuffer,network.frag_ptr->message_buffer,network.frag_ptr->message_size);
+ * }        
+ * @endcode  
+  * Linux devices (defined as RF24_LINUX) currently cache all payload types, and do not utilize frag_ptr. 
+  */
+  RF24NetworkFrame* frag_ptr;
+  #endif
+
+  /**
+  * Variable to determine whether update() will return after the radio buffers have been emptied (DEFAULT), or
+  * whether to return immediately when (most) system types are received. 
+  * 
+  * As an example, this is used with RF24Mesh to catch and handle system messages without loading them into the user cache.
+  *
+  * The following reserved/system message types are handled automatically, and not returned.
+  *
+  * | System Message Types <br> (Not Returned) |
+  * |-----------------------|
+  * | NETWORK_ADDR_RESPONSE |
+  * | NETWORK_ACK           |
+  * | NETWORK_PING          |
+  * | NETWORK_POLL <br>(With multicast enabled) |
+  * | NETWORK_REQ_ADDRESS   |  
+  *
+  */  
+  bool returnSysMsgs;
+
+  /**
+  * Network Flags allow control of data flow
+  *
+  * Incoming Blocking: If the network user-cache is full, lets radio cache fill up. Radio ACKs are not sent when radio internal cache is full.<br>
+  * This behaviour may seem to result in more failed sends, but the payloads would have otherwise been dropped due to the cache being full.<br>
+  * 
+  * | FLAGS | Value | Description |
+  * |-------|-------|-------------|
+  * |FLAG_HOLD_INCOMING| 1(bit_1) | INTERNAL: Set automatically when a fragmented payload will exceed the available cache |
+  * |FLAG_BYPASS_HOLDS| 2(bit_2) | EXTERNAL: Can be used to prevent holds from blocking. Note: Holds are disabled & re-enabled by RF24Mesh when renewing addresses. This will cause data loss if incoming data exceeds the available cache space|
+  * |FLAG_FAST_FRAG| 4(bit_3) | INTERNAL: Replaces the fastFragTransfer variable, and allows for faster transfers between directly connected nodes. |
+  * 
+  */
+  uint8_t networkFlags;
+    
+  private:
+
+  uint32_t txTime;
+
+  bool write(uint16_t, uint8_t directTo);
+  bool write_to_pipe( uint16_t node, uint8_t pipe, bool multicast );
+  uint8_t enqueue(RF24NetworkHeader *header);
 
   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 );
+  //uint8_t pipe_to_descendant( uint16_t node );
   void setup_address(void);
+  bool _write(RF24NetworkHeader& header,const void* message, uint16_t len, uint16_t writeDirect);
+    
+  struct logicalToPhysicalStruct{
+    uint16_t send_node; 
+    uint8_t send_pipe;
+    bool multicast;
+  };
+  
+  bool logicalToPhysicalAddress(logicalToPhysicalStruct *conversionInfo);
+  
+  
+  RF24& radio; /**< Underlying radio driver, provides link/physical layers */
+#if defined (DUAL_HEAD_RADIO)
+  RF24& radio1;
+#endif
+#if defined (RF24NetworkMulticast)  
+  uint8_t multicast_level;  
+#endif
+  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_size;
+  const static unsigned int max_frame_payload_size = MAX_FRAME_SIZE-sizeof(RF24NetworkHeader);
+
 
-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 */
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+    #if !defined (NUM_USER_PAYLOADS)
+      #define NUM_USER_PAYLOADS 5
+    #endif
+      
+    #if defined (DISABLE_USER_PAYLOADS)
+    uint8_t frame_queue[1]; /**< Space for a small set of frames that need to be delivered to the app layer */
+    #else
+    uint8_t frame_queue[MAIN_BUFFER_SIZE]; /**< Space for a small set of frames that need to be delivered to the app layer */
+    #endif
+    
+    uint8_t* next_frame; /**< Pointer into the @p frame_queue where we should place the next received frame */
+    
+    #if !defined ( DISABLE_FRAGMENTATION )
+      RF24NetworkFrame frag_queue;
+      uint8_t frag_queue_message_buffer[MAX_PAYLOAD_SIZE]; //frame size + 1 
+    #endif
+  
 
+  
+  //uint8_t frag_queue[MAX_PAYLOAD_SIZE + 11];
+  //RF24NetworkFrame frag_queue;
+  
   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 */
-  uint8_t min(uint8_t, uint8_t);
+  
+  #if defined ENABLE_NETWORK_STATS
+  static uint32_t nFails;
+  static uint32_t nOK;
+  #endif  
+  
+public:
+
+   
+
 };
 
 /**
- * @example helloworld_tx.pde
+ * @example helloworld_tx.ino
  *
  * Simplest possible example of using RF24Network.  Put this sketch
  * on one node, and helloworld_rx.pde on the other.  Tx will send
@@ -183,7 +853,7 @@
  */
 
 /**
- * @example helloworld_rx.pde
+ * @example helloworld_rx.ino
  *
  * Simplest possible example of using RF24Network.  Put this sketch
  * on one node, and helloworld_tx.pde on the other.  Tx will send
@@ -191,12 +861,34 @@
  */
 
 /**
- * @example meshping.pde
+ * @example Network_Ping.ino
  *
- * Example of pinging across a mesh network
+ * Example to give users an understanding of addressing and topology in the 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 Network_Ping_Sleep.ino
+ *
+ * Example: This is almost exactly the same as the Network_Ping example, but with use
+ * of the integrated sleep mode.
+ *
+ * This example demonstrates how nodes on the network utilize sleep mode to conserve power. For example,
+ * the radio itself will draw about 13.5mA in receive mode. In sleep mode, it will use as little as 22ua (.000022mA)
+ * of power when not actively transmitting or receiving data. In addition, the Arduino is powered down as well,
+ * dropping network power consumption dramatically compared to previous capabilities. <br>
+ * Note: Sleeping nodes generate traffic that will wake other nodes up. This may be mitigated with further modifications. Sleep
+ * payloads are currently always routed to the master node, which will wake up intermediary nodes. Routing nodes can be configured
+ * to go back to sleep immediately.
+ * The displayed millis() count will give an indication of how much a node has been sleeping compared to the others, as millis() will
+ * not increment while a node sleeps.
+ *<br>
+ * - Using this sketch, each node will send a ping to every other node in the network every few seconds.<br>
+ * - The RF24Network library will route the message across the mesh to the correct node.<br>
+ *
  */
 
 /**
@@ -211,17 +903,19 @@
  * @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.
+ * by the newly optimized <a href="http://tmrh20.github.com/RF24/">RF24</a> library fork.
  *
  * @section Purpose Purpose/Goal
  *
- * Create an alternative to ZigBee radios for Arduino communication.
+ * Original: Create an alternative to ZigBee radios for Arduino communication.
+ * 
+ * New: Enhance the current functionality for maximum efficiency, reliability, and speed
  *
- * Xbees are excellent little radios, backed up by a mature and robust standard 
+ * 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 
+ * For many Arduino uses, they seem like overkill.  So I am working to improve the current
+ * standard for nRF24L01 radios.  The best RF24 modules are available for less than
  * $6 from many sources.  With the RF24Network layer, I hope to cover many
  * common communication scenarios.
  *
@@ -229,39 +923,55 @@
  *
  * @section Features Features
  *
+ * <b>Whats new? </b><br> 
+ *  @li New: (Dec 8) Merge of RPi and Arduino code. Finally moving closer to a stable release.  Report issues at https://github.com/TMRh20/RF24Network/issues
+ *  @li New functionality: (Dec 8) Support for fragmented multicast payloads on both RPi and Arduino
+ *  @li New functionality: (Nov 24) Fragmentation & reassembly supported on both RPi and Arduino  
+ *  @li Note: structure of network frames is changed, these are only used by external applications like RF24Ethernet and RF24toTUN, and for fragmentation
+ *  @li New functionality: User message types 1 through 64 will not receive a network ack
+ *
  * The layer provides:
+ * @li <b>New</b> (2014): Network ACKs: Efficient acknowledgement of network-wide transmissions, via dynamic radio acks and network protocol acks.
+ * @li <b>New</b> (2014): Updated addressing standard for optimal radio transmission.
+ * @li <b>New</b> (2014): Extended timeouts and staggered timeout intervals. The new txTimeout variable allows fully automated extended timeout periods via auto-retry/auto-reUse of payloads.
+ * @li <b>New</b> (2014): Optimization to the core library provides improvements to reliability, speed and efficiency. See https://tmrh20.github.io/RF24 for more info.
+ * @li <b>New</b> (2014): Built in sleep mode using interrupts. (Still under development. (Enable via RF24Network_config.h))
+  * @li <b>New</b> (2014): Dual headed operation: The use of dual radios for busy routing nodes or the master node enhances throughput and decreases errors. See the <a href="Tuning.html">Tuning</a> section.
  * @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.
+ * The layer does not provide:
+ * @li Dynamic address assignment. (See RF24Mesh)
+ * @li Layer 4 protocols (TCP/IP - See RF24Ethernet and RF24toTUN)
  *
  * @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>.
+ * @li <a href="AdvancedConfig.html"> Advanced Configuration Options</a>
+ * @li <a href="Addressing.html"> Addressing format</a>
+ * @li <a href="Tuning.html"> Topology and Overview</a>
+ * @li <a href="https://github.com/TMRh20/RF24Network/archive/Development.zip">Download Current Development Package</a>
+ * @li <a href="examples.html">Examples Page</a>.  Start with <a href="helloworld_rx_8ino-example.html">helloworld_rx</a> and <a href="helloworld_tx_8ino-example.html">helloworld_tx</a>.
  *
+ * <b> Additional Information & Add-ons </b>  
+ * @li <a href="https://github.com/TMRh20/RF24Mesh">RF24Mesh: Dynamic Mesh Layer for RF24Network Dev</a>
+ * @li <a href="https://github.com/TMRh20/RF24Ethernet">RF24Ethernet: TCP/IP over RF24Network</a>
+ * @li <a href="http://tmrh20.blogspot.com/2014/03/high-speed-data-transfers-and-wireless.html">My Blog: RF24 Optimization Overview</a>
+ * @li <a href="http://tmrh20.blogspot.com/2014/03/arduino-radiointercomwireless-audio.html">My Blog: RF24 Wireless Audio</a>
+ * @li <a href="http://maniacbug.github.com/RF24/">RF24: Original Author</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 
+ * 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
+ * @section Octal Octal Addressing and Topology
  *
  * 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
@@ -272,6 +982,15 @@
  * @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.
+ * An example topology is shown below, with 5 nodes in direct communication with the master node,
+ * and multiple leaf nodes spread out at a distance, using intermediate nodes to reach other nodes.
+ *
+ *|   |    | 00 |    |    | 00 |    |    |    | Master Node (00)                                    |
+ *|---|----|----|----|----|----|----|----|----|-----------------------------------------------------|
+ *|   |    | 01 |    |    | 04 |    |    |    | 1st level children of master (00)                   |
+ *|   | 011|    | 021|    |    |014 |    |    | 2nd level children of master. Children of 1st level.|
+ *|111|    |    | 121| 221|    |    | 114|    | 3rd level children of master. Children of 2nd level.|
+ *|   |    |    |    |1221|    |1114|2114|3114| 4th level children of master. Children of 3rd level.|
  *
  * @section Routing How routing is handled
  *
@@ -291,26 +1010,257 @@
  * 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 
+ * @section Directionality Directionality
  *
  * By default all nodes are always listening, so messages will quickly reach
- * their destination.  
+ * their destination.
+ *
+ * You may choose to sleep any nodes on the network if using interrupts. This is useful in a
+ * case where the nodes are operating on batteries and need to sleep. This greatly decreases
+ * the power requirements for a sensor network. The leaf nodes can sleep most of the time,
+ * and wake every few minutes to send in a reading. Routing nodes can be triggered to wake up
+ * whenever a payload is received See sleepNode() in the class documentation, and RFNetwork_config.h
+ * to enable sleep mode.
+ *
+ *
+ * @page Addressing Addressing Format: Understanding Addressing and Topology
+ * An overview of addressing in RF24Network
+ *
+ * @section Overview Overview
+ * The nrf24 radio modules typically use a 40-bit address format, requiring 5-bytes of storage space per address, and allowing a wide
+ * array of addresses to be utilized. In addition, the radios are limited to direct communication with 6 other nodes while using the 
+ * Enhanced-Shock-Burst (ESB) functionality of the radios.  
+ *
+ * RF24Network uses a simple method of data compression to store the addresses using only 2 bytes, in a format designed to represent the
+ * network topology in an intuitive way.
+ * See the <a href="Tuning.html"> Topology and Overview</a> page for more info regarding topology.
+ *
+ * @section Octal_Binary Decimal, Octal and Binary formats
+ * 
+ * Say we want to designate a logical address to a node, using a tree topology as defined by the manufacturer.
+ * In the simplest format, we could assign the first node the address of 1, the second 2 and so on.  
+ * Since a single node can only connect to 6 other nodes (1 parent and 5 children) subnets need to be created if using more than 6 nodes.<br>
+ * In this case the children of node 1 could simply be designated as 11,21,31,41, and 51<br>
+ * Children of node 2 could be designated as 12,22,32,42, and 52  
+ * 
+ * The above example is exactly how RF24Network manages the addresses, but they are represented in Octal format.
+ * 
+ * <b>Decimal, Octal and Binary</b>  
+ * <table> 
+ * <tr bgcolor="#a3b4d7" >
+ * <td> Decimal </td> <td> Binary </td><td> Decimal </td> <td> Binary </td><td> Decimal </td> <td> Binary </td>
+ * </tr><tr>
+ * <td> 1 </td> <td> 00000001 </td><td> 11 </td> <td> 00001011 </td><td> 111 </td> <td> 01101111 </td>
+ * </tr><tr bgcolor="#a3b4d7" >
+ * <td> Octal </td> <td> Binary </td><td> Octal </td> <td> Binary </td><td> Octal </td> <td> Binary </td>
+ * </tr><tr>
+ * <td> 1 </td> <td> 00000001 </td><td> 011 </td> <td> 00001001 </td><td> 0111 </td> <td> 1001001 </td>
+ * </tr>
+ * </table>
+ *
+ *  
+ * Since the numbers 0-7 can be represented in exactly three bits, each digit is represented by exactly 3 bits when viewed in octal format.  
+ * This allows a very simple method of managing addresses via masking and bit shifting.  
+ *   
+ * @section DisplayAddresses Displaying Addresses
+ *
+ * When using Arduino devices, octal addresses can be printed in the following manner:
+ * @code
+ * uint16_t address = 0111; 
+ * Serial.println(address,OCT);
+ * @endcode
+ *
+ * Printf can also be used, if enabled, or if using linux/RPi
+ * @code
+ * uint16_t address = 0111;
+ * printf("0%o\n",address);
+ * @endcode
+ *
+ * See http://www.cplusplus.com/doc/hex/ for more information<br>
+ * See the <a href="Tuning.html"> Topology and Overview</a> page for more info regarding topology.  
+ *
+ * @page AdvancedConfig Advanced Configuration
+ *
+ * RF24Network offers many features, some of which can be configured by editing the RF24Network_config.h file
+ *
+ * | Configuration Option | Description |
+ * |----------------------|-------------|
+ * |<b> #define RF24NetworkMulticast </b> | This option allows nodes to send and receive multicast payloads. Nodes with multicast enabled can also be configured to relay multicast payloads on to further multicast levels. See multicastRelay |
+ * | <b> #define DISABLE_FRAGMENTATION </b> | Fragmentation is enabled by default, and uses an additional 144 bytes of memory. |
+ * | <b> #define MAX_PAYLOAD_SIZE 144 </b> | The maximum size of payloads defaults to 144 bytes. If used with RF24toTUN and two Raspberry Pi, set this to 1514 (TAP) or 1500 (TUN) |
+ * | <b> #define NUM_USER_PAYLOADS 5 </b> | This is the number of 24-byte payloads the network layer will cache for the user. If using fragmentation, this number * 24 must be larger than MAX_PAYLOAD_SIZE |
+ * | <b> #define DISABLE_USER_PAYLOADS </b> | This option will disable user-caching of payloads entirely. Use with RF24Ethernet to reduce memory usage. (TCP/IP is an external data type, and not cached) |
+ * | <b> #define ENABLE_SLEEP_MODE </b> | Uncomment this option to enable sleep mode for AVR devices. (ATTiny,Uno, etc) |
+ * | <b> #define DUAL_HEAD_RADIO </b> | Uncomment this option to enable use of dual radios |
+ * | **#define ENABLE_NETWORK_STATS** | Enable counting of all successful or failed transmissions, routed or sent directly |
+ *
+ ** @page Tuning Performance and Data Loss: Tuning the Network
+ * Tips and examples for tuning the network and general operation.
+ *
+ *  <img src="tmrh20/topologyImage.jpg" alt="Topology" height="75%" width="75%">
+ *
+ * @section General Understanding Radio Communication and Topology
+ * When a transmission takes place from one radio module to another, the receiving radio will communicate
+ * back to the sender with an acknowledgement (ACK) packet, to indicate success. If the sender does not
+ * receive an ACK, the radio automatically engages in a series of timed retries, at set intervals. The 
+ * radios use techniques like addressing and numbering of payloads to manage this, but it is all done 
+ * automatically by the nrf chip, out of sight from the user.
+ *
+ * When working over a radio network, some of these automated techniques can actually hinder data transmission to a degree.
+ * Retrying failed payloads over and over on a radio network can hinder communication for nearby nodes, or 
+ * reduce throughput and errors on routing nodes.
+ *
+ * Radios in this network are linked by <b>addresses</b> assigned to <b>pipes</b>. Each radio can listen
+ * to 6 addresses on 6 pipes, therefore each radio has a parent pipe and 5 child pipes, which are used
+ * to form a tree structure. Nodes communicate directly with their parent and children nodes. Any other
+ * traffic to or from a node must be routed through the network.
+ *
+ * @section Topology Topology of RF24Network
+ *
+ * Anybody who is familiar at all with IP networking should be able to easily understand RF24Network topology. The
+ * master node can be seen as the gateway, with up to 4 directly connected nodes. Each of those nodes creates a
+ * subnet below it, with up to 4 additional child nodes. The numbering scheme can also be related to IP addresses,
+ * for purposes of understanding the topology via subnetting. Nodes can have 5 children if multicast is disabled.
+ *
+ * Expressing RF24Network addresses in IP format:  
+ *
+ * As an example, we could designate the master node in theory, as Address 10.10.10.10 <br> 
+ * The children nodes of the master would be 10.10.10.1, 10.10.10.2, 10.10.10.3, 10.10.10.4 and 10.10.10.5 <br> 
+ * The children nodes of 10.10.10.1 would be 10.10.1.1, 10.10.2.1, 10.10.3.1, 10.10.4.1 and 10.10.5.1 <br> 
+ *    
+ * In RF24Network, the master is just 00  <br>
+ * Children of master are 01,02,03,04,05  <br>
+ * Children of 01 are 011,021,031,041,051  <br>
  * 
- * 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.
+ * @section Network Routing
+ *
+ * Routing of traffic is handled invisibly to the user, by the network layer. If the network addresses are
+ * assigned in accordance with the physical layout of the network, nodes will route traffic automatically
+ * as required. Users simply constuct a header containing the appropriate destination address, and the network
+ * will forward it through to the correct node. Individual nodes only route individual fragments, so if using
+ * fragmentation, routing nodes do not need it enabled, unless sending or receiving fragmented payloads themselves.
+ *
+ * If routing data between parent and child nodes (marked by direct links on the topology image above) the network
+ * uses built-in acknowledgement and retry functions of the chip to prevent data loss. When payloads are sent to
+ * other nodes, they need to be routed. Routing is managed using a combination of built in ACK requests, and
+ * software driven network ACKs. This allows all routing nodes to forward data very quickly, with only the final
+ * routing node confirming delivery and sending back an
+ * acknowledgement.
+ *
+ * Example: Node 00 sends to node 01. The nodes will use the built in auto-retry and auto-ack functions.<br>
+ * Example: Node 00 sends to node 011. Node 00 will send to node 01 as before. Node 01 will forward the message to
+ * 011. If delivery was successful, node 01 will also forward a message back to node 00, indicating success.
+ *
+ * Old Functionality: Node 00 sends to node 011 using auto-ack. Node 00 first sends to 01, 01 acknowledges.
+ * Node 01 forwards the payload to 011 using auto-ack. If the payload fails between 01 and 011, node 00 has
+ * no way of knowing. 
+ * 
+ * @note When retrying failed payloads that have been routed, there is a chance of duplicate payloads if the network-ack
+ * is not successful. In this case, it is left up to the user to manage retries and filtering of duplicate payloads.
+ *
+ * Acknowledgements can and should be managed by the application or user. If requesting a response from another node,
+ * an acknowledgement is not required, so a user defined type of 0-64 should be used, to prevent the network from
+ * responding with an acknowledgement. If not requesting a response, and wanting to know if the payload was successful
+ * or not, users can utilize header types 65-127.
+ * 
+ * @section TuningOverview Tuning Overview
+ * The RF24 radio modules are generally only capable of either sending or receiving data at any given
+ * time, but have built-in auto-retry mechanisms to prevent the loss of data. These values are adjusted
+ * automatically by the library on startup, but can be further adjusted to reduce data loss, and
+ * thus increase throughput of the network. This page is intended to provide a general overview of its
+ * operation within the context of the network library, and provide guidance for adjusting these values.
+ *
+ * @section RetryTiming Auto-Retry Timing
+ *
+ * The core radio library provides the functionality of adjusting the internal auto-retry interval of the
+ * radio modules. In the network configuration, the radios can be set to automatically retry failed
+ * transmissions at intervals ranging anywhere from 500us (.5ms) up to 4000us (4ms). When operating any
+ * number of radios larger than two, it is important to stagger the assigned intervals, to prevent the
+ * radios from interfering with each other at the radio frequency (RF) layer.
+ *
+ * The library should provide fairly good working values, as it simply staggers the assigned values within
+ * groups of radios in direct communication. This value can be set manually by calling radio.setRetries(X,15);
+ * and adjusting the value of X from 1 to 15 (steps of 250us).
+ *
+ * @section AutoRetry Auto-Retry Count and Extended Timeouts
+ *
+ * The core radio library also provides the ability to adjust the internal auto-retry count of the radio
+ * modules. The default setting is 15 automatic retries per payload, and can be extended by configuring
+ * the network.txTimeout variable. This default retry count should generally be left at 15, as per the
+ * example in the above section. An interval/retry setting of (15,15) will provide 15 retrys at intervals of
+ * 4ms, taking up to 60ms per payload. The library now provides staggered timeout periods by default, but
+ * they can also be adjusted on a per-node basis.
  *
- * 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.
+ * The txTimeout variable is used to extend the retry count to a defined duration in milliseconds. See the
+ * network.txTimeout variable. Timeout periods of extended duration (500+) will generally not help when payloads
+ * are failing due to data collisions, it will only extend the duration of the errors. Extended duration timeouts
+ * should generally only be configured on leaf nodes that do not receive data, or on a dual-headed node.
+ *
+ * @section Examples
+ *
+ * <b>Example 1:</b> Network with master node and three leaf nodes that send data to the master node. None of the leaf
+ * nodes need to receive data.
+ *
+ * a: Master node uses default configuration<br>
+ * b: Leaf nodes can be configured with extended timeout periods to ensure reception by the master.<br>
+ * c:
+ * @code
+ * Leaf 01: network.txTimeout = 500;   Leaf 02: network.txTimeout = 573;  Leaf 03: network.txTimeout = 653;
+ * @endcode
+ * This configuration will provide a reduction in errors, as the timeouts have been extended, and are staggered
+ * between devices.
+ *
+ *
+ * <b>Example 2:</b> Network with master node and three leaf nodes that send data to the master node. The second leaf
+ * node needs to receive configuration data from the master at set intervals of 1 second, and send data back to the
+ * master node. The other leaf nodes will send basic sensor information every few seconds, and a few dropped payloads
+ * will not affect the operation greatly.
+ *
+ * a: Master node configured with extended timeouts of .5 seconds, and increased retry delay:
+ *   @code
+ *      radio.setRetries(11,15);
+ *      network.txTimeout = 500;
+ *   @endcode
+ * b: Second leaf node configured with a similar timeout period and retry delay:
+ * @code
+ *      radio.setRetries(8,15);
+ *      network.txTimeout = 553;
+ * @endcode
+ * c: First and third leaf nodes configured with default timeout periods or slightly increased timout periods.
+ *
+ * @section DualHead Dual Headed Operation
+ *
+ * The library now supports a dual radio configuration to further enhance network performance, while reducing errors on
+ * busy networks. Master nodes or relay nodes with a large number of child nodes can benefit somewhat from a dual headed
+ * configuration, since one radio is used for receiving, and the other entirely for transmission.
+ *
+ * To configure a dual headed node:
+ * 1. Edit the RF24Network_config.h file, and uncomment #define DUAL_HEAD_RADIO
+ * 2. Connect another radio, using the same MOSI, MISO, and SCK lines.
+ * 3. Choose another two pins to use for CE and CS on the second radio. Connect them.
+ * 4. Setup the radio and network like so:
+ *
+ * @code
+ *  RF24 radio(7,8);            // Using CE (7) and CS (8) for first radio
+ *  RF24 radio1(4,5);           // Using CE (4) and CS (5) for second radio
+ *  RF24Network network(radio,radio1);  // Set up the network using both radios
+ *
+ *  Then in setup(), call radio.begin(); and radio1.begin(); before network.begin();
+ * @endcode
+ *
+ * 5. Upload to MCU. The node will now use the first radio to receive data, and radio1 to transmit, preventing data loss on a busy network.
+ * 6. Re-comment the #define in the config file as required if configuring other single-headed radios.
+ *
+ *
+ * Any node can be configured in dual-head mode.
+ *
+ *
+ *
  *
  * @page Zigbee Comparison to ZigBee
  *
  * This network layer is influenced by the design of ZigBee, but does not implement it
- * directly.  
+ * directly.
  *
  * @section Advantage Which is better?
  *
@@ -318,7 +1268,7 @@
  * 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 
+ * for under $2.  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
@@ -326,8 +1276,8 @@
  * 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. 
+ * @li In ZigBee networks, only leaf nodes can sleep
+ * @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
@@ -338,7 +1288,11 @@
  * 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
+
--- a/RF24Network_config.h	Mon Jul 06 05:18:22 2015 +0000
+++ b/RF24Network_config.h	Thu Nov 05 05:40:44 2015 +0000
@@ -7,17 +7,135 @@
  version 2 as published by the Free Software Foundation.
  */
 
-#ifndef __RF24_CONFIG_H__
-#define __RF24_CONFIG_H__
+#ifndef __RF24NETWORK_CONFIG_H__
+#define __RF24NETWORK_CONFIG_H__
 
 #include "mbed.h"
 
-#include <stddef.h>
+
+
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 #define _BV(x) (1<<(x))
 
 
-#endif // __RF24_CONFIG_H__
-// vim:ai:cin:sts=2 sw=2 ft=cpp
+
+
+
+
+
+
+
+
+#include <stddef.h>
+
+
+
+
+
+/********** USER CONFIG - non ATTiny **************/
+
+//#define DUAL_HEAD_RADIO
+//#define ENABLE_SLEEP_MODE  //AVR only
+#define RF24NetworkMulticast
+
+/** \def
+ * Saves memory by disabling fragmentation
+ */
+//#define DISABLE_FRAGMENTATION
+
+/** System defines */
+
+/** The size of the main buffer. This is the user-cache, where incoming data is stored.
+ * Data is stored using Frames: Header (8-bytes) + Frame_Size (2-bytes) + Data (?-bytes)
+ *
+ * @note The MAX_PAYLOAD_SIZE is (MAIN_BUFFER_SIZE - 10), and the result must be divisible by 24.
+ */
+#define MAIN_BUFFER_SIZE 144 + 10
+
+/** Maximum size of fragmented network frames and fragmentation cache. This MUST BE divisible by 24.
+* @note: Must be a multiple of 24.
+* @note: If used with RF24Ethernet, this value is used to set the buffer sizes.
+*/
+#define MAX_PAYLOAD_SIZE  MAIN_BUFFER_SIZE-10
+
+/** Disable user payloads. Saves memory when used with RF24Ethernet or software that uses external data.*/
+//#define DISABLE_USER_PAYLOADS
+
+/** Enable tracking of success and failures for all transmissions, routed and user initiated */
+//#define ENABLE_NETWORK_STATS
+
+/** Enable dynamic payloads - If using different types of NRF24L01 modules, some may be incompatible when using this feature **/
+#define ENABLE_DYNAMIC_PAYLOADS
+
+/** Debug Options */
+//#define SERIAL_DEBUG
+//#define SERIAL_DEBUG_MINIMAL
+//#define SERIAL_DEBUG_ROUTING
+//#define SERIAL_DEBUG_FRAGMENTATION
+//#define SERIAL_DEBUG_FRAGMENTATION_L2
+/*************************************/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifndef rf24_max
+#define rf24_max(a,b) (a>b?a:b)
+#endif
+#ifndef rf24_min
+#define rf24_min(a,b) (a<b?a:b)
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#if defined (SERIAL_DEBUG_MINIMAL)
+#define IF_SERIAL_DEBUG_MINIMAL(x) ({x;})
+#else
+#define IF_SERIAL_DEBUG_MINIMAL(x)
+#endif
+
+#if defined (SERIAL_DEBUG_FRAGMENTATION)
+#define IF_SERIAL_DEBUG_FRAGMENTATION(x) ({x;})
+#else
+#define IF_SERIAL_DEBUG_FRAGMENTATION(x)
+#endif
+
+#if defined (SERIAL_DEBUG_FRAGMENTATION_L2)
+#define IF_SERIAL_DEBUG_FRAGMENTATION_L2(x) ({x;})
+#else
+#define IF_SERIAL_DEBUG_FRAGMENTATION_L2(x)
+#endif
+
+#if defined (SERIAL_DEBUG_ROUTING)
+#define IF_SERIAL_DEBUG_ROUTING(x) ({x;})
+#else
+#define IF_SERIAL_DEBUG_ROUTING(x)
+#endif
+#endif // RF24_NETWORK_CONFIG_H
+