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