From 94dfbd50cecd21306e3b2bffbc34e048117c4d8f Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Thu, 18 Sep 2014 01:51:56 -0600 Subject: [PATCH] Cleanup for Aduino code - Reduced memory buffer by 64 bytes for ATTiny - Removed unused stuff - Added struct for getting routing info - Added address of pipe, to get direct child addresses - Removed type limitation on header initialization - Fix to allow multicast level 0 (node 00) - Need to align changed with RPi --- RF24Network.cpp | 229 ++++++++++++++++++++++++------------------- RF24Network.h | 143 ++++++++++++++++++++++++--- RF24Network_config.h | 2 +- 3 files changed, 258 insertions(+), 116 deletions(-) diff --git a/RF24Network.cpp b/RF24Network.cpp index d0ad310c..53737616 100644 --- a/RF24Network.cpp +++ b/RF24Network.cpp @@ -51,8 +51,8 @@ void RF24Network::begin(uint8_t _channel, uint16_t _node_address ) // Set up the radio the way we want it to look radio.setChannel(_channel); - radio.setDataRate(RF24_1MBPS); - radio.setCRCLength(RF24_CRC_16); + //radio.setDataRate(RF24_1MBPS); + //radio.setCRCLength(RF24_CRC_16); radio.enableDynamicAck(); radio.enableDynamicPayloads(); // Use different retry periods to reduce data collisions @@ -100,13 +100,12 @@ uint8_t RF24Network::update(void) { // if there is data ready uint8_t pipe_num; + uint8_t returnVal = 0; + while ( radio.isValid() && radio.available())//&pipe_num) ) { - // Dump the payloads until we've gotten everything - - //while (radio.available()) - //{ + // Dump the payloads until we've gotten everything // Fetch the payload, and see if this was the last one. radio.read( frame_buffer, sizeof(frame_buffer) ); @@ -126,9 +125,10 @@ uint8_t RF24Network::update(void) if ( header.to_node == node_address ){ if(res == NETWORK_ACK){ // If received a routing payload, (Network ACK) discard it, and indicate what it was. #ifdef SERIAL_DEBUG_ROUTING - //printf_P(PSTR("MAC: Network ACK Rcvd \n")); + printf_P(PSTR("MAC: Network ACK Rcvd \n")); #endif - return NETWORK_ACK; + returnVal = NETWORK_ACK; + continue; } // Add it to the buffer of frames for us enqueue(); @@ -158,8 +158,8 @@ uint8_t RF24Network::update(void) 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 + //if(radio.available()){printf("------FLUSHED DATA --------------");} + write(header.to_node,1); //Send it on, indicate it is a routed payload #endif } @@ -181,8 +181,7 @@ uint8_t RF24Network::update(void) #endif //} } - - return 0; + return returnVal; } /******************************************************************/ @@ -286,7 +285,7 @@ bool RF24Network::multicast(RF24NetworkHeader& header,const void* message, size_ IF_SERIAL_DEBUG(const uint16_t* i = reinterpret_cast(message);printf_P(PSTR("%lu: NET message %04x\n\r"),millis(),*i)); } - return write(levelToAddress(level),4); + return write(levelToAddress(level),USER_TX_MULTICAST); } #endif @@ -324,18 +323,18 @@ bool RF24Network::_write(RF24NetworkHeader& header,const void* message, size_t l if ( header.to_node == node_address ){ // Just queue it in the received queue return enqueue(); - }else{ + } // Otherwise send it out over the air if(writeDirect != 070){ if(header.to_node == writeDirect){ - return write(writeDirect,2); + return write(writeDirect,USER_TX_TO_PHYSICAL_ADDRESS); }else{ - return write(writeDirect,3); + return write(writeDirect,USER_TX_TO_LOGICAL_ADDRESS); } }else{ - return write(header.to_node,0); + return write(header.to_node,TX_NORMAL); } - } + } /******************************************************************/ @@ -344,107 +343,60 @@ bool RF24Network::write(uint16_t to_node, uint8_t directTo) // Direct To: 0 = F { bool ok = false; 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); + //const uint16_t fromAddress = frame_buffer[0] | (frame_buffer[1] << 8); // Throw it away if it's not a valid address if ( !is_valid_address(to_node) ) - return false; - - - // Where do we send this? By default, to our parent - uint16_t send_node = parent_node; - - // On which pipe - uint8_t send_pipe = parent_pipe %5; + return false; - - 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; - // To its listening pipe - send_pipe = 5; - } - // If the node is a child of a child - // talk on our child's listening pipe, - // and let the direct child relay it. - else if ( is_descendant(to_node) ) - { - send_node = direct_child_route_to(to_node); - send_pipe = 5; - } - - - //if( ( send_node != to_node) || frame_buffer[6] == NETWORK_ACK ){ -// multicast = 0; - //} - // printf("Multi %d\n\r",multicast); + //Load info into our conversion structure, and get the converted address info + conversion.send_node = to_node; + conversion.send_pipe = directTo; + conversion.multicast = multicast; + logicalToPhysicalAddress(&conversion); - IF_SERIAL_DEBUG(printf_P(PSTR("%lu: MAC Sending to 0%o via 0%o on pipe %x\n\r"),millis(),logicalAddress,send_node,send_pipe)); + IF_SERIAL_DEBUG(printf_P(PSTR("%lu: MAC Sending to 0%o via 0%o on pipe %x\n\r"),millis(),to_node,conversion.send_node,conversion.send_pipe)); - + /**Write it*/ + ok=write_to_pipe(conversion.send_node, conversion.send_pipe, conversion.multicast); - - ok=write_to_pipe(send_node, send_pipe, multicast); - #ifdef SERIAL_DEBUG_ROUTING - if(!ok){ printf_P(PSTR("%lu: 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("%lu: MAC Send fail to 0%o via 0%o on pipe %x\n\r"),millis(),to_node,conversion.send_node,conversion.send_pipe); } #endif - if( directTo == 1 && ok && send_node == to_node && frame_buffer[6] != NETWORK_ACK && fromAddress != node_address){ - frame_buffer[6] = NETWORK_ACK; // Set the payload type to NETWORK_ACK - //frame_buffer[7] = 0; - frame_buffer[2] = frame_buffer[0]; frame_buffer[3] = frame_buffer[1]; // Change the 'to' address to the 'from' address - dynLen=8; - write(fromAddress,1); // Send it back as a routed message + if( directTo == TX_ROUTED && ok && conversion.send_node == to_node && frame_buffer[6] != NETWORK_ACK ){ + + RF24NetworkHeader& header = * reinterpret_cast(frame_buffer); + header.type = NETWORK_ACK; // Set the payload type to NETWORK_ACK + header.to_node = header.from_node; // Change the 'to' address to the 'from' address + dynLen=8; + + conversion.send_node=header.from_node; + conversion.send_pipe = TX_ROUTED; + logicalToPhysicalAddress(&conversion); + + //Write the data using the resulting physical address + write_to_pipe(conversion.send_node, conversion.send_pipe, multicast); + dynLen=0; #if defined (SERIAL_DEBUG_ROUTING) - //if(!test){ - //printf_P(PSTR("MAC: Route OK to 0%o ACK sent to 0%o\n"),send_node,fromAddress); - //}else{ - //printf("ACK send fail"); - //} - + printf_P(PSTR("%lu MAC: Route OK to 0%o ACK sent to 0%o\n"),millis(),conversion.send_node,fromAddress); #endif - } - - + } + // if(!ok){ printf_P(PSTR("%lu: MAC No Ack from 0%o via 0%o on pipe %x\n\r"),millis(),to_node,send_node,send_pipe); } - - //printf_P(PSTR("%lu: MAC Sending to 0%o via 0%o on pipe %x\n\r"),millis(),to_node,send_node,send_pipe); - // NOT NEEDED anymore. Now all reading pipes are open to start. -#if 0 - // If we are talking on our talking pipe, it's possible that no one is listening. - // If this fails, try sending it on our parent's listening pipe. That will wake - // it up, and next time it will listen to us. - - //if ( !ok && send_node == parent_node ) - // ok = write_to_pipe( parent_node, 0 ); -#endif - #if !defined (DUAL_HEAD_RADIO) // Now, continue listening radio.startListening(); #endif - if( ok && (send_node != logicalAddress) && (directTo==0 || directTo == 3 )){ + if( ok && (conversion.send_node != to_node) && (directTo==0 || directTo == 3 )){ uint32_t reply_time = millis(); while( update() != NETWORK_ACK){ if(millis() - reply_time > routeTimeout){ #ifdef SERIAL_DEBUG_ROUTING - printf_P(PSTR("%lu: MAC Network ACK fail from 0%o via 0%o on pipe %x\n\r"),millis(),logicalAddress,send_node,send_pipe); + printf_P(PSTR("%lu: MAC Network ACK fail from 0%o via 0%o on pipe %x\n\r"),millis(),to_node,conversion.send_node,conversion.send_pipe); #endif ok=0; break; @@ -462,6 +414,56 @@ bool RF24Network::write(uint16_t to_node, uint8_t directTo) // Direct To: 0 = F /******************************************************************/ + // Provided the to_node and directTo option, it will return the resulting node and pipe +bool RF24Network::logicalToPhysicalAddress(logicalToPhysicalStruct *conversionInfo){ + + //Create pointers so this makes sense.. kind of + //We take in the to_node(logical) now, at the end of the function, output the send_node(physical) address, etc. + //back to the original memory address that held the logical information. + uint16_t *to_node = &conversionInfo->send_node; + uint8_t *directTo = &conversionInfo->send_pipe; + bool *multicast = &conversionInfo->multicast; + + // Where do we send this? By default, to our parent + uint16_t pre_conversion_send_node = parent_node; + + // On which pipe + uint8_t pre_conversion_send_pipe = parent_pipe %5; + + if(*directTo > TX_ROUTED ){ + pre_conversion_send_node = *to_node; + *multicast = 1; + if(*directTo == USER_TX_MULTICAST){ + pre_conversion_send_pipe=0; + } + } + // If the node is a direct child, + else + if ( is_direct_child(*to_node) ) + { + // Send directly + pre_conversion_send_node = *to_node; + // To its listening pipe + pre_conversion_send_pipe = 5; + } + // If the node is a child of a child + // talk on our child's listening pipe, + // and let the direct child relay it. + else if ( is_descendant(*to_node) ) + { + pre_conversion_send_node = direct_child_route_to(*to_node); + pre_conversion_send_pipe = 5; + } + + *to_node = pre_conversion_send_node; + *directTo = pre_conversion_send_pipe; + + return 1; + +} + +/********************************************************/ + bool RF24Network::write_to_pipe( uint16_t node, uint8_t pipe, bool multicast ) { @@ -478,7 +480,8 @@ bool RF24Network::write_to_pipe( uint16_t node, uint8_t pipe, bool multicast ) size_t wLen = dynLen ? dynLen: frame_size; radio.writeFast(frame_buffer, wLen,multicast); ok = radio.txStandBy(txTimeout); - + + #else radio1.openWritingPipe(out_pipe); radio1.writeFast(frame_buffer, frame_size); @@ -573,21 +576,38 @@ void RF24Network::setup_address(void) #endif } +/******************************************************************/ +uint16_t RF24Network::addressOfPipe( uint16_t node, uint8_t pipeNo ) +{ + //Say this node is 013 (1011), mask is 077 or (00111111) + //Say we want to use pipe 3 (11) + //6 bits in node mask, so shift pipeNo 6 times left and | into address + uint16_t m = node_mask >> 3; + uint8_t i=0; + + while (m){ //While there are bits left in the node mask + m>>=1; //Shift to the right + i++; //Count the # of increments + } + + return node | (pipeNo << i); +} + /******************************************************************/ uint16_t RF24Network::direct_child_route_to( uint16_t node ) { // Presumes that this is in fact a child!! - uint16_t child_mask = ( node_mask << 3 ) | 0B111; - return node & child_mask ; + return node & child_mask; + } /******************************************************************/ - +/* uint8_t RF24Network::pipe_to_descendant( uint16_t node ) { - uint16_t i = node; + uint16_t i = node; uint16_t m = node_mask; while (m) @@ -597,7 +617,7 @@ uint8_t RF24Network::pipe_to_descendant( uint16_t node ) } return i & 0B111; -} +}*/ /******************************************************************/ @@ -634,8 +654,13 @@ void RF24Network::multicastLevel(uint8_t level){ } uint16_t levelToAddress(uint8_t level){ + uint16_t levelAddr = 1; - levelAddr = levelAddr << ((level-1) * 3); + if(level){ + levelAddr = levelAddr << ((level-1) * 3); + }else{ + return 0; + } return levelAddr; } #endif diff --git a/RF24Network.h b/RF24Network.h index 5a06ac7c..47851a5a 100644 --- a/RF24Network.h +++ b/RF24Network.h @@ -19,6 +19,36 @@ #include #include "RF24Network_config.h" +/** + * Network Management message types for management of network frames and messages + * System discard types (128 to 147) Contain no user data, just additional system sub-types sent for informational purposes. (Initially within NETWORK_ACK responses) + * System retained types (148-167) Contain user data + * + * System types can also contain sub-types, included as information, TBD + * + */ + +/** System Discard Types */ +#define NETWORK_ACK_REQUEST 128 +#define NETWORK_ACK 129 + /**System-Sub Types (0-255)*/ + #define NETWORK_REQ_STREAM 11; + +/** System retained types */ +#define NETWORK_FIRST_FRAGMENT 148 +#define NETWORK_MORE_FRAGMENTS 149 +#define NETWORK_LAST_FRAGMENT 150 +/* System retained - response messages */ +#define NETWORK_REQ_ADDRESS 151 +#define NETWORK_ADDR_RESPONSE 152 + +/** Defines for handling written payloads */ +#define TX_NORMAL 0 +#define TX_ROUTED 1 +#define USER_TX_TO_PHYSICAL_ADDRESS 2 +#define USER_TX_TO_LOGICAL_ADDRESS 3 +#define USER_TX_MULTICAST 4 + class RF24; @@ -46,10 +76,14 @@ struct RF24NetworkHeader RF24NetworkHeader() {} /** - * Send constructor - * - * Use this constructor to create a header and then send a message - * + * Send constructor + * + * @note Raspberry Pi now supports fragmentation for very long messages, send as normal. Arduino, ATTiny will handle routing of fragmented messages, but cannot receive them properly + * @warning The latest updates to add fragmentation requires updating ALL devices + * + * + * Use this constructor to create a header and then send a message + * * @code * RF24NetworkHeader header(recipient_address,'t'); * network.write(header,&message,sizeof(message)); @@ -59,8 +93,9 @@ struct RF24NetworkHeader * @param _type The type of message which follows. Only 0-127 are allowed for * user messages. */ - RF24NetworkHeader(uint16_t _to, unsigned char _type = 0): to_node(_to), id(next_id++), type(_type&0x7f) {} - + //RF24NetworkHeader(uint16_t _to, unsigned char _type = 0): to_node(_to), id(next_id++), type(_type&0x7f) {} + RF24NetworkHeader(uint16_t _to, unsigned char _type = 0): to_node(_to), id(next_id++), type(_type) {} + /** * Create debugging string * @@ -73,6 +108,66 @@ 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 + */ +/** +@code + struct RF24NetworkFrame +{ + RF24NetworkHeader header; /**< Header which is sent with each message / + 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 / + uint8_t total_fragments; /**New (2014): Network ACKs: Efficient acknowledgement of network-wide transmissions, via dynamic radio acks and network protocol acks. * @li New (2014): Updated addressing standard for optimal radio transmission. diff --git a/RF24Network_config.h b/RF24Network_config.h index d8b01181..4f315272 100644 --- a/RF24Network_config.h +++ b/RF24Network_config.h @@ -24,7 +24,7 @@ //#define ENABLE_SLEEP_MODE //#define RF24NetworkMulticast //#define SERIAL_DEBUG -#define SERIAL_DEBUG_ROUTING +//#define SERIAL_DEBUG_ROUTING /*************************************/