From 5696f310f146b7da485d3de6a94987507d108f08 Mon Sep 17 00:00:00 2001
From: Rei <devel@reixd.net>
Date: Fri, 29 Aug 2014 15:29:35 +0200
Subject: [PATCH 01/10] Fix some indentation issues. Strip trailing spaces.
 Replace tabs with spaces.

---
 RPi/RF24Network/RF24Network.cpp      | 337 +++++++++++++--------------
 RPi/RF24Network/RF24Network.h        | 106 ++++-----
 RPi/RF24Network/RF24Network_config.h |   2 +-
 3 files changed, 222 insertions(+), 223 deletions(-)

diff --git a/RPi/RF24Network/RF24Network.cpp b/RPi/RF24Network/RF24Network.cpp
index c9c51940..2a15ecd9 100644
--- a/RPi/RF24Network/RF24Network.cpp
+++ b/RPi/RF24Network/RF24Network.cpp
@@ -24,7 +24,7 @@ uint16_t RF24NetworkHeader::next_id = 1;
 
 uint64_t pipe_address( uint16_t node, uint8_t pipe );
 #if defined (RF24NetworkMulticast)
-uint16_t levelToAddress( uint8_t level );
+  uint16_t levelToAddress( uint8_t level );
 #endif
 bool is_valid_address( uint16_t node );
 uint32_t nFails = 0, nOK=0;
@@ -32,24 +32,22 @@ uint32_t nFails = 0, nOK=0;
 /******************************************************************/
 
 RF24Network::RF24Network( RF24& _radio ): radio(_radio), next_frame(frame_queue)
-{
-}
+{}
 
 /******************************************************************/
 
-void RF24Network::begin(uint8_t _channel, uint16_t _node_address )
-{
-  if (! is_valid_address(_node_address) ){
+void RF24Network::begin(uint8_t _channel, uint16_t _node_address ) {
+  if (! is_valid_address(_node_address) ) {
     return;
-}
+  }
 
   node_address = _node_address;
 
-  if ( ! radio.isValid() ){
+  if ( ! radio.isValid() ) {
     return;
   }
 
-    // Set up the radio the way we want it to look
+  // Set up the radio the way we want it to look
   radio.setChannel(_channel);
   radio.setDataRate(RF24_1MBPS);
   radio.setCRCLength(RF24_CRC_16);
@@ -60,22 +58,22 @@ void RF24Network::begin(uint8_t _channel, uint16_t _node_address )
   radio.setRetries(retryVar, 5);
   txTimeout = 20;
   routeTimeout = txTimeout+35;
-  
+
   // Setup our address helper cache
   setup_address();
 
   // Open up all listening pipes
   int i = 6;
-  while (i--){
+  while (i--) {
     radio.openReadingPipe(i,pipe_address(_node_address,i));
   }
-    #if defined (RF24NetworkMulticast)
+  #if defined (RF24NetworkMulticast)
     uint8_t count = 0; uint16_t addy = _node_address;
-	while(addy){
-		addy/=8;
-		count++;
-	}
-	multicast_level = count;	
+    while(addy) {
+        addy/=8;
+        count++;
+    }
+    multicast_level = count;
   #endif
   radio.startListening();
 
@@ -83,8 +81,8 @@ void RF24Network::begin(uint8_t _channel, uint16_t _node_address )
 
 /******************************************************************/
 void RF24Network::failures(uint32_t *_fails, uint32_t *_ok){
-	*_fails = nFails;
-	*_ok = nOK;
+    *_fails = nFails;
+    *_ok = nOK;
 }
 
 uint8_t RF24Network::update(void)
@@ -108,49 +106,49 @@ uint8_t RF24Network::update(void)
 
       // Throw it away if it's not a valid address
       if ( !is_valid_address(header.to_node) ){
-		continue;
-	  }
-	  
-	  
-	  uint8_t res = header.type;	  
+        continue;
+      }
+
+
+      uint8_t res = header.type;
       // Is this for us?
       if ( header.to_node == node_address ){
-			if(res == NETWORK_ACK){
-				#ifdef SERIAL_DEBUG_ROUTING
-					printf_P(PSTR("MAC: Network ACK Rcvd\n"));
-				#endif
-				return NETWORK_ACK;
-			}
-			enqueue();
-
-		
+            if(res == NETWORK_ACK){
+                #ifdef SERIAL_DEBUG_ROUTING
+                    printf_P(PSTR("MAC: Network ACK Rcvd\n"));
+                #endif
+                return NETWORK_ACK;
+            }
+            enqueue();
+
+
       }else{
-	  
-	  #if defined	(RF24NetworkMulticast)		
-			if( header.to_node == 0100){
-				if(header.id != lastMultiMessageID){
-					if(multicastRelay){					
-						#ifdef SERIAL_DEBUG_ROUTING
-							printf_P(PSTR("MAC: FWD multicast frame from 0%o to level %d\n"),header.from_node,multicast_level+1);
-						#endif
-						write(levelToAddress(multicast_level)<<3,4);
-					}
-				enqueue();				
-				lastMultiMessageID = header.id;
-				}
-				#ifdef SERIAL_DEBUG_ROUTING
-				else{				
-					printf_P(PSTR("MAC: Drop duplicate multicast frame %u from 0%o\n"),header.id,header.from_node);
-				}
-				#endif
-			}else{
-				write(header.to_node,1);	//Send it on, indicate it is a routed payload
-			}
-		#else
-		//if(radio.available()){printf("------FLUSHED DATA --------------");}
-		write(header.to_node,1);	//Send it on, indicate it is a routed payload	
-		#endif
-	 }
+
+      #if defined   (RF24NetworkMulticast)
+            if( header.to_node == 0100){
+                if(header.id != lastMultiMessageID){
+                    if(multicastRelay){
+                        #ifdef SERIAL_DEBUG_ROUTING
+                            printf_P(PSTR("MAC: FWD multicast frame from 0%o to level %d\n"),header.from_node,multicast_level+1);
+                        #endif
+                        write(levelToAddress(multicast_level)<<3,4);
+                    }
+                enqueue();
+                lastMultiMessageID = header.id;
+                }
+                #ifdef SERIAL_DEBUG_ROUTING
+                else{
+                    printf_P(PSTR("MAC: Drop duplicate multicast frame %u from 0%o\n"),header.id,header.from_node);
+                }
+                #endif
+            }else{
+                write(header.to_node,1);    //Send it on, indicate it is a routed payload
+            }
+        #else
+        //if(radio.available()){printf("------FLUSHED DATA --------------");}
+        write(header.to_node,1);    //Send it on, indicate it is a routed payload
+        #endif
+     }
 
       // NOT NEEDED anymore.  Now all reading pipes are open to start.
 #if 0
@@ -160,11 +158,11 @@ uint8_t RF24Network::update(void)
 
       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));
+        uint8_t pipe = pipe_to_descendant(header.from_node);
+        radio.openReadingPipe(pipe,pipe_address(node_address,pipe));
 
-	// Also need to open pipe 1 so the system can get the full 5-byte address of the pipe.
-	radio.openReadingPipe(1,pipe_address(node_address,1));
+        // Also need to open pipe 1 so the system can get the full 5-byte address of the pipe.
+        radio.openReadingPipe(1,pipe_address(node_address,1));
       }
 #endif
     //}
@@ -258,11 +256,11 @@ size_t RF24Network::read(RF24NetworkHeader& header,void* message, size_t maxlen)
 #if defined RF24NetworkMulticast
 
 bool RF24Network::multicast(RF24NetworkHeader& header,const void* message, size_t len, uint8_t level){
-	// Fill out the header
-	
-  header.to_node = 0100;	
+  // Fill out the header
+
+  header.to_node = 0100;
   header.from_node = node_address;
-  
+
   // Build the full frame to send
   memcpy(frame_buffer,&header,sizeof(RF24NetworkHeader));
   if (len)
@@ -274,22 +272,22 @@ bool RF24Network::multicast(RF24NetworkHeader& header,const void* message, size_
     IF_SERIAL_DEBUG(const uint16_t* i = reinterpret_cast<const uint16_t*>(message);printf_P(PSTR("%u: NET message %04x\n\r"),millis(),*i));
   }
 
-	//uint16_t levelAddr = (level * 10)*8;     
-    uint16_t levelAddr = 1;
-    levelAddr = levelAddr << ((level-1) * 3); 
-  
-    return write(levelAddr,4);
-  
+  //uint16_t levelAddr = (level * 10)*8;
+  uint16_t levelAddr = 1;
+  levelAddr = levelAddr << ((level-1) * 3);
+
+  return write(levelAddr,4);
+
 }
 #endif
 
 /******************************************************************/
 bool RF24Network::write(RF24NetworkHeader& header,const void* message, size_t len){
-	return _write(header,message,len,070);
+    return _write(header,message,len,070);
 }
 /******************************************************************/
 bool RF24Network::write(RF24NetworkHeader& header,const void* message, size_t len, uint16_t writeDirect){
-	return _write(header,message,len,writeDirect);
+    return _write(header,message,len,writeDirect);
 }
 /******************************************************************/
 
@@ -307,7 +305,7 @@ bool RF24Network::_write(RF24NetworkHeader& header,const void* message, size_t l
   if (len)
   {
    // IF_SERIAL_DEBUG(const uint16_t* i = reinterpret_cast<const uint16_t*>(message);printf_P(PSTR("%u: NET message %04x\n\r"),millis(),*i));
-	IF_SERIAL_DEBUG(printf("%u: NET message ",millis());const char* charPtr = reinterpret_cast<const char*>(message);while(len--){ printf("%02x ",charPtr[len]);} printf("\n\r") );
+    IF_SERIAL_DEBUG(printf("%u: NET message ",millis());const char* charPtr = reinterpret_cast<const char*>(message);while(len--){ printf("%02x ",charPtr[len]);} printf("\n\r") );
   }
 
 
@@ -316,16 +314,16 @@ bool RF24Network::_write(RF24NetworkHeader& header,const void* message, size_t l
     // Just queue it in the received queue
     return enqueue();
   }else{
-	if(writeDirect != 070){
-		if(header.to_node == writeDirect){
-			return write(writeDirect,2);
-	    }else{
-			return write(writeDirect,3);
-		}	
+    if(writeDirect != 070){
+        if(header.to_node == writeDirect){
+            return write(writeDirect,2);
+        }else{
+            return write(writeDirect,3);
+        }
     }else{
-		// Otherwise send it out over the air
-		return write(header.to_node,0);
-	}
+        // Otherwise send it out over the air
+        return write(header.to_node,0);
+    }
   }
 }
 
@@ -337,7 +335,7 @@ bool RF24Network::write(uint16_t to_node, uint8_t directTo)
   bool multicast = 0; // Radio ACK requested = 0
   const uint16_t fromAddress = frame_buffer[0] | (frame_buffer[1] << 8);
   const uint16_t logicalAddress = frame_buffer[2] | (frame_buffer[3] << 8);
-  
+
   // Throw it away if it's not a valid address
   if ( !is_valid_address(to_node) )
     return false;
@@ -349,18 +347,18 @@ bool RF24Network::write(uint16_t to_node, uint8_t directTo)
   uint16_t send_node = parent_node;
   // On which pipe
   uint8_t send_pipe = parent_pipe%5;
-  
- if(directTo>1){    
-	send_node = to_node;
-	multicast = 1;	
-	if(directTo == 4){
-		send_pipe=0;
-	}	
+
+ if(directTo>1){
+    send_node = to_node;
+    multicast = 1;
+    if(directTo == 4){
+        send_pipe=0;
+    }
   }
-  
+
   // If the node is a direct child,
   else if ( is_direct_child(to_node) )
-  {  
+  {
     // Send directly
     send_node = to_node;
 
@@ -371,38 +369,38 @@ bool RF24Network::write(uint16_t to_node, uint8_t directTo)
   // 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 = 5;
   }
 
-  
+
   //if( ( send_node != to_node) || frame_buffer[6] == NETWORK_ACK || directTo == 3 || directTo == 4){
-//		multicast = 1;
- // }
-  
+  //      multicast = 1;
+  // }
+
   IF_SERIAL_DEBUG(printf_P(PSTR("%u: MAC Sending to 0%o via 0%o on pipe %x\n\r"),millis(),logicalAddress,send_node,send_pipe));
 
-  
+
   // Put the frame on the pipe
-  ok = write_to_pipe( send_node, send_pipe, multicast );  
-//printf("Multi %d\n",multicast);
-   
+  ok = write_to_pipe( send_node, send_pipe, multicast );
+  //printf("Multi %d\n",multicast);
+
   #if defined (SERIAL_DEBUG_ROUTING) || defined(SERIAL_DEBUG)
-  if(!ok){ printf_P(PSTR("%u: MAC Send fail to 0%o from 0%o via 0%o on pipe %x\n\r"),millis(),logicalAddress,fromAddress,send_node,send_pipe); }
+    if(!ok){ printf_P(PSTR("%u: MAC Send fail to 0%o from 0%o via 0%o on pipe %x\n\r"),millis(),logicalAddress,fromAddress,send_node,send_pipe); }
   #endif
-  
-   	   if( directTo == 1 && ok && send_node == to_node && frame_buffer[6] != NETWORK_ACK && fromAddress != node_address ){
-			frame_buffer[6] = NETWORK_ACK;
-			frame_buffer[2] = frame_buffer[0]; frame_buffer[3] = frame_buffer[1];
-			write(fromAddress,1);	
-			#if defined (SERIAL_DEBUG_ROUTING)
-				printf("MAC: Route OK to 0%o ACK sent to 0%o\n",to_node,fromAddress);
-			#endif
-	   }
-	   
-
-  
+
+       if( directTo == 1 && ok && send_node == to_node && frame_buffer[6] != NETWORK_ACK && fromAddress != node_address ){
+            frame_buffer[6] = NETWORK_ACK;
+            frame_buffer[2] = frame_buffer[0]; frame_buffer[3] = frame_buffer[1];
+            write(fromAddress,1);
+            #if defined (SERIAL_DEBUG_ROUTING)
+                printf("MAC: Route OK to 0%o ACK sent to 0%o\n",to_node,fromAddress);
+            #endif
+       }
+
+
+
   // 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.
@@ -417,22 +415,22 @@ bool RF24Network::write(uint16_t to_node, uint8_t directTo)
   radio.startListening();
 
   if( (send_node != logicalAddress) && (directTo==0 || directTo == 3 )){
-		uint32_t reply_time = millis(); 
-		while( update() != NETWORK_ACK){
-			if(millis() - reply_time > routeTimeout){ 
-				ok=0; 
-				#ifdef SERIAL_DEBUG_ROUTING
-					printf_P(PSTR("%u: MAC Network ACK fail from 0%o via 0%o on pipe %x\n\r"),millis(),logicalAddress,send_node,send_pipe); 
-				#endif
-				break;
-			}
-		}
-		//if(pOK){printf("pOK\n");}
+        uint32_t reply_time = millis();
+        while( update() != NETWORK_ACK){
+            if(millis() - reply_time > routeTimeout){
+                ok=0;
+                #ifdef SERIAL_DEBUG_ROUTING
+                    printf_P(PSTR("%u: MAC Network ACK fail from 0%o via 0%o on pipe %x\n\r"),millis(),logicalAddress,send_node,send_pipe);
+                #endif
+                break;
+            }
+        }
+        //if(pOK){printf("pOK\n");}
    }
     if(ok == true){
-			nOK++;
-	}else{	nFails++;
-	}
+            nOK++;
+    }else{  nFails++;
+    }
 return ok;
 }
 
@@ -443,7 +441,7 @@ bool RF24Network::write_to_pipe( uint16_t node, uint8_t pipe, bool multicast )
   bool ok = false;
 
   uint64_t out_pipe = pipe_address( node, pipe );
-  
+
   // First, stop listening so we can talk
   radio.stopListening();
   // Open the correct pipe for writing.
@@ -453,7 +451,7 @@ bool RF24Network::write_to_pipe( uint16_t node, uint8_t pipe, bool multicast )
   radio.writeFast(frame_buffer, frame_size,multicast);
   ok = radio.txStandBy(txTimeout);
   //ok = radio.write(frame_buffer,frame_size);
-  
+
   IF_SERIAL_DEBUG(printf_P(PSTR("%u: MAC Sent on %x %s\n\r"),millis(),(uint32_t)out_pipe,ok?PSTR("ok"):PSTR("failed")));
 
   return ok;
@@ -522,7 +520,7 @@ void RF24Network::setup_address(void)
   {
     i >>= 3;
     m >>= 3;
-  }  
+  }
   parent_pipe = i;
   //parent_pipe=i-1;
 
@@ -566,11 +564,11 @@ bool is_valid_address( uint16_t node )
   while(node)
   {
     uint8_t digit = node & 0B111;
-	#if !defined (RF24NetworkMulticast)
+    #if !defined (RF24NetworkMulticast)
     if (digit < 1 || digit > 5)
-	#else
-	if (digit < 0 || digit > 5)	//Allow our out of range multicast address
-	#endif
+    #else
+    if (digit < 0 || digit > 5) //Allow our out of range multicast address
+    #endif
     {
       result = false;
       printf_P(PSTR("*** WARNING *** Invalid address 0%o\n\r"),node);
@@ -586,53 +584,54 @@ bool is_valid_address( uint16_t node )
 #if defined (RF24NetworkMulticast)
 void RF24Network::multicastLevel(uint8_t level){
   multicast_level = level;
-  radio.stopListening();  
+  radio.stopListening();
   radio.openReadingPipe(0,pipe_address(levelToAddress(level),0));
   radio.startListening();
-  }
-  
+}
+
 uint16_t levelToAddress(uint8_t level){
-	uint16_t levelAddr = 1;
-	levelAddr = levelAddr << ((level-1) * 3);
-	return levelAddr;
-}  
+  uint16_t levelAddr = 1;
+  levelAddr = levelAddr << ((level-1) * 3);
+  return levelAddr;
+}
 #endif
 
 /******************************************************************/
 
 uint64_t pipe_address( uint16_t node, uint8_t pipe )
 {
-  
+
   static uint8_t address_translation[] = { 0xc3,0x3c,0x33,0xce,0x3e,0xe3,0xec };
   uint64_t result = 0xCCCCCCCCCCLL;
   uint8_t* out = reinterpret_cast<uint8_t*>(&result);
-  
+
   // Translate the address to use our optimally chosen radio address bytes
-	uint8_t count = 1; uint16_t dec = node;
-   #if defined (RF24NetworkMulticast)
-	if(pipe != 0 || !node){
-   #endif
-	while(dec){		
-		out[count]=address_translation[(dec % 8)];		// Convert our decimal values to octal, translate them to address bytes, and set our address
-		dec /= 8;	
-		count++;
-	}
- 		
-	out[0] = address_translation[pipe];		// Set last byte by pipe number
-   #if defined (RF24NetworkMulticast)
-	}else{
-		while(dec){
-			dec/=8;
-			count++;
-		}
-		out[1] = address_translation[count-1];	
-	}
-  
+    uint8_t count = 1; uint16_t dec = node;
+  #if defined (RF24NetworkMulticast)
+    if(pipe != 0 || !node){
   #endif
-  
+    while(dec){
+        out[count]=address_translation[(dec % 8)];      // Convert our decimal values to octal, translate them to address bytes, and set our address
+        dec /= 8;
+        count++;
+    }
+
+    out[0] = address_translation[pipe];     // Set last byte by pipe number
+  #if defined (RF24NetworkMulticast)
+    }else{
+        while(dec){
+            dec/=8;
+            count++;
+        }
+        out[1] = address_translation[count-1];
+    }
+
+  #endif
+
   IF_SERIAL_DEBUG(uint32_t* top = reinterpret_cast<uint32_t*>(out+1);printf_P(PSTR("%u: NET Pipe %i on node 0%o has address %x%x\n\r"),millis(),pipe,node,*top,*out));
-	
+
   return result;
 }
 
 
+// vim:ai:cin:sts=2 sw=2 ft=cpp
diff --git a/RPi/RF24Network/RF24Network.h b/RPi/RF24Network/RF24Network.h
index d195259b..f5a0d6f7 100644
--- a/RPi/RF24Network/RF24Network.h
+++ b/RPi/RF24Network/RF24Network.h
@@ -104,9 +104,9 @@ class RF24Network
    * @param _node_address The logical address of this node
    */
   void begin(uint8_t _channel, uint16_t _node_address );
-  
+
   void failures(uint32_t *_fails, uint32_t *_ok);
-  
+
   /**
    * Main layer loop
    *
@@ -117,11 +117,11 @@ class RF24Network
 
   /**
    * 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
    *
@@ -143,7 +143,7 @@ class RF24Network
    * @return The total number of bytes copied into @p message
    */
   size_t read(RF24NetworkHeader& header, void* message, size_t maxlen);
-  
+
   /**
    * Send a message
    *
@@ -151,20 +151,20 @@ class RF24Network
    * @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, size_t len);
   bool write(RF24NetworkHeader& header,const void* message, size_t len, uint16_t writeDirect);
-  
+
   /**
    * This node's parent address
-   * 
-   * @return This node's parent address, or -1 if this is the base 
+   *
+   * @return This node's parent address, or -1 if this is the base
    */
   uint16_t parent() const;
- 
+
    /**
    * @note: Optimization:This value is automatically assigned based on the node address
    * to reduce errors and increase throughput of the network.
@@ -176,7 +176,7 @@ class RF24Network
    */
 
   unsigned long txTimeout;
- 
+
    /**
    * @note: Optimization: This new value defaults to 200 milliseconds.
    * This only affects payloads that are routed by one or more nodes.
@@ -184,7 +184,7 @@ class RF24Network
    * Radios routing directly to their parent or children nodes do not
    * utilize this value.
    */
-  
+
    uint16_t routeTimeout;
 
   /**@}*/
@@ -194,12 +194,12 @@ class RF24Network
    *  Methods you can use to drive the network in more advanced ways
    */
   /**@{*/
- #if defined RF24NetworkMulticast
+#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  
+   * 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
    * @param message Pointer to memory where the message is located
@@ -207,37 +207,37 @@ class RF24Network
    * @param level Multicast level to broadcast to
    * @return Whether the message was successfully received
    */
-   
-   bool multicast(RF24NetworkHeader& header,const void* message, size_t len, uint8_t level);
-   
-	/**
-	* 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. This option
-	* is used to override the defaults, and create custom multicast groups that all share a single
-	* address.  
-	* The level should be specified in decimal format 1-6  
-	* Nodes can be configured to automatically forward multicast payloads to the next multicast level
-	* @see multicastRelay 
-	*
-	* @param level Levels 1 to 6 are available. All nodes at the same level will receive the same
-	* messages if in range. 
-	*/
-	
-	void multicastLevel(uint8_t level);
-	
-	/**
-	 * Set individual nodes to relay received multicast payloads onto the next multicast level. 
-	 * Relay nodes will still receive the payloads, but they will also forward them on.
-	 * Relay nodes can have a maximum of 4 direct child nodes, but can multicast to any number
-	 * of nodes. 
-	 * Multicast nodes and relays are configured to filter out duplicate payloads, so having multiple
-	 * relays in an area should not be a problem.
-	 */
-	 
-	bool multicastRelay;
-
-#endif	
-   
+
+  bool multicast(RF24NetworkHeader& header,const void* message, size_t len, uint8_t level);
+
+  /**
+  * 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. This option
+  * is used to override the defaults, and create custom multicast groups that all share a single
+  * address.
+  * The level should be specified in decimal format 1-6
+  * Nodes can be configured to automatically forward multicast payloads to the next multicast level
+  * @see multicastRelay
+  *
+  * @param level Levels 1 to 6 are available. All nodes at the same level will receive the same
+  * messages if in range.
+  */
+
+  void multicastLevel(uint8_t level);
+
+  /**
+   * Set individual nodes to relay received multicast payloads onto the next multicast level.
+   * Relay nodes will still receive the payloads, but they will also forward them on.
+   * Relay nodes can have a maximum of 4 direct child nodes, but can multicast to any number
+   * of nodes.
+   * Multicast nodes and relays are configured to filter out duplicate payloads, so having multiple
+   * relays in an area should not be a problem.
+   */
+
+  bool multicastRelay;
+
+#endif
+
 protected:
   void open_pipes(void);
   uint16_t find_node( uint16_t current_node, uint16_t target_node );
@@ -251,15 +251,15 @@ class RF24Network
   uint8_t pipe_to_descendant( uint16_t node );
   void setup_address(void);
   bool _write(RF24NetworkHeader& header,const void* message, size_t len, uint16_t writeDirect);
-  
+
 private:
 #if defined (RF24NetworkMulticast)
   uint16_t lastMultiMessageID;
   uint8_t multicast_level;
 #endif
-  RF24& radio; /**< Underlying radio driver, provides link/physical layers */ 
+  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 */ 
+  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[255*frame_size]; /**< RPi can buffer 500 frames (16kB) - Arduino does 5 by default. 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 */
@@ -277,7 +277,7 @@ class RF24Network
  * Simplest possible example of using RF24Network.  Put this sketch
  * on one node, and helloworld_rx.pde on the other.  Tx will send
  * Rx a nice message every 2 seconds which rx will print out for us.
- * 
+ *
  */
 
 /**
diff --git a/RPi/RF24Network/RF24Network_config.h b/RPi/RF24Network/RF24Network_config.h
index b32c2ac6..693e6715 100644
--- a/RPi/RF24Network/RF24Network_config.h
+++ b/RPi/RF24Network/RF24Network_config.h
@@ -54,7 +54,7 @@ typedef uint16_t prog_uint16_t;
 #define printf_P printf
 #define strlen_P strlen
 #define PROGMEM
-#define pgm_read_word(p) (*(p)) 
+#define pgm_read_word(p) (*(p))
 #define PRIPSTR "%s"
 #endif
 

From fda8602c7beeb747b31175203f39bb9caf5c14dd Mon Sep 17 00:00:00 2001
From: Rei <devel@reixd.net>
Date: Fri, 29 Aug 2014 15:50:29 +0200
Subject: [PATCH 02/10] Add a frame structure for each message. The frame
 consists of a header, the payload size and a message payload.

This structure is only a helper struct for lib internals, to be able to use dynamic payload sizes.
Over the air only the header and the payload (without the payload size) are transmitted.
---
 RPi/RF24Network/RF24Network.h | 46 +++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/RPi/RF24Network/RF24Network.h b/RPi/RF24Network/RF24Network.h
index f5a0d6f7..c2a5e004 100644
--- a/RPi/RF24Network/RF24Network.h
+++ b/RPi/RF24Network/RF24Network.h
@@ -77,6 +77,52 @@ struct RF24NetworkHeader
   const char* toString(void) const;
 };
 
+/**
+ * Frame structure for each message
+ *
+ * The frame put over the air consists of a header and a message payload
+ */
+struct RF24NetworkFrame
+{
+  RF24NetworkHeader header; /**< Header which is sent with each message */
+  uint8_t payload_size; /**< The size in bytes of the payload length */
+
+  /**
+   * Default constructor
+   *
+   * Simply constructs a blank frame
+   */
+  RF24NetworkFrame() {}
+
+  /**
+   * Send constructor
+   *
+   * Use this constructor to create a frame with header and then send a message
+   *
+   * @code
+   *  RF24NetworkFrame frame(recipient_address,'t',sizeof(message));
+   *  network.write(frame,&message,sizeof(message));
+   * @endcode
+   *
+   * @param _to The logical node address where the message is going.
+   * @param _type The type of message which follows.  Only 0-127 are allowed for
+   * user messages.
+   * @param _psize Length in bytes of the payload.
+   */
+  RF24NetworkFrame(uint16_t _to, unsigned char _type = 0, uint16_t _psize = 0) : header(RF24NetworkHeader(_to,_type)), payload_size(_psize) {}
+
+  /**
+   * 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;
+};
+
 /**
  * TMRh20 2014 - Optimized Network Layer for RF24 Radios
  *

From 03a1bc7e47570c30a2316b7fa0841af1a9a64158 Mon Sep 17 00:00:00 2001
From: Rei <devel@reixd.net>
Date: Fri, 29 Aug 2014 16:27:52 +0200
Subject: [PATCH 03/10] Extendend the frame struct to allow setting payload.
 Define MAX_FRAME_SIZE as a makro with value of '32' (Bytes).

---
 RPi/RF24Network/RF24Network.h | 38 +++++++++++++++++++++++++++++------
 1 file changed, 32 insertions(+), 6 deletions(-)

diff --git a/RPi/RF24Network/RF24Network.h b/RPi/RF24Network/RF24Network.h
index c2a5e004..d13287ce 100644
--- a/RPi/RF24Network/RF24Network.h
+++ b/RPi/RF24Network/RF24Network.h
@@ -24,6 +24,7 @@
 #include <stddef.h>
 #include "RF24Network_config.h"
 
+#define MAX_FRAME_SIZE 32
 
 class RF24;
 
@@ -85,7 +86,8 @@ struct RF24NetworkHeader
 struct RF24NetworkFrame
 {
   RF24NetworkHeader header; /**< Header which is sent with each message */
-  uint8_t payload_size; /**< The size in bytes of the payload length */
+  size_t payload_size; /**< The size in bytes of the payload length */
+  uint8_t payload_buffer[MAX_FRAME_SIZE]; /**< Space to put the frame payload that will be sent/received over the air */
 
   /**
    * Default constructor
@@ -97,19 +99,43 @@ struct RF24NetworkFrame
   /**
    * Send constructor
    *
-   * Use this constructor to create a frame with header and then send a message
+   * Use this constructor to create a frame with header and payload and then send a message
    *
    * @code
-   *  RF24NetworkFrame frame(recipient_address,'t',sizeof(message));
-   *  network.write(frame,&message,sizeof(message));
+   *  RF24NetworkFrame frame(recipient_address,'t',message,sizeof(message));
+   *  network.write(frame);
    * @endcode
    *
    * @param _to The logical node address where the message is going.
    * @param _type The type of message which follows.  Only 0-127 are allowed for
    * user messages.
+   * @param _payload The message content.
    * @param _psize Length in bytes of the payload.
    */
-  RF24NetworkFrame(uint16_t _to, unsigned char _type = 0, uint16_t _psize = 0) : header(RF24NetworkHeader(_to,_type)), payload_size(_psize) {}
+  RF24NetworkFrame(uint16_t _to, unsigned char _type = 0, const void* _payload = NULL, size_t _psize = 0) : header(RF24NetworkHeader(_to,_type)), payload_size(_psize) {
+    if (_payload != NULL)
+      memcpy(payload_buffer,_payload,std::min(MAX_FRAME_SIZE-sizeof(RF24NetworkHeader),_psize));
+  }
+
+  /**
+   * Send constructor
+   *
+   * Use this constructor to create a frame with header and payload and then send a message
+   *
+   * @code
+   *  RF24NetworkHeader header(recipient_address,'t');
+   *  RF24NetworkFrame frame(header,message,sizeof(message));
+   *  network.write(frame);
+   * @endcode
+   *
+   * @param _header The header struct of the frame
+   * @param _payload The message content.
+   * @param _psize Length in bytes of the payload.
+   */
+  RF24NetworkFrame(RF24NetworkHeader& _header, const void* _payload = NULL, size_t _psize = 0) : header(_header), payload_size(_psize) {
+    if (_payload != NULL)
+      memcpy(payload_buffer,_payload,std::min(MAX_FRAME_SIZE-sizeof(RF24NetworkHeader),_psize));
+  }
 
   /**
    * Create debugging string
@@ -305,7 +331,7 @@ class RF24Network
 #endif
   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 */
+  const static int frame_size = MAX_FRAME_SIZE; /**< 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[255*frame_size]; /**< RPi can buffer 500 frames (16kB) - Arduino does 5 by default. 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 */

From 64147ff40ef55c11a7b48a605253cbf58808ecf0 Mon Sep 17 00:00:00 2001
From: Rei <devel@reixd.net>
Date: Mon, 1 Sep 2014 10:29:57 +0200
Subject: [PATCH 04/10] Use the RF24NetworkFrame type for internal management
 of frames Changes in code:     - internally use the introuduced
 RF24NetworkFrame type to describe and manage header and payload.     - keep
 the write and read API for backward compatibility.     - make needed changes
 in some functions to be able to use the RF24NetworkFrame and circular buffer.
     - extend the circular buffer class with some functions         - front() 
        - isEmpty()         - isFull()     - update copyrith

TODO:
    - check if the code is supported in arduino
    - check for memory lecks
    - check for memory space usage (arduino)
    - implement automatic fragmentation and reassembly of large payloads
    - two independent tx and rx (circular buffer) FIFOs
    - clean up code
        - remove not need parts
---
 RPi/RF24Network/RF24Network.cpp        | 68 +++++++++++-----------
 RPi/RF24Network/RF24Network.h          |  8 ++-
 RPi/RF24Network/utils/CircularBuffer.h | 78 ++++++++++++++++++++++++++
 3 files changed, 115 insertions(+), 39 deletions(-)
 create mode 100644 RPi/RF24Network/utils/CircularBuffer.h

diff --git a/RPi/RF24Network/RF24Network.cpp b/RPi/RF24Network/RF24Network.cpp
index 2a15ecd9..3c65c591 100644
--- a/RPi/RF24Network/RF24Network.cpp
+++ b/RPi/RF24Network/RF24Network.cpp
@@ -1,5 +1,6 @@
 /*
  Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>
+ Copyright (C) 2014 Rei <devel@reixd.net>
 
  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
@@ -31,7 +32,7 @@ uint32_t nFails = 0, nOK=0;
 
 /******************************************************************/
 
-RF24Network::RF24Network( RF24& _radio ): radio(_radio), next_frame(frame_queue)
+RF24Network::RF24Network( RF24& _radio ): radio(_radio)
 {}
 
 /******************************************************************/
@@ -96,10 +97,17 @@ uint8_t RF24Network::update(void)
     //while (radio.available())
     //{
       // Fetch the payload, and see if this was the last one.
-      radio.read( frame_buffer, sizeof(frame_buffer) );
+      size_t len = radio.getDynamicPayloadSize();
+      radio.read( frame_buffer, len );
+
+      //Do we have a valid length for a frame?
+      //We need at least a frame with header a no payload (payload_size equals 0).
+      if (len < sizeof(RF24NetworkHeader))
+        continue;
 
       // Read the beginning of the frame as the header
-      const RF24NetworkHeader& header = * reinterpret_cast<RF24NetworkHeader*>(frame_buffer);
+      RF24NetworkHeader header;
+      memcpy(&header,frame_buffer,sizeof(RF24NetworkHeader));
 
       IF_SERIAL_DEBUG(printf_P("%u: 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("%u: NET message %04x\n\r",millis(),*i));
@@ -109,6 +117,9 @@ uint8_t RF24Network::update(void)
         continue;
       }
 
+      // Build the full frame
+      size_t payload_size = len-sizeof(RF24NetworkHeader);
+      RF24NetworkFrame frame = RF24NetworkFrame(header,frame_buffer+sizeof(RF24NetworkHeader),payload_size);
 
       uint8_t res = header.type;
       // Is this for us?
@@ -119,7 +130,7 @@ uint8_t RF24Network::update(void)
                 #endif
                 return NETWORK_ACK;
             }
-            enqueue();
+            enqueue(frame);
 
 
       }else{
@@ -133,7 +144,7 @@ uint8_t RF24Network::update(void)
                         #endif
                         write(levelToAddress(multicast_level)<<3,4);
                     }
-                enqueue();
+                enqueue(frame);
                 lastMultiMessageID = header.id;
                 }
                 #ifdef SERIAL_DEBUG_ROUTING
@@ -170,28 +181,20 @@ uint8_t RF24Network::update(void)
   return 0;
 }
 
-
-
-
 /******************************************************************/
 
-bool RF24Network::enqueue(void)
-{
+bool RF24Network::enqueue(RF24NetworkFrame frame) {
   bool result = false;
 
-  IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Enqueue @%x "),millis(),next_frame-frame_queue));
+  IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Enqueue @%x "),millis(),frame_queue.remain()));
 
   // 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;
+  frame_queue.push(frame);
+  result = true;
 
-    result = true;
+  if (result) {
     IF_SERIAL_DEBUG(printf("ok\n\r"));
-  }
-  else
-  {
+  } else {
     IF_SERIAL_DEBUG(printf("failed\n\r"));
   }
 
@@ -203,7 +206,7 @@ bool RF24Network::enqueue(void)
 bool RF24Network::available(void)
 {
   // Are there frames on the queue for us?
-  return (next_frame > frame_queue);
+  return (!frame_queue.isEmpty());
 }
 
 /******************************************************************/
@@ -222,8 +225,8 @@ 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));
+    RF24NetworkFrame frame = frame_queue.front();
+    memcpy(&header,&frame,sizeof(RF24NetworkHeader));
   }
 }
 
@@ -235,16 +238,13 @@ size_t RF24Network::read(RF24NetworkHeader& header,void* message, size_t maxlen)
 
   if ( available() )
   {
-    // Move the pointer back one in the queue
-    next_frame -= frame_size;
-    uint8_t* frame = next_frame;
+    RF24NetworkFrame frame = frame_queue.pop();
 
     // How much buffer size should we actually copy?
-    bufsize = std::min(maxlen,frame_size-sizeof(RF24NetworkHeader));
+    bufsize = std::min(frame.payload_size,maxlen);
 
-    // Copy the next available frame from the queue into the provided buffer
-    memcpy(&header,frame,sizeof(RF24NetworkHeader));
-    memcpy(message,frame+sizeof(RF24NetworkHeader),bufsize);
+    memcpy(&header,&(frame.header),sizeof(RF24NetworkHeader));
+    memcpy(message,frame.payload_buffer,bufsize);
 
     IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Received %s\n\r"),millis(),header.toString()));
   }
@@ -262,9 +262,7 @@ bool RF24Network::multicast(RF24NetworkHeader& header,const void* message, size_
   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,std::min(frame_size-sizeof(RF24NetworkHeader),len));
+  RF24NetworkFrame frame = RF24NetworkFrame(header,message,std::min(sizeof(message),len));
 
   IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Sending %s\n\r"),millis(),header.toString()));
   if (len)
@@ -297,9 +295,7 @@ bool RF24Network::_write(RF24NetworkHeader& header,const void* message, size_t l
   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,std::min(frame_size-sizeof(RF24NetworkHeader),len));
+  RF24NetworkFrame frame = RF24NetworkFrame(header,message,sizeof(message));
 
   IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Sending %s\n\r"),millis(),header.toString()));
   if (len)
@@ -312,7 +308,7 @@ bool RF24Network::_write(RF24NetworkHeader& header,const void* message, size_t l
   // If the user is trying to send it to himself
   if ( header.to_node == node_address ){
     // Just queue it in the received queue
-    return enqueue();
+    return enqueue(frame);
   }else{
     if(writeDirect != 070){
         if(header.to_node == writeDirect){
diff --git a/RPi/RF24Network/RF24Network.h b/RPi/RF24Network/RF24Network.h
index d13287ce..34543e83 100644
--- a/RPi/RF24Network/RF24Network.h
+++ b/RPi/RF24Network/RF24Network.h
@@ -1,5 +1,6 @@
 /*
  Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>
+ Copyright (C) 2014 Rei <devel@reixd.net>
 
  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
@@ -23,8 +24,10 @@
 #include <sys/time.h>
 #include <stddef.h>
 #include "RF24Network_config.h"
+#include "utils/CircularBuffer.h"
 
 #define MAX_FRAME_SIZE 32
+#define MAX_FRAME_BUFFER_SIZE 255
 
 class RF24;
 
@@ -315,7 +318,7 @@ class RF24Network
   uint16_t find_node( uint16_t current_node, uint16_t target_node );
   bool write(uint16_t, uint8_t directTo);
   bool write_to_pipe( uint16_t node, uint8_t pipe, bool multicast );
-  bool enqueue(void);
+  bool enqueue(RF24NetworkFrame frame);
 
   bool is_direct_child( uint16_t node );
   bool is_descendant( uint16_t node );
@@ -333,8 +336,7 @@ class RF24Network
   uint16_t node_address; /**< Logical node address of this unit, 1 .. UINT_MAX */
   const static int frame_size = MAX_FRAME_SIZE; /**< 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[255*frame_size]; /**< RPi can buffer 500 frames (16kB) - Arduino does 5 by default. 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 */
+  CircularBuffer<RF24NetworkFrame,MAX_FRAME_BUFFER_SIZE> frame_queue; /**< RPi can buffer 500 frames (16kB) - Arduino does 5 by default. Space for a small set of frames that need to be delivered to the app layer */
 
   uint16_t parent_node; /**< Our parent's node address */
   uint8_t parent_pipe; /**< The pipe our parent uses to listen to us */
diff --git a/RPi/RF24Network/utils/CircularBuffer.h b/RPi/RF24Network/utils/CircularBuffer.h
new file mode 100644
index 00000000..d950882c
--- /dev/null
+++ b/RPi/RF24Network/utils/CircularBuffer.h
@@ -0,0 +1,78 @@
+/*
+  CircularBuffer.h - circular buffer library for Arduino.
+
+  Copyright (c) 2009 Hiroki Yagita.
+  Copyright (c) 2014 Rei <devel@reixd.net>.
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  'Software'), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef CIRCULARBUFFER_h
+#define CIRCULARBUFFER_h
+#include <inttypes.h>
+
+template <typename T, uint16_t Size>
+class CircularBuffer {
+public:
+  enum {
+    Empty = 0,
+    Half = Size / 2,
+    Full = Size,
+  };
+
+  CircularBuffer() :
+    wp_(buf_), rp_(buf_), tail_(buf_+Size),  remain_(0), size_(Size) {}
+  ~CircularBuffer() {}
+  void push(T value) {
+    *wp_++ = value;
+    remain_++;
+    if (wp_ == tail_) wp_ = buf_;
+  }
+  T pop() {
+    T result = *rp_++;
+    remain_--;
+    if (rp_ == tail_) rp_ = buf_;
+    return result;
+  }
+  T front() {
+    T result = *rp_;
+    return result;
+  }
+  int remain() const {
+    return remain_;
+  }
+  bool isEmpty() {
+    if (remain_)
+      return true;
+    return false;
+  }
+  bool isFull() {
+    return (size_ == remain_);
+  }
+
+private:
+  T buf_[Size];
+  T *wp_;
+  T *rp_;
+  T *tail_;
+  uint16_t remain_;
+  uint16_t size_;
+};
+
+#endif

From e1bfd7ae27b727c874ae764e5aadbf162849d82e Mon Sep 17 00:00:00 2001
From: Rei <devel@reixd.net>
Date: Thu, 4 Sep 2014 10:27:03 +0200
Subject: [PATCH 05/10] Many changes in the fragmentation

FIXME: problems with reassembly data structure
---
 RPi/RF24Network/{utils => }/CircularBuffer.h |   0
 RPi/RF24Network/Makefile                     |   2 +-
 RPi/RF24Network/RF24Network.cpp              | 100 +++++++++++++++++--
 RPi/RF24Network/RF24Network.h                |  65 ++++++++++--
 RPi/RF24Network/lrucache.h                   |  74 ++++++++++++++
 5 files changed, 224 insertions(+), 17 deletions(-)
 rename RPi/RF24Network/{utils => }/CircularBuffer.h (100%)
 create mode 100644 RPi/RF24Network/lrucache.h

diff --git a/RPi/RF24Network/utils/CircularBuffer.h b/RPi/RF24Network/CircularBuffer.h
similarity index 100%
rename from RPi/RF24Network/utils/CircularBuffer.h
rename to RPi/RF24Network/CircularBuffer.h
diff --git a/RPi/RF24Network/Makefile b/RPi/RF24Network/Makefile
index 0fefb222..e0282f6b 100644
--- a/RPi/RF24Network/Makefile
+++ b/RPi/RF24Network/Makefile
@@ -24,7 +24,7 @@ LIBNAME_RFN=$(LIB_RFN).so.1.0
 HEADER_DIR=${PREFIX}/include/RF24Network
 
 # The recommended compiler flags for the Raspberry Pi
-CCFLAGS=-Ofast -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s
+CCFLAGS=-Ofast -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -std=c++0x
 
 # make all
 # reinstall the library after each recompilation
diff --git a/RPi/RF24Network/RF24Network.cpp b/RPi/RF24Network/RF24Network.cpp
index 3c65c591..9602eb73 100644
--- a/RPi/RF24Network/RF24Network.cpp
+++ b/RPi/RF24Network/RF24Network.cpp
@@ -186,11 +186,32 @@ uint8_t RF24Network::update(void)
 bool RF24Network::enqueue(RF24NetworkFrame frame) {
   bool result = false;
 
-  IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Enqueue @%x "),millis(),frame_queue.remain()));
+  if (frame.header.fragment_id > 0) {
+    IF_SERIAL_DEBUG(printf("%u: NET message as fragment %i received\n\r",millis(),header.fragment_id););
+
+    //if fragment_id > 1 then
+    if (frame.header.fragment_id > 1) {
+      //Enqueue the frame with it fragmented payload in the LRUCache
+      //The cache will assemble all payloads into one big payload
+      //!frameAssemblyCache.put(frame.header.from_node,frame);
+      result = true;
+    } else if (frame.header.fragment_id == 1) {
+      //if we got a fragment_id == 1, then we got the last fragment
+      //Enqueue this frame into the frame_queue
+      //!frame_queue.push( frameAssemblyCache.get(frame.header.from_node) );
+      result = true;
+    } else {
+      //  otherwise discard the message with the large payload
+      result = false;
+    }
+
+  } else {
+    IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Enqueue @%x "),millis(),frame_queue.remain()));
 
-  // Copy the current frame into the frame queue
-  frame_queue.push(frame);
-  result = true;
+    // Copy the current frame into the frame queue
+    frame_queue.push(frame);
+    result = true;
+  }
 
   if (result) {
     IF_SERIAL_DEBUG(printf("ok\n\r"));
@@ -241,10 +262,10 @@ size_t RF24Network::read(RF24NetworkHeader& header,void* message, size_t maxlen)
     RF24NetworkFrame frame = frame_queue.pop();
 
     // How much buffer size should we actually copy?
-    bufsize = std::min(frame.payload_size,maxlen);
+    bufsize = std::min(frame.getPayloadSize(),maxlen);
 
     memcpy(&header,&(frame.header),sizeof(RF24NetworkHeader));
-    memcpy(message,frame.payload_buffer,bufsize);
+    memcpy(message,frame.getPayloadArray(),bufsize);
 
     IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Received %s\n\r"),millis(),header.toString()));
   }
@@ -281,11 +302,71 @@ bool RF24Network::multicast(RF24NetworkHeader& header,const void* message, size_
 
 /******************************************************************/
 bool RF24Network::write(RF24NetworkHeader& header,const void* message, size_t len){
-    return _write(header,message,len,070);
+    return write(header,message,len,070);
 }
 /******************************************************************/
 bool RF24Network::write(RF24NetworkHeader& header,const void* message, size_t len, uint16_t writeDirect){
+  bool txSuccess = true;
+
+  //Check payload size
+  if (len <= max_frame_payload_size) {
+    //If message payload length fits in a single message
+    //then use the normal _write() function
     return _write(header,message,len,writeDirect);
+  }
+
+  if (len >= 255*max_frame_payload_size) {
+    //If the message payload is too big, whe cannot generate enough fragments
+    //and enumerate them
+    txSuccess = false;
+    return txSuccess;
+  }
+  //The payload is smaller than 6kBytes. We cann transmit it.
+
+  //Divide the message payload into chuncks of max_frame_payload_size
+  uint8_t fragment_id = 1 + ((len - 1) / max_frame_payload_size);  //the number of fragments to send = ceil(len/max_frame_payload_size)
+  uint8_t msgCount = 0;
+
+  IF_SERIAL_DEBUG(printf("%u: NET total message fragments %i\n\r",millis(),fragment_id););
+
+  //Iterate over the payload chuncks
+  //  Assemble a new message, copy and fill out the header
+  //  Try to send this message
+  //  If it fails
+  //    then break
+  //    return result as false
+  while (fragment_id > 0) {
+
+    //Copy and fill out the header
+    RF24NetworkHeader fragmentHeader;
+    fragmentHeader = header;
+    fragmentHeader.fragment_id = fragment_id;
+
+    size_t offset = msgCount*max_frame_payload_size;
+
+    IF_SERIAL_DEBUG(printf("%u: NET try to transmit msg with fragment '%i'\n\r",millis(),(msgCount+1)););
+
+    //Try to send the payload chunk with the copied header
+    bool ok = _write(fragmentHeader,message+offset,len-offset,writeDirect);
+    if (!ok) {
+      IF_SERIAL_DEBUG(printf("%u: NET message transmission with fragmentID '%i' failed. Abort.\n\r",millis(),(msgCount+1)););
+      txSuccess = false;
+      break;
+    }
+    IF_SERIAL_DEBUG(printf("%u: NET message transmission with fragmentID '%i' sucessfull.\n\r",millis(),(msgCount+1)););
+
+    //Message was successful sent
+    //Check and modify counters
+    fragment_id--;
+    msgCount++;
+
+    IF_SERIAL_DEBUG(printf("%u: NET DEBUG: fragmentID=%i msgCount=%i loop_done?=%i\n\r",millis(),fragment_id,msgCount,!(fragment_id > 0)););
+  }
+
+  //Return true if all the chuncks where sent successfuly
+  //else return false
+  IF_SERIAL_DEBUG(printf("%u: NET total message fragments sent %i. Status",millis(),msgCount); printf("%s\n\r", ok ? "ok" : "not ok"););
+  return txSuccess;
 }
 /******************************************************************/
 
@@ -295,7 +376,8 @@ bool RF24Network::_write(RF24NetworkHeader& header,const void* message, size_t l
   header.from_node = node_address;
 
   // Build the full frame to send
-  RF24NetworkFrame frame = RF24NetworkFrame(header,message,sizeof(message));
+  if (len)
+    memcpy(frame_buffer + sizeof(RF24NetworkHeader),message,std::min(frame_size-sizeof(RF24NetworkHeader),len));
 
   IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Sending %s\n\r"),millis(),header.toString()));
   if (len)
@@ -307,6 +389,8 @@ bool RF24Network::_write(RF24NetworkHeader& header,const void* message, size_t l
 
   // If the user is trying to send it to himself
   if ( header.to_node == node_address ){
+    // Build the frame to send
+    RF24NetworkFrame frame = RF24NetworkFrame(header,message,sizeof(message));
     // Just queue it in the received queue
     return enqueue(frame);
   }else{
diff --git a/RPi/RF24Network/RF24Network.h b/RPi/RF24Network/RF24Network.h
index 34543e83..e28454c1 100644
--- a/RPi/RF24Network/RF24Network.h
+++ b/RPi/RF24Network/RF24Network.h
@@ -17,17 +17,24 @@
  * Class declaration for RF24Network
  */
 
+
 #include <stdint.h>
 #include <stdio.h>
 #include <time.h>
 #include <string.h>
 #include <sys/time.h>
 #include <stddef.h>
+#include <assert.h>
+//!#include <vector>
+#include <list>
 #include "RF24Network_config.h"
-#include "utils/CircularBuffer.h"
+#include "CircularBuffer.h"
+#include "FrameLRUCache.h"
 
 #define MAX_FRAME_SIZE 32
 #define MAX_FRAME_BUFFER_SIZE 255
+#define MAX_PAYLOAD_SIZE ((MAX_FRAME_SIZE-sizeof(RF24NetworkHeader))*255)
+#define MAX_LRU_CACHE_SIZE 32
 
 class RF24;
 
@@ -42,7 +49,7 @@ struct RF24NetworkHeader
   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 */
+  unsigned char fragment_id; /**< Used to count the number of fragments of the payload. Zero (0) means no more fragments left. */
 
   static uint16_t next_id; /**< The message ID of the next message to be sent */
 
@@ -90,7 +97,7 @@ struct RF24NetworkFrame
 {
   RF24NetworkHeader header; /**< Header which is sent with each message */
   size_t payload_size; /**< The size in bytes of the payload length */
-  uint8_t payload_buffer[MAX_FRAME_SIZE]; /**< Space to put the frame payload that will be sent/received over the air */
+  std::list<uint8_t> payload_buffer; /**< Vector to put the frame payload that will be sent/received over the air */
 
   /**
    * Default constructor
@@ -116,8 +123,7 @@ struct RF24NetworkFrame
    * @param _psize Length in bytes of the payload.
    */
   RF24NetworkFrame(uint16_t _to, unsigned char _type = 0, const void* _payload = NULL, size_t _psize = 0) : header(RF24NetworkHeader(_to,_type)), payload_size(_psize) {
-    if (_payload != NULL)
-      memcpy(payload_buffer,_payload,std::min(MAX_FRAME_SIZE-sizeof(RF24NetworkHeader),_psize));
+    appendToPayload(_payload,payload_size);
   }
 
   /**
@@ -136,8 +142,7 @@ struct RF24NetworkFrame
    * @param _psize Length in bytes of the payload.
    */
   RF24NetworkFrame(RF24NetworkHeader& _header, const void* _payload = NULL, size_t _psize = 0) : header(_header), payload_size(_psize) {
-    if (_payload != NULL)
-      memcpy(payload_buffer,_payload,std::min(MAX_FRAME_SIZE-sizeof(RF24NetworkHeader),_psize));
+    appendToPayload(_payload,payload_size);
   }
 
   /**
@@ -150,6 +155,48 @@ struct RF24NetworkFrame
    * @return String representation of this object
    */
   const char* toString(void) const;
+
+  /**
+   * Get the frame payload (message) as array
+   *
+   * Internally is the payload a vector.
+   * @return array pointer to the payload
+   */
+  const void* getPayloadArray(void) {
+    //!const void* res = &payload_buffer[0];
+    //!return res;
+    uint8_t *arr = new uint8_t[payload_buffer.size()];
+    std::copy(payload_buffer.begin(),payload_buffer.end(),arr);
+    return arr;
+  }
+
+  /**
+   *  Get the payload size
+   *
+   * @return Size in bytes of the current payload
+   */
+  size_t getPayloadSize(void) {
+    return payload_buffer.size();
+  }
+
+  /**
+   * Append the given payload to the current payload_buffer
+   *
+   */
+  void appendToPayload(const void* payload, size_t len) {
+    if (payload && len) {
+      if ((payload_buffer.size()+len) <= MAX_PAYLOAD_SIZE) {
+        //Cast the payload as uint8_t
+        const uint8_t *q = (const uint8_t *)payload;
+        //Append the payload to the buffer
+        payload_buffer.insert(payload_buffer.end(), q, q+len);
+        //Save space in RAM
+        //!payload_buffer.shrink_to_fit();
+      }
+    }
+    //Set the new payload_buffer size
+    payload_size = payload_buffer.size();
+  };
 };
 
 /**
@@ -334,9 +381,11 @@ class RF24Network
 #endif
   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 = MAX_FRAME_SIZE; /**< How large is each frame over the air */
+  const static unsigned int frame_size = MAX_FRAME_SIZE; /**< How large is each frame over the air */
+  const static unsigned int max_frame_payload_size = frame_size-sizeof(RF24NetworkHeader);
   uint8_t frame_buffer[frame_size]; /**< Space to put the frame that will be sent/received over the air */
   CircularBuffer<RF24NetworkFrame,MAX_FRAME_BUFFER_SIZE> frame_queue; /**< RPi can buffer 500 frames (16kB) - Arduino does 5 by default. Space for a small set of frames that need to be delivered to the app layer */
+  //!FrameLRUCache<uint16_t,RF24NetworkFrame,MAX_LRU_CACHE_SIZE> frameAssemblyCache;
 
   uint16_t parent_node; /**< Our parent's node address */
   uint8_t parent_pipe; /**< The pipe our parent uses to listen to us */
diff --git a/RPi/RF24Network/lrucache.h b/RPi/RF24Network/lrucache.h
new file mode 100644
index 00000000..0eabfa2a
--- /dev/null
+++ b/RPi/RF24Network/lrucache.h
@@ -0,0 +1,74 @@
+/*
+ * File:   lrucache.hpp
+ * Author: Alexander Ponomarev
+ * https://github.com/aponomarev/cpp-lru-cache/blob/master/include/lrucache.hpp
+ *
+ * Created on June 20, 2013, 5:09 PM
+ */
+
+#ifndef _LRUCACHE_HPP_INCLUDED_
+#define _LRUCACHE_HPP_INCLUDED_
+
+#include <unordered_map>
+#include <list>
+#include <cstddef>
+#include <stdexcept>
+
+namespace cache {
+
+template<typename key_t, typename value_t>
+class lru_cache {
+public:
+    typedef typename std::pair<key_t, value_t> key_value_pair_t;
+    typedef typename std::list<key_value_pair_t>::iterator list_iterator_t;
+
+    lru_cache(size_t max_size) :
+        _max_size(max_size) {
+    }
+
+    void put(const key_t& key, const value_t& value) {
+        auto it = _cache_items_map.find(key);
+        if (it != _cache_items_map.end()) {
+            _cache_items_list.erase(it->second);
+            _cache_items_map.erase(it);
+        }
+
+        _cache_items_list.push_front(key_value_pair_t(key, value));
+        _cache_items_map[key] = _cache_items_list.begin();
+
+        if (_cache_items_map.size() > _max_size) {
+            auto last = _cache_items_list.end();
+            last--;
+            _cache_items_map.erase(last->first);
+            _cache_items_list.pop_back();
+        }
+    }
+
+    const value_t& get(const key_t& key) {
+        auto it = _cache_items_map.find(key);
+        if (it == _cache_items_map.end()) {
+            throw std::range_error("There is no such key in cache");
+        } else {
+            _cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second);
+            return it->second->second;
+        }
+    }
+
+    bool exists(const key_t& key) const {
+        return _cache_items_map.find(key) != _cache_items_map.end();
+    }
+
+    size_t size() const {
+        return _cache_items_map.size();
+    }
+
+private:
+    std::list<key_value_pair_t> _cache_items_list;
+    std::unordered_map<key_t, list_iterator_t> _cache_items_map;
+    size_t _max_size;
+};
+
+} // namespace lru
+
+#endif  /* _LRUCACHE_HPP_INCLUDED_ */
+

From a20004f4f5d5576dab59fe3e7a6b45ebb23be0e9 Mon Sep 17 00:00:00 2001
From: Rei <devel@reixd.net>
Date: Fri, 5 Sep 2014 16:55:11 +0200
Subject: [PATCH 06/10] Change isEmpty test

---
 RPi/RF24Network/CircularBuffer.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/RPi/RF24Network/CircularBuffer.h b/RPi/RF24Network/CircularBuffer.h
index d950882c..22d3c236 100644
--- a/RPi/RF24Network/CircularBuffer.h
+++ b/RPi/RF24Network/CircularBuffer.h
@@ -58,7 +58,7 @@ class CircularBuffer {
     return remain_;
   }
   bool isEmpty() {
-    if (remain_)
+    if (remain_ > 0)
       return true;
     return false;
   }

From 49670849f32182b719f36efceea3d11a6066939f Mon Sep 17 00:00:00 2001
From: Rei <devel@reixd.net>
Date: Fri, 5 Sep 2014 17:14:39 +0200
Subject: [PATCH 07/10] Delete not needed data structure

---
 RPi/RF24Network/lrucache.h | 74 --------------------------------------
 1 file changed, 74 deletions(-)
 delete mode 100644 RPi/RF24Network/lrucache.h

diff --git a/RPi/RF24Network/lrucache.h b/RPi/RF24Network/lrucache.h
deleted file mode 100644
index 0eabfa2a..00000000
--- a/RPi/RF24Network/lrucache.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * File:   lrucache.hpp
- * Author: Alexander Ponomarev
- * https://github.com/aponomarev/cpp-lru-cache/blob/master/include/lrucache.hpp
- *
- * Created on June 20, 2013, 5:09 PM
- */
-
-#ifndef _LRUCACHE_HPP_INCLUDED_
-#define _LRUCACHE_HPP_INCLUDED_
-
-#include <unordered_map>
-#include <list>
-#include <cstddef>
-#include <stdexcept>
-
-namespace cache {
-
-template<typename key_t, typename value_t>
-class lru_cache {
-public:
-    typedef typename std::pair<key_t, value_t> key_value_pair_t;
-    typedef typename std::list<key_value_pair_t>::iterator list_iterator_t;
-
-    lru_cache(size_t max_size) :
-        _max_size(max_size) {
-    }
-
-    void put(const key_t& key, const value_t& value) {
-        auto it = _cache_items_map.find(key);
-        if (it != _cache_items_map.end()) {
-            _cache_items_list.erase(it->second);
-            _cache_items_map.erase(it);
-        }
-
-        _cache_items_list.push_front(key_value_pair_t(key, value));
-        _cache_items_map[key] = _cache_items_list.begin();
-
-        if (_cache_items_map.size() > _max_size) {
-            auto last = _cache_items_list.end();
-            last--;
-            _cache_items_map.erase(last->first);
-            _cache_items_list.pop_back();
-        }
-    }
-
-    const value_t& get(const key_t& key) {
-        auto it = _cache_items_map.find(key);
-        if (it == _cache_items_map.end()) {
-            throw std::range_error("There is no such key in cache");
-        } else {
-            _cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second);
-            return it->second->second;
-        }
-    }
-
-    bool exists(const key_t& key) const {
-        return _cache_items_map.find(key) != _cache_items_map.end();
-    }
-
-    size_t size() const {
-        return _cache_items_map.size();
-    }
-
-private:
-    std::list<key_value_pair_t> _cache_items_list;
-    std::unordered_map<key_t, list_iterator_t> _cache_items_map;
-    size_t _max_size;
-};
-
-} // namespace lru
-
-#endif  /* _LRUCACHE_HPP_INCLUDED_ */
-

From a4dbdd149a4b2c81f97f95ed2de4249aa08f78c5 Mon Sep 17 00:00:00 2001
From: Rei <devel@reixd.net>
Date: Fri, 5 Sep 2014 17:14:51 +0200
Subject: [PATCH 08/10] Fully functional fragmentation implementation for large
 payloads. Fragmentation is transparent to caller application.

TODO:
        - multicast fragmentation
        - test with multiple nodes in a larger network
        - use a circular queue for the frame_queue data structure
        - use a LRUCache data structure for the frame reassembly
        - lower memory consumption
        - arduino porting
        - cleanup code
        - remove redundant and innecessary code

- Based on IPv4 fragmentation https://tools.ietf.org/html/rfc791.
- Tested only on Raspberry Pi, may not work in Arduinos due to memory usage
  Tested only with two raspberris using NRF24L01+ 10 meters appart.
- The lib is capable to detect if the message payload is bigger than frame_size-sizeof(Header)
  and split the payload into chuncks and send them separately.
- This commit introduces two new flag types:
        - NETWORK_MORE_FRAGMENTS
        - NETWORK_LAST_FRAGMENT
- As of IPv4 fragmention this flags are used to mark the frames to notify the receiver if more
  fragments will come or this is the last fragment.
- The previous _write() function to transmit the frames is used.
- Changes in payload size management were made to allow dynamic payload sizes without the need
  to define a field in the header.
- Introduce a new struct type "RF24NetworkFrame" for better frame handling inside the lib.
  This type encapsulates the header, the current size of the payload and a (fixed size) array
  containing the payload.
- The frame_buffer data structure was changes in favor of a std::queue for better handling.
- Make some changes renaming variables and defining the values.
- Use a std::map with double key (header.to_from,header.id) to identify the incoming fragments,
  allowing the reassembly of multiple transmission simultaneously.
- The reassembly of frames hapens in the enqueue(frame) function.
  Based on the fragment_id and header.id the fragments are handled diffently and in the end
  the completely assembled frames are queued in the frame_queue presenting them to the calling
  application.
- Introduce a new debug flag to print fragmentation debug messages.
- Use definitions for static values like frame size or payload max size.
- Strip trailing spaces and fix some indentation issues.
---
 RPi/RF24Network/RF24Network.cpp      | 149 ++++++++++++++++++---------
 RPi/RF24Network/RF24Network.h        | 111 ++++++--------------
 RPi/RF24Network/RF24Network_config.h |   9 +-
 3 files changed, 138 insertions(+), 131 deletions(-)

diff --git a/RPi/RF24Network/RF24Network.cpp b/RPi/RF24Network/RF24Network.cpp
index 9602eb73..0f248de4 100644
--- a/RPi/RF24Network/RF24Network.cpp
+++ b/RPi/RF24Network/RF24Network.cpp
@@ -32,7 +32,7 @@ uint32_t nFails = 0, nOK=0;
 
 /******************************************************************/
 
-RF24Network::RF24Network( RF24& _radio ): radio(_radio)
+RF24Network::RF24Network( RF24& _radio ): radio(_radio), frame_size(MAX_FRAME_SIZE)
 {}
 
 /******************************************************************/
@@ -53,6 +53,7 @@ void RF24Network::begin(uint8_t _channel, uint16_t _node_address ) {
   radio.setDataRate(RF24_1MBPS);
   radio.setCRCLength(RF24_CRC_16);
   radio.enableDynamicAck();
+  radio.enableDynamicPayloads();
 
   //uint8_t retryVar = (node_address % 7) + 5;
   uint8_t retryVar = (((node_address % 6)+1) *2) + 3;
@@ -110,16 +111,20 @@ uint8_t RF24Network::update(void)
       memcpy(&header,frame_buffer,sizeof(RF24NetworkHeader));
 
       IF_SERIAL_DEBUG(printf_P("%u: 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("%u: NET message %04x\n\r",millis(),*i));
+      if (len) {
+        IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC frame size %i",millis(),len););
+        IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC frame ",millis()); const char* charPtr = reinterpret_cast<const char*>(frame_buffer); for (size_t i = 0; i < len; i++) { printf("%02X ", charPtr[i]); }; printf("\n\r"));
+      }
 
       // Throw it away if it's not a valid address
       if ( !is_valid_address(header.to_node) ){
         continue;
       }
 
+      IF_SERIAL_DEBUG(printf_P("%u: MAC Valid frame from %i with size %i received.\n\r",millis(),header.from_node,len));
+
       // Build the full frame
-      size_t payload_size = len-sizeof(RF24NetworkHeader);
-      RF24NetworkFrame frame = RF24NetworkFrame(header,frame_buffer+sizeof(RF24NetworkHeader),payload_size);
+      RF24NetworkFrame frame = RF24NetworkFrame(header,frame_buffer+sizeof(RF24NetworkHeader),len-sizeof(RF24NetworkHeader));
 
       uint8_t res = header.type;
       // Is this for us?
@@ -186,27 +191,30 @@ uint8_t RF24Network::update(void)
 bool RF24Network::enqueue(RF24NetworkFrame frame) {
   bool result = false;
 
-  if (frame.header.fragment_id > 0) {
-    IF_SERIAL_DEBUG(printf("%u: NET message as fragment %i received\n\r",millis(),header.fragment_id););
-
-    //if fragment_id > 1 then
-    if (frame.header.fragment_id > 1) {
-      //Enqueue the frame with it fragmented payload in the LRUCache
-      //The cache will assemble all payloads into one big payload
-      //!frameAssemblyCache.put(frame.header.from_node,frame);
-      result = true;
-    } else if (frame.header.fragment_id == 1) {
-      //if we got a fragment_id == 1, then we got the last fragment
-      //Enqueue this frame into the frame_queue
-      //!frame_queue.push( frameAssemblyCache.get(frame.header.from_node) );
-      result = true;
-    } else {
-      //  otherwise discard the message with the large payload
-      result = false;
-    }
+  if (frame.header.fragment_id > 1 && frame.header.type == NETWORK_MORE_FRAGMENTS) {
+    //Set the more fragments flag to indicate a fragmented frame
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC fragmented payload of size %i Bytes with fragmentID '%i' received.\n\r",millis(),frame.message_size,frame.header.fragment_id););
+
+    //Append payload
+    appendFragmentToFrame(frame);
+    result = true;
+
+  } else if (frame.header.fragment_id == 1 && frame.header.type == NETWORK_LAST_FRAGMENT) {
+    //Set the last fragment flag to indicate the last fragment
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC Last fragment with size %i Bytes and fragmentID '%i' received.\n\r",millis(),frame.message_size,frame.header.fragment_id););
+
+    //Append payload
+    appendFragmentToFrame(frame);
+
+    IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Enqueue assembled frame @%x "),millis(),frame_queue.size()));
+    //Push the assembled frame in the frame_queue and remove it from cache
+    frame_queue.push( frameFragmentsCache[ std::make_pair(frame.header.from_node,frame.header.id) ] );
+    frameFragmentsCache.erase( std::make_pair(frame.header.from_node,frame.header.id) );
+
+    result = true;
 
   } else {
-    IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Enqueue @%x "),millis(),frame_queue.remain()));
+    IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Enqueue @%x "),millis(),frame_queue.size()));
 
     // Copy the current frame into the frame queue
     frame_queue.push(frame);
@@ -224,10 +232,31 @@ bool RF24Network::enqueue(RF24NetworkFrame frame) {
 
 /******************************************************************/
 
+void RF24Network::appendFragmentToFrame(RF24NetworkFrame frame) {
+
+  if (frameFragmentsCache.count(std::make_pair(frame.header.from_node,frame.header.id)) == 0 ) {
+    //This is the first of many fragments
+    frameFragmentsCache[ std::make_pair(frame.header.from_node,frame.header.id) ] = frame;
+  } else {
+    //We have at least received one fragments.
+
+    //Append payload
+    RF24NetworkFrame *f = &(frameFragmentsCache[ std::make_pair(frame.header.from_node,frame.header.id) ]);
+    memcpy(f->message_buffer+f->message_size, frame.message_buffer, frame.message_size);
+
+    //Increment message size
+    f->message_size += frame.message_size;
+    //Update header
+    f->header = frame.header;
+  }
+}
+
+/******************************************************************/
+
 bool RF24Network::available(void)
 {
   // Are there frames on the queue for us?
-  return (!frame_queue.isEmpty());
+  return (!frame_queue.empty());
 }
 
 /******************************************************************/
@@ -259,17 +288,20 @@ size_t RF24Network::read(RF24NetworkHeader& header,void* message, size_t maxlen)
 
   if ( available() )
   {
-    RF24NetworkFrame frame = frame_queue.pop();
+    RF24NetworkFrame frame = frame_queue.front();
 
     // How much buffer size should we actually copy?
-    bufsize = std::min(frame.getPayloadSize(),maxlen);
+    bufsize = std::min(frame.message_size,maxlen);
 
     memcpy(&header,&(frame.header),sizeof(RF24NetworkHeader));
-    memcpy(message,frame.getPayloadArray(),bufsize);
+    memcpy(message,frame.message_buffer,bufsize);
 
-    IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Received %s\n\r"),millis(),header.toString()));
-  }
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET message size %i\n",millis(),frame.message_size););
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET message ",millis()); const char* charPtr = reinterpret_cast<const char*>(message); for (size_t i = 0; i < bufsize; i++) { printf("%02X ", charPtr[i]); }; printf("\n\r"));
+    IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET readed %s\n\r"),millis(),header.toString()));
 
+    frame_queue.pop();
+  }
   return bufsize;
 }
 
@@ -309,25 +341,33 @@ bool RF24Network::write(RF24NetworkHeader& header,const void* message, size_t le
   bool txSuccess = true;
 
   //Check payload size
+  if (len > MAX_PAYLOAD_SIZE) {
+    IF_SERIAL_DEBUG(printf("%u: NET write message failed. Given 'len' is bigger than the MAX Payload size of %i\n\r",millis(),MAX_PAYLOAD_SIZE););
+    return false;
+  }
+
+  //If message payload length fits in a single message
+  //then use the normal _write() function
   if (len <= max_frame_payload_size) {
-    //If message payload length fits in a single message
-    //then use the normal _write() function
     return _write(header,message,len,writeDirect);
   }
 
-  if (len >= 255*max_frame_payload_size) {
-    //If the message payload is too big, whe cannot generate enough fragments
-    //and enumerate them
+  //If the message payload is too big, whe cannot generate enough fragments
+  //and enumerate them
+  if (len > 255*max_frame_payload_size) {
+
     txSuccess = false;
     return txSuccess;
   }
-  //The payload is smaller than 6kBytes. We cann transmit it.
+
+  //The payload is smaller than MAX_PAYLOAD_SIZE and we can enumerate the fragments.
+  // --> We cann transmit the message.
 
   //Divide the message payload into chuncks of max_frame_payload_size
   uint8_t fragment_id = 1 + ((len - 1) / max_frame_payload_size);  //the number of fragments to send = ceil(len/max_frame_payload_size)
   uint8_t msgCount = 0;
 
-  IF_SERIAL_DEBUG(printf("%u: NET total message fragments %i\n\r",millis(),fragment_id););
+  IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET total message fragments %i\n\r",millis(),fragment_id););
 
   //Iterate over the payload chuncks
   //  Assemble a new message, copy and fill out the header
@@ -338,34 +378,38 @@ bool RF24Network::write(RF24NetworkHeader& header,const void* message, size_t le
   while (fragment_id > 0) {
 
     //Copy and fill out the header
-    RF24NetworkHeader fragmentHeader;
-    fragmentHeader = header;
+    RF24NetworkHeader fragmentHeader = header;
     fragmentHeader.fragment_id = fragment_id;
 
+    if (fragment_id == 1) {
+      fragmentHeader.type = NETWORK_LAST_FRAGMENT;  //Set the last fragment flag to indicate the last fragment
+    } else {
+      fragmentHeader.type = NETWORK_MORE_FRAGMENTS; //Set the more fragments flag to indicate a fragmented frame
+    }
+
     size_t offset = msgCount*max_frame_payload_size;
+    size_t fragmentLen = std::min(len-offset,max_frame_payload_size);
 
-    IF_SERIAL_DEBUG(printf("%u: NET try to transmit msg with fragment '%i'\n\r",millis(),(msgCount+1)););
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET try to transmit fragmented payload of size %i Bytes with fragmentID '%i'\n\r",millis(),fragmentLen,fragment_id););
 
     //Try to send the payload chunk with the copied header
-    bool ok = _write(fragmentHeader,message+offset,len-offset,writeDirect);
+    bool ok = _write(fragmentHeader,message+offset,fragmentLen,writeDirect);
     if (!ok) {
-      IF_SERIAL_DEBUG(printf("%u: NET message transmission with fragmentID '%i' failed. Abort.\n\r",millis(),(msgCount+1)););
+      IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET message transmission with fragmentID '%i' failed. Abort.\n\r",millis(),fragment_id););
       txSuccess = false;
       break;
     }
-    IF_SERIAL_DEBUG(printf("%u: NET message transmission with fragmentID '%i' sucessfull.\n\r",millis(),(msgCount+1)););
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET message transmission with fragmentID '%i' sucessfull.\n\r",millis(),fragment_id););
 
     //Message was successful sent
     //Check and modify counters
     fragment_id--;
     msgCount++;
-
-    IF_SERIAL_DEBUG(printf("%u: NET DEBUG: fragmentID=%i msgCount=%i loop_done?=%i\n\r",millis(),fragment_id,msgCount,!(fragment_id > 0)););
   }
 
   //Return true if all the chuncks where sent successfuly
   //else return false
-  IF_SERIAL_DEBUG(printf("%u: NET total message fragments sent %i. Status",millis(),msgCount); printf("%s\n\r", ok ? "ok" : "not ok"););
+  IF_SERIAL_DEBUG(printf("%u: NET total message fragments sent %i. txSuccess ",millis(),msgCount); printf("%s\n\r", txSuccess ? "YES" : "NO"););
   return txSuccess;
 }
 /******************************************************************/
@@ -376,21 +420,26 @@ bool RF24Network::_write(RF24NetworkHeader& header,const void* message, size_t l
   header.from_node = node_address;
 
   // Build the full frame to send
-  if (len)
-    memcpy(frame_buffer + sizeof(RF24NetworkHeader),message,std::min(frame_size-sizeof(RF24NetworkHeader),len));
+  memcpy(frame_buffer,&header,sizeof(RF24NetworkHeader));
+  frame_size = sizeof(RF24NetworkHeader); //Set the current frame size
+  if (len) {
+    memcpy(frame_buffer + sizeof(RF24NetworkHeader),message,std::min(MAX_FRAME_SIZE-sizeof(RF24NetworkHeader),len));
+    frame_size += len; //Set the current frame size
+  }
 
   IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Sending %s\n\r"),millis(),header.toString()));
-  if (len)
+  if (frame_size)
   {
    // IF_SERIAL_DEBUG(const uint16_t* i = reinterpret_cast<const uint16_t*>(message);printf_P(PSTR("%u: NET message %04x\n\r"),millis(),*i));
-    IF_SERIAL_DEBUG(printf("%u: NET message ",millis());const char* charPtr = reinterpret_cast<const char*>(message);while(len--){ printf("%02x ",charPtr[len]);} printf("\n\r") );
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC frame size %i",millis(),frame_size););
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC frame ",millis()); const char* charPtr = reinterpret_cast<const char*>(frame_buffer); for (size_t i = 0; i < frame_size; i++) { printf("%02X ", charPtr[i]); }; printf("\n\r"));
   }
 
 
   // If the user is trying to send it to himself
   if ( header.to_node == node_address ){
     // Build the frame to send
-    RF24NetworkFrame frame = RF24NetworkFrame(header,message,sizeof(message));
+    RF24NetworkFrame frame = RF24NetworkFrame(header,message,std::min(MAX_FRAME_SIZE-sizeof(RF24NetworkHeader),len));
     // Just queue it in the received queue
     return enqueue(frame);
   }else{
diff --git a/RPi/RF24Network/RF24Network.h b/RPi/RF24Network/RF24Network.h
index e28454c1..c0d16fd4 100644
--- a/RPi/RF24Network/RF24Network.h
+++ b/RPi/RF24Network/RF24Network.h
@@ -25,17 +25,23 @@
 #include <sys/time.h>
 #include <stddef.h>
 #include <assert.h>
-//!#include <vector>
-#include <list>
+#include <map>
+#include <utility>      // std::pair
+#include <queue>
 #include "RF24Network_config.h"
-#include "CircularBuffer.h"
-#include "FrameLRUCache.h"
 
 #define MAX_FRAME_SIZE 32
 #define MAX_FRAME_BUFFER_SIZE 255
-#define MAX_PAYLOAD_SIZE ((MAX_FRAME_SIZE-sizeof(RF24NetworkHeader))*255)
+#define MAX_PAYLOAD_SIZE 1500
 #define MAX_LRU_CACHE_SIZE 32
 
+//Network header message types
+#define NETWORK_ACK_REQUEST 128
+#define NETWORK_ACK 129
+#define NETWORK_MORE_FRAGMENTS 130
+#define NETWORK_LAST_FRAGMENT 131
+
+
 class RF24;
 
 /**
@@ -96,8 +102,8 @@ struct RF24NetworkHeader
 struct RF24NetworkFrame
 {
   RF24NetworkHeader header; /**< Header which is sent with each message */
-  size_t payload_size; /**< The size in bytes of the payload length */
-  std::list<uint8_t> payload_buffer; /**< Vector to put the frame payload that will be sent/received over the air */
+  size_t message_size; /**< The size in bytes of the payload length */
+  uint8_t message_buffer[MAX_PAYLOAD_SIZE]; /**< Vector to put the frame payload that will be sent/received over the air */
 
   /**
    * Default constructor
@@ -110,39 +116,24 @@ struct RF24NetworkFrame
    * Send constructor
    *
    * Use this constructor to create a frame with header and payload and then send a message
-   *
-   * @code
-   *  RF24NetworkFrame frame(recipient_address,'t',message,sizeof(message));
-   *  network.write(frame);
-   * @endcode
-   *
-   * @param _to The logical node address where the message is going.
-   * @param _type The type of message which follows.  Only 0-127 are allowed for
-   * user messages.
-   * @param _payload The message content.
-   * @param _psize Length in bytes of the payload.
    */
-  RF24NetworkFrame(uint16_t _to, unsigned char _type = 0, const void* _payload = NULL, size_t _psize = 0) : header(RF24NetworkHeader(_to,_type)), payload_size(_psize) {
-    appendToPayload(_payload,payload_size);
+  RF24NetworkFrame(uint16_t _to, unsigned char _type = 0, const void* _message = NULL, size_t _len = 0) :
+                  header(RF24NetworkHeader(_to,_type)), message_size(_len) {
+    if (_message && _len) {
+      memcpy(message_buffer,_message,_len);
+    }
   }
 
   /**
    * Send constructor
    *
    * Use this constructor to create a frame with header and payload and then send a message
-   *
-   * @code
-   *  RF24NetworkHeader header(recipient_address,'t');
-   *  RF24NetworkFrame frame(header,message,sizeof(message));
-   *  network.write(frame);
-   * @endcode
-   *
-   * @param _header The header struct of the frame
-   * @param _payload The message content.
-   * @param _psize Length in bytes of the payload.
    */
-  RF24NetworkFrame(RF24NetworkHeader& _header, const void* _payload = NULL, size_t _psize = 0) : header(_header), payload_size(_psize) {
-    appendToPayload(_payload,payload_size);
+  RF24NetworkFrame(RF24NetworkHeader& _header, const void* _message = NULL, size_t _len = 0) :
+                  header(_header), message_size(_len) {
+    if (_message && _len) {
+      memcpy(message_buffer,_message,_len);
+    }
   }
 
   /**
@@ -156,47 +147,6 @@ struct RF24NetworkFrame
    */
   const char* toString(void) const;
 
-  /**
-   * Get the frame payload (message) as array
-   *
-   * Internally is the payload a vector.
-   * @return array pointer to the payload
-   */
-  const void* getPayloadArray(void) {
-    //!const void* res = &payload_buffer[0];
-    //!return res;
-    uint8_t *arr = new uint8_t[payload_buffer.size()];
-    std::copy(payload_buffer.begin(),payload_buffer.end(),arr);
-    return arr;
-  }
-
-  /**
-   *  Get the payload size
-   *
-   * @return Size in bytes of the current payload
-   */
-  size_t getPayloadSize(void) {
-    return payload_buffer.size();
-  }
-
-  /**
-   * Append the given payload to the current payload_buffer
-   *
-   */
-  void appendToPayload(const void* payload, size_t len) {
-    if (payload && len) {
-      if ((payload_buffer.size()+len) <= MAX_PAYLOAD_SIZE) {
-        //Cast the payload as uint8_t
-        const uint8_t *q = (const uint8_t *)payload;
-        //Append the payload to the buffer
-        payload_buffer.insert(payload_buffer.end(), q, q+len);
-        //Save space in RAM
-        //!payload_buffer.shrink_to_fit();
-      }
-    }
-    //Set the new payload_buffer size
-    payload_size = payload_buffer.size();
-  };
 };
 
 /**
@@ -373,6 +323,7 @@ class RF24Network
   uint8_t pipe_to_descendant( uint16_t node );
   void setup_address(void);
   bool _write(RF24NetworkHeader& header,const void* message, size_t len, uint16_t writeDirect);
+  void appendFragmentToFrame(RF24NetworkFrame frame);
 
 private:
 #if defined (RF24NetworkMulticast)
@@ -381,17 +332,17 @@ class RF24Network
 #endif
   RF24& radio; /**< Underlying radio driver, provides link/physical layers */
   uint16_t node_address; /**< Logical node address of this unit, 1 .. UINT_MAX */
-  const static unsigned int frame_size = MAX_FRAME_SIZE; /**< How large is each frame over the air */
-  const static unsigned int max_frame_payload_size = frame_size-sizeof(RF24NetworkHeader);
-  uint8_t frame_buffer[frame_size]; /**< Space to put the frame that will be sent/received over the air */
-  CircularBuffer<RF24NetworkFrame,MAX_FRAME_BUFFER_SIZE> frame_queue; /**< RPi can buffer 500 frames (16kB) - Arduino does 5 by default. Space for a small set of frames that need to be delivered to the app layer */
-  //!FrameLRUCache<uint16_t,RF24NetworkFrame,MAX_LRU_CACHE_SIZE> frameAssemblyCache;
+  uint8_t frame_size; /**< How large is each frame over the air */
+  const static unsigned int max_frame_payload_size = MAX_FRAME_SIZE-sizeof(RF24NetworkHeader);
+  uint8_t frame_buffer[MAX_FRAME_SIZE]; /**< Space to put the frame that will be sent/received over the air */
+  std::queue<RF24NetworkFrame> frame_queue;
+  std::map<std::pair<uint16_t, uint16_t>, RF24NetworkFrame> frameFragmentsCache;
+
 
   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 */
-  #define NETWORK_ACK_REQUEST 128
-  #define NETWORK_ACK 129
+
 };
 
 /**
diff --git a/RPi/RF24Network/RF24Network_config.h b/RPi/RF24Network/RF24Network_config.h
index 693e6715..fd3de785 100644
--- a/RPi/RF24Network/RF24Network_config.h
+++ b/RPi/RF24Network/RF24Network_config.h
@@ -15,8 +15,9 @@
 /********** USER CONFIG **************/
 
 //#define RF24NetworkMulticast
-//#define SERIAL_DEBUG  //Change #undef to #define for debug
+#define SERIAL_DEBUG  //Change #undef to #define for debug
 #define SERIAL_DEBUG_ROUTING
+//#define SERIAL_DEBUG_FRAGMENTATION
 
 /*************************************/
 
@@ -35,6 +36,12 @@
 #define IF_SERIAL_DEBUG(x)
 #endif
 
+#if defined (SERIAL_DEBUG_FRAGMENTATION)
+#define IF_SERIAL_DEBUG_FRAGMENTATION(x) ({x;})
+#else
+#define IF_SERIAL_DEBUG_FRAGMENTATION(x)
+#endif
+
 // Avoid spurious warnings
 #if ! defined( NATIVE ) && defined( ARDUINO )
 #undef PROGMEM

From d49e9579b1bdf173606084223c0bf42175a7cb66 Mon Sep 17 00:00:00 2001
From: Rei <devel@reixd.net>
Date: Fri, 5 Sep 2014 17:14:51 +0200
Subject: [PATCH 09/10] Fully functional fragmentation and reassembly
 implementation for large payloads. Fragmentation is transparent to calling
 application.

TODO:
        - multicast fragmentation
        - test with multiple nodes in a larger network
        - use a circular queue for the frame_queue data structure
        - use a LRUCache data structure for the frame reassembly
        - lower memory consumption
        - arduino porting
        - cleanup code
        - remove redundant and unnecessary code

- Based on IPv4 fragmentation https://tools.ietf.org/html/rfc791.
- Tested only on Raspberry Pi, may not work in Arduinos due to memory usage
  Tested only with two raspberries using NRF24L01+ 10 meters apart.
- The lib is capable to detect if the message payload is bigger than frame_size-sizeof(Header)
  and split the payload into chucks and send them separately.
- This commit introduces two new flag types:
        - NETWORK_MORE_FRAGMENTS
        - NETWORK_LAST_FRAGMENT
- As of IPv4 fragmentation this flags are used to mark the frames to notify the receiver if more
  fragments will come or this is the last fragment.
- The previous _write() function to transmit the frames is used.
- Changes in payload size management were made to allow dynamic payload sizes without the need
  to define a field in the header.
- Introduce a new struct type "RF24NetworkFrame" for better frame handling inside the lib.
  This type encapsulates the header, the current size of the payload and a (fixed size) array
  containing the payload.
- The frame_buffer data structure was changes in favor of a std::queue for better handling.
- Make some changes renaming variables and defining the values.
- Use a std::map with double key (header.to_from,header.id) to identify the incoming fragments,
  allowing the reassembly of multiple transmission simultaneously.
- The reassembly of frames happens in the enqueue(frame) function.
  Based on the fragment_id and header.id the fragments are handled differently and in the end
  the completely assembled frames are queued in the frame_queue presenting them to the calling
  application.
- Introduce a new debug flag to print fragmentation debug messages.
- Use definitions for static values like frame size or payload max size.
- Strip trailing spaces and fix some indentation issues.
---
 RPi/RF24Network/RF24Network.cpp      | 149 ++++++++++++++++++---------
 RPi/RF24Network/RF24Network.h        | 111 ++++++--------------
 RPi/RF24Network/RF24Network_config.h |   9 +-
 3 files changed, 138 insertions(+), 131 deletions(-)

diff --git a/RPi/RF24Network/RF24Network.cpp b/RPi/RF24Network/RF24Network.cpp
index 9602eb73..0f248de4 100644
--- a/RPi/RF24Network/RF24Network.cpp
+++ b/RPi/RF24Network/RF24Network.cpp
@@ -32,7 +32,7 @@ uint32_t nFails = 0, nOK=0;
 
 /******************************************************************/
 
-RF24Network::RF24Network( RF24& _radio ): radio(_radio)
+RF24Network::RF24Network( RF24& _radio ): radio(_radio), frame_size(MAX_FRAME_SIZE)
 {}
 
 /******************************************************************/
@@ -53,6 +53,7 @@ void RF24Network::begin(uint8_t _channel, uint16_t _node_address ) {
   radio.setDataRate(RF24_1MBPS);
   radio.setCRCLength(RF24_CRC_16);
   radio.enableDynamicAck();
+  radio.enableDynamicPayloads();
 
   //uint8_t retryVar = (node_address % 7) + 5;
   uint8_t retryVar = (((node_address % 6)+1) *2) + 3;
@@ -110,16 +111,20 @@ uint8_t RF24Network::update(void)
       memcpy(&header,frame_buffer,sizeof(RF24NetworkHeader));
 
       IF_SERIAL_DEBUG(printf_P("%u: 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("%u: NET message %04x\n\r",millis(),*i));
+      if (len) {
+        IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC frame size %i",millis(),len););
+        IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC frame ",millis()); const char* charPtr = reinterpret_cast<const char*>(frame_buffer); for (size_t i = 0; i < len; i++) { printf("%02X ", charPtr[i]); }; printf("\n\r"));
+      }
 
       // Throw it away if it's not a valid address
       if ( !is_valid_address(header.to_node) ){
         continue;
       }
 
+      IF_SERIAL_DEBUG(printf_P("%u: MAC Valid frame from %i with size %i received.\n\r",millis(),header.from_node,len));
+
       // Build the full frame
-      size_t payload_size = len-sizeof(RF24NetworkHeader);
-      RF24NetworkFrame frame = RF24NetworkFrame(header,frame_buffer+sizeof(RF24NetworkHeader),payload_size);
+      RF24NetworkFrame frame = RF24NetworkFrame(header,frame_buffer+sizeof(RF24NetworkHeader),len-sizeof(RF24NetworkHeader));
 
       uint8_t res = header.type;
       // Is this for us?
@@ -186,27 +191,30 @@ uint8_t RF24Network::update(void)
 bool RF24Network::enqueue(RF24NetworkFrame frame) {
   bool result = false;
 
-  if (frame.header.fragment_id > 0) {
-    IF_SERIAL_DEBUG(printf("%u: NET message as fragment %i received\n\r",millis(),header.fragment_id););
-
-    //if fragment_id > 1 then
-    if (frame.header.fragment_id > 1) {
-      //Enqueue the frame with it fragmented payload in the LRUCache
-      //The cache will assemble all payloads into one big payload
-      //!frameAssemblyCache.put(frame.header.from_node,frame);
-      result = true;
-    } else if (frame.header.fragment_id == 1) {
-      //if we got a fragment_id == 1, then we got the last fragment
-      //Enqueue this frame into the frame_queue
-      //!frame_queue.push( frameAssemblyCache.get(frame.header.from_node) );
-      result = true;
-    } else {
-      //  otherwise discard the message with the large payload
-      result = false;
-    }
+  if (frame.header.fragment_id > 1 && frame.header.type == NETWORK_MORE_FRAGMENTS) {
+    //Set the more fragments flag to indicate a fragmented frame
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC fragmented payload of size %i Bytes with fragmentID '%i' received.\n\r",millis(),frame.message_size,frame.header.fragment_id););
+
+    //Append payload
+    appendFragmentToFrame(frame);
+    result = true;
+
+  } else if (frame.header.fragment_id == 1 && frame.header.type == NETWORK_LAST_FRAGMENT) {
+    //Set the last fragment flag to indicate the last fragment
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC Last fragment with size %i Bytes and fragmentID '%i' received.\n\r",millis(),frame.message_size,frame.header.fragment_id););
+
+    //Append payload
+    appendFragmentToFrame(frame);
+
+    IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Enqueue assembled frame @%x "),millis(),frame_queue.size()));
+    //Push the assembled frame in the frame_queue and remove it from cache
+    frame_queue.push( frameFragmentsCache[ std::make_pair(frame.header.from_node,frame.header.id) ] );
+    frameFragmentsCache.erase( std::make_pair(frame.header.from_node,frame.header.id) );
+
+    result = true;
 
   } else {
-    IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Enqueue @%x "),millis(),frame_queue.remain()));
+    IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Enqueue @%x "),millis(),frame_queue.size()));
 
     // Copy the current frame into the frame queue
     frame_queue.push(frame);
@@ -224,10 +232,31 @@ bool RF24Network::enqueue(RF24NetworkFrame frame) {
 
 /******************************************************************/
 
+void RF24Network::appendFragmentToFrame(RF24NetworkFrame frame) {
+
+  if (frameFragmentsCache.count(std::make_pair(frame.header.from_node,frame.header.id)) == 0 ) {
+    //This is the first of many fragments
+    frameFragmentsCache[ std::make_pair(frame.header.from_node,frame.header.id) ] = frame;
+  } else {
+    //We have at least received one fragments.
+
+    //Append payload
+    RF24NetworkFrame *f = &(frameFragmentsCache[ std::make_pair(frame.header.from_node,frame.header.id) ]);
+    memcpy(f->message_buffer+f->message_size, frame.message_buffer, frame.message_size);
+
+    //Increment message size
+    f->message_size += frame.message_size;
+    //Update header
+    f->header = frame.header;
+  }
+}
+
+/******************************************************************/
+
 bool RF24Network::available(void)
 {
   // Are there frames on the queue for us?
-  return (!frame_queue.isEmpty());
+  return (!frame_queue.empty());
 }
 
 /******************************************************************/
@@ -259,17 +288,20 @@ size_t RF24Network::read(RF24NetworkHeader& header,void* message, size_t maxlen)
 
   if ( available() )
   {
-    RF24NetworkFrame frame = frame_queue.pop();
+    RF24NetworkFrame frame = frame_queue.front();
 
     // How much buffer size should we actually copy?
-    bufsize = std::min(frame.getPayloadSize(),maxlen);
+    bufsize = std::min(frame.message_size,maxlen);
 
     memcpy(&header,&(frame.header),sizeof(RF24NetworkHeader));
-    memcpy(message,frame.getPayloadArray(),bufsize);
+    memcpy(message,frame.message_buffer,bufsize);
 
-    IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Received %s\n\r"),millis(),header.toString()));
-  }
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET message size %i\n",millis(),frame.message_size););
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET message ",millis()); const char* charPtr = reinterpret_cast<const char*>(message); for (size_t i = 0; i < bufsize; i++) { printf("%02X ", charPtr[i]); }; printf("\n\r"));
+    IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET readed %s\n\r"),millis(),header.toString()));
 
+    frame_queue.pop();
+  }
   return bufsize;
 }
 
@@ -309,25 +341,33 @@ bool RF24Network::write(RF24NetworkHeader& header,const void* message, size_t le
   bool txSuccess = true;
 
   //Check payload size
+  if (len > MAX_PAYLOAD_SIZE) {
+    IF_SERIAL_DEBUG(printf("%u: NET write message failed. Given 'len' is bigger than the MAX Payload size of %i\n\r",millis(),MAX_PAYLOAD_SIZE););
+    return false;
+  }
+
+  //If message payload length fits in a single message
+  //then use the normal _write() function
   if (len <= max_frame_payload_size) {
-    //If message payload length fits in a single message
-    //then use the normal _write() function
     return _write(header,message,len,writeDirect);
   }
 
-  if (len >= 255*max_frame_payload_size) {
-    //If the message payload is too big, whe cannot generate enough fragments
-    //and enumerate them
+  //If the message payload is too big, whe cannot generate enough fragments
+  //and enumerate them
+  if (len > 255*max_frame_payload_size) {
+
     txSuccess = false;
     return txSuccess;
   }
-  //The payload is smaller than 6kBytes. We cann transmit it.
+
+  //The payload is smaller than MAX_PAYLOAD_SIZE and we can enumerate the fragments.
+  // --> We cann transmit the message.
 
   //Divide the message payload into chuncks of max_frame_payload_size
   uint8_t fragment_id = 1 + ((len - 1) / max_frame_payload_size);  //the number of fragments to send = ceil(len/max_frame_payload_size)
   uint8_t msgCount = 0;
 
-  IF_SERIAL_DEBUG(printf("%u: NET total message fragments %i\n\r",millis(),fragment_id););
+  IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET total message fragments %i\n\r",millis(),fragment_id););
 
   //Iterate over the payload chuncks
   //  Assemble a new message, copy and fill out the header
@@ -338,34 +378,38 @@ bool RF24Network::write(RF24NetworkHeader& header,const void* message, size_t le
   while (fragment_id > 0) {
 
     //Copy and fill out the header
-    RF24NetworkHeader fragmentHeader;
-    fragmentHeader = header;
+    RF24NetworkHeader fragmentHeader = header;
     fragmentHeader.fragment_id = fragment_id;
 
+    if (fragment_id == 1) {
+      fragmentHeader.type = NETWORK_LAST_FRAGMENT;  //Set the last fragment flag to indicate the last fragment
+    } else {
+      fragmentHeader.type = NETWORK_MORE_FRAGMENTS; //Set the more fragments flag to indicate a fragmented frame
+    }
+
     size_t offset = msgCount*max_frame_payload_size;
+    size_t fragmentLen = std::min(len-offset,max_frame_payload_size);
 
-    IF_SERIAL_DEBUG(printf("%u: NET try to transmit msg with fragment '%i'\n\r",millis(),(msgCount+1)););
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET try to transmit fragmented payload of size %i Bytes with fragmentID '%i'\n\r",millis(),fragmentLen,fragment_id););
 
     //Try to send the payload chunk with the copied header
-    bool ok = _write(fragmentHeader,message+offset,len-offset,writeDirect);
+    bool ok = _write(fragmentHeader,message+offset,fragmentLen,writeDirect);
     if (!ok) {
-      IF_SERIAL_DEBUG(printf("%u: NET message transmission with fragmentID '%i' failed. Abort.\n\r",millis(),(msgCount+1)););
+      IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET message transmission with fragmentID '%i' failed. Abort.\n\r",millis(),fragment_id););
       txSuccess = false;
       break;
     }
-    IF_SERIAL_DEBUG(printf("%u: NET message transmission with fragmentID '%i' sucessfull.\n\r",millis(),(msgCount+1)););
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: NET message transmission with fragmentID '%i' sucessfull.\n\r",millis(),fragment_id););
 
     //Message was successful sent
     //Check and modify counters
     fragment_id--;
     msgCount++;
-
-    IF_SERIAL_DEBUG(printf("%u: NET DEBUG: fragmentID=%i msgCount=%i loop_done?=%i\n\r",millis(),fragment_id,msgCount,!(fragment_id > 0)););
   }
 
   //Return true if all the chuncks where sent successfuly
   //else return false
-  IF_SERIAL_DEBUG(printf("%u: NET total message fragments sent %i. Status",millis(),msgCount); printf("%s\n\r", ok ? "ok" : "not ok"););
+  IF_SERIAL_DEBUG(printf("%u: NET total message fragments sent %i. txSuccess ",millis(),msgCount); printf("%s\n\r", txSuccess ? "YES" : "NO"););
   return txSuccess;
 }
 /******************************************************************/
@@ -376,21 +420,26 @@ bool RF24Network::_write(RF24NetworkHeader& header,const void* message, size_t l
   header.from_node = node_address;
 
   // Build the full frame to send
-  if (len)
-    memcpy(frame_buffer + sizeof(RF24NetworkHeader),message,std::min(frame_size-sizeof(RF24NetworkHeader),len));
+  memcpy(frame_buffer,&header,sizeof(RF24NetworkHeader));
+  frame_size = sizeof(RF24NetworkHeader); //Set the current frame size
+  if (len) {
+    memcpy(frame_buffer + sizeof(RF24NetworkHeader),message,std::min(MAX_FRAME_SIZE-sizeof(RF24NetworkHeader),len));
+    frame_size += len; //Set the current frame size
+  }
 
   IF_SERIAL_DEBUG(printf_P(PSTR("%u: NET Sending %s\n\r"),millis(),header.toString()));
-  if (len)
+  if (frame_size)
   {
    // IF_SERIAL_DEBUG(const uint16_t* i = reinterpret_cast<const uint16_t*>(message);printf_P(PSTR("%u: NET message %04x\n\r"),millis(),*i));
-    IF_SERIAL_DEBUG(printf("%u: NET message ",millis());const char* charPtr = reinterpret_cast<const char*>(message);while(len--){ printf("%02x ",charPtr[len]);} printf("\n\r") );
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC frame size %i",millis(),frame_size););
+    IF_SERIAL_DEBUG_FRAGMENTATION(printf("%u: MAC frame ",millis()); const char* charPtr = reinterpret_cast<const char*>(frame_buffer); for (size_t i = 0; i < frame_size; i++) { printf("%02X ", charPtr[i]); }; printf("\n\r"));
   }
 
 
   // If the user is trying to send it to himself
   if ( header.to_node == node_address ){
     // Build the frame to send
-    RF24NetworkFrame frame = RF24NetworkFrame(header,message,sizeof(message));
+    RF24NetworkFrame frame = RF24NetworkFrame(header,message,std::min(MAX_FRAME_SIZE-sizeof(RF24NetworkHeader),len));
     // Just queue it in the received queue
     return enqueue(frame);
   }else{
diff --git a/RPi/RF24Network/RF24Network.h b/RPi/RF24Network/RF24Network.h
index e28454c1..c0d16fd4 100644
--- a/RPi/RF24Network/RF24Network.h
+++ b/RPi/RF24Network/RF24Network.h
@@ -25,17 +25,23 @@
 #include <sys/time.h>
 #include <stddef.h>
 #include <assert.h>
-//!#include <vector>
-#include <list>
+#include <map>
+#include <utility>      // std::pair
+#include <queue>
 #include "RF24Network_config.h"
-#include "CircularBuffer.h"
-#include "FrameLRUCache.h"
 
 #define MAX_FRAME_SIZE 32
 #define MAX_FRAME_BUFFER_SIZE 255
-#define MAX_PAYLOAD_SIZE ((MAX_FRAME_SIZE-sizeof(RF24NetworkHeader))*255)
+#define MAX_PAYLOAD_SIZE 1500
 #define MAX_LRU_CACHE_SIZE 32
 
+//Network header message types
+#define NETWORK_ACK_REQUEST 128
+#define NETWORK_ACK 129
+#define NETWORK_MORE_FRAGMENTS 130
+#define NETWORK_LAST_FRAGMENT 131
+
+
 class RF24;
 
 /**
@@ -96,8 +102,8 @@ struct RF24NetworkHeader
 struct RF24NetworkFrame
 {
   RF24NetworkHeader header; /**< Header which is sent with each message */
-  size_t payload_size; /**< The size in bytes of the payload length */
-  std::list<uint8_t> payload_buffer; /**< Vector to put the frame payload that will be sent/received over the air */
+  size_t message_size; /**< The size in bytes of the payload length */
+  uint8_t message_buffer[MAX_PAYLOAD_SIZE]; /**< Vector to put the frame payload that will be sent/received over the air */
 
   /**
    * Default constructor
@@ -110,39 +116,24 @@ struct RF24NetworkFrame
    * Send constructor
    *
    * Use this constructor to create a frame with header and payload and then send a message
-   *
-   * @code
-   *  RF24NetworkFrame frame(recipient_address,'t',message,sizeof(message));
-   *  network.write(frame);
-   * @endcode
-   *
-   * @param _to The logical node address where the message is going.
-   * @param _type The type of message which follows.  Only 0-127 are allowed for
-   * user messages.
-   * @param _payload The message content.
-   * @param _psize Length in bytes of the payload.
    */
-  RF24NetworkFrame(uint16_t _to, unsigned char _type = 0, const void* _payload = NULL, size_t _psize = 0) : header(RF24NetworkHeader(_to,_type)), payload_size(_psize) {
-    appendToPayload(_payload,payload_size);
+  RF24NetworkFrame(uint16_t _to, unsigned char _type = 0, const void* _message = NULL, size_t _len = 0) :
+                  header(RF24NetworkHeader(_to,_type)), message_size(_len) {
+    if (_message && _len) {
+      memcpy(message_buffer,_message,_len);
+    }
   }
 
   /**
    * Send constructor
    *
    * Use this constructor to create a frame with header and payload and then send a message
-   *
-   * @code
-   *  RF24NetworkHeader header(recipient_address,'t');
-   *  RF24NetworkFrame frame(header,message,sizeof(message));
-   *  network.write(frame);
-   * @endcode
-   *
-   * @param _header The header struct of the frame
-   * @param _payload The message content.
-   * @param _psize Length in bytes of the payload.
    */
-  RF24NetworkFrame(RF24NetworkHeader& _header, const void* _payload = NULL, size_t _psize = 0) : header(_header), payload_size(_psize) {
-    appendToPayload(_payload,payload_size);
+  RF24NetworkFrame(RF24NetworkHeader& _header, const void* _message = NULL, size_t _len = 0) :
+                  header(_header), message_size(_len) {
+    if (_message && _len) {
+      memcpy(message_buffer,_message,_len);
+    }
   }
 
   /**
@@ -156,47 +147,6 @@ struct RF24NetworkFrame
    */
   const char* toString(void) const;
 
-  /**
-   * Get the frame payload (message) as array
-   *
-   * Internally is the payload a vector.
-   * @return array pointer to the payload
-   */
-  const void* getPayloadArray(void) {
-    //!const void* res = &payload_buffer[0];
-    //!return res;
-    uint8_t *arr = new uint8_t[payload_buffer.size()];
-    std::copy(payload_buffer.begin(),payload_buffer.end(),arr);
-    return arr;
-  }
-
-  /**
-   *  Get the payload size
-   *
-   * @return Size in bytes of the current payload
-   */
-  size_t getPayloadSize(void) {
-    return payload_buffer.size();
-  }
-
-  /**
-   * Append the given payload to the current payload_buffer
-   *
-   */
-  void appendToPayload(const void* payload, size_t len) {
-    if (payload && len) {
-      if ((payload_buffer.size()+len) <= MAX_PAYLOAD_SIZE) {
-        //Cast the payload as uint8_t
-        const uint8_t *q = (const uint8_t *)payload;
-        //Append the payload to the buffer
-        payload_buffer.insert(payload_buffer.end(), q, q+len);
-        //Save space in RAM
-        //!payload_buffer.shrink_to_fit();
-      }
-    }
-    //Set the new payload_buffer size
-    payload_size = payload_buffer.size();
-  };
 };
 
 /**
@@ -373,6 +323,7 @@ class RF24Network
   uint8_t pipe_to_descendant( uint16_t node );
   void setup_address(void);
   bool _write(RF24NetworkHeader& header,const void* message, size_t len, uint16_t writeDirect);
+  void appendFragmentToFrame(RF24NetworkFrame frame);
 
 private:
 #if defined (RF24NetworkMulticast)
@@ -381,17 +332,17 @@ class RF24Network
 #endif
   RF24& radio; /**< Underlying radio driver, provides link/physical layers */
   uint16_t node_address; /**< Logical node address of this unit, 1 .. UINT_MAX */
-  const static unsigned int frame_size = MAX_FRAME_SIZE; /**< How large is each frame over the air */
-  const static unsigned int max_frame_payload_size = frame_size-sizeof(RF24NetworkHeader);
-  uint8_t frame_buffer[frame_size]; /**< Space to put the frame that will be sent/received over the air */
-  CircularBuffer<RF24NetworkFrame,MAX_FRAME_BUFFER_SIZE> frame_queue; /**< RPi can buffer 500 frames (16kB) - Arduino does 5 by default. Space for a small set of frames that need to be delivered to the app layer */
-  //!FrameLRUCache<uint16_t,RF24NetworkFrame,MAX_LRU_CACHE_SIZE> frameAssemblyCache;
+  uint8_t frame_size; /**< How large is each frame over the air */
+  const static unsigned int max_frame_payload_size = MAX_FRAME_SIZE-sizeof(RF24NetworkHeader);
+  uint8_t frame_buffer[MAX_FRAME_SIZE]; /**< Space to put the frame that will be sent/received over the air */
+  std::queue<RF24NetworkFrame> frame_queue;
+  std::map<std::pair<uint16_t, uint16_t>, RF24NetworkFrame> frameFragmentsCache;
+
 
   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 */
-  #define NETWORK_ACK_REQUEST 128
-  #define NETWORK_ACK 129
+
 };
 
 /**
diff --git a/RPi/RF24Network/RF24Network_config.h b/RPi/RF24Network/RF24Network_config.h
index 693e6715..fd3de785 100644
--- a/RPi/RF24Network/RF24Network_config.h
+++ b/RPi/RF24Network/RF24Network_config.h
@@ -15,8 +15,9 @@
 /********** USER CONFIG **************/
 
 //#define RF24NetworkMulticast
-//#define SERIAL_DEBUG  //Change #undef to #define for debug
+#define SERIAL_DEBUG  //Change #undef to #define for debug
 #define SERIAL_DEBUG_ROUTING
+//#define SERIAL_DEBUG_FRAGMENTATION
 
 /*************************************/
 
@@ -35,6 +36,12 @@
 #define IF_SERIAL_DEBUG(x)
 #endif
 
+#if defined (SERIAL_DEBUG_FRAGMENTATION)
+#define IF_SERIAL_DEBUG_FRAGMENTATION(x) ({x;})
+#else
+#define IF_SERIAL_DEBUG_FRAGMENTATION(x)
+#endif
+
 // Avoid spurious warnings
 #if ! defined( NATIVE ) && defined( ARDUINO )
 #undef PROGMEM

From f45441532f2014a990e12d2e565e7b0a8a51baab Mon Sep 17 00:00:00 2001
From: Rei <devel@reixd.net>
Date: Fri, 5 Sep 2014 17:29:57 +0200
Subject: [PATCH 10/10] Remove not needed CircularBuffer data structure

---
 RPi/RF24Network/CircularBuffer.h | 78 --------------------------------
 1 file changed, 78 deletions(-)
 delete mode 100644 RPi/RF24Network/CircularBuffer.h

diff --git a/RPi/RF24Network/CircularBuffer.h b/RPi/RF24Network/CircularBuffer.h
deleted file mode 100644
index 22d3c236..00000000
--- a/RPi/RF24Network/CircularBuffer.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-  CircularBuffer.h - circular buffer library for Arduino.
-
-  Copyright (c) 2009 Hiroki Yagita.
-  Copyright (c) 2014 Rei <devel@reixd.net>.
-
-  Permission is hereby granted, free of charge, to any person obtaining
-  a copy of this software and associated documentation files (the
-  'Software'), to deal in the Software without restriction, including
-  without limitation the rights to use, copy, modify, merge, publish,
-  distribute, sublicense, and/or sell copies of the Software, and to
-  permit persons to whom the Software is furnished to do so, subject to
-  the following conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-#ifndef CIRCULARBUFFER_h
-#define CIRCULARBUFFER_h
-#include <inttypes.h>
-
-template <typename T, uint16_t Size>
-class CircularBuffer {
-public:
-  enum {
-    Empty = 0,
-    Half = Size / 2,
-    Full = Size,
-  };
-
-  CircularBuffer() :
-    wp_(buf_), rp_(buf_), tail_(buf_+Size),  remain_(0), size_(Size) {}
-  ~CircularBuffer() {}
-  void push(T value) {
-    *wp_++ = value;
-    remain_++;
-    if (wp_ == tail_) wp_ = buf_;
-  }
-  T pop() {
-    T result = *rp_++;
-    remain_--;
-    if (rp_ == tail_) rp_ = buf_;
-    return result;
-  }
-  T front() {
-    T result = *rp_;
-    return result;
-  }
-  int remain() const {
-    return remain_;
-  }
-  bool isEmpty() {
-    if (remain_ > 0)
-      return true;
-    return false;
-  }
-  bool isFull() {
-    return (size_ == remain_);
-  }
-
-private:
-  T buf_[Size];
-  T *wp_;
-  T *rp_;
-  T *tail_;
-  uint16_t remain_;
-  uint16_t size_;
-};
-
-#endif