From f7682e3e96a9dff726dfbd4405564d1ab6b321f9 Mon Sep 17 00:00:00 2001 From: TMRh20 Date: Thu, 5 Nov 2015 19:09:13 -0600 Subject: [PATCH] Improve address requests, docs update - getAddress() now returns -1 if failed instead of 0 - Remove sending network address from initial address request & remove address response struct - shortens request by 2 bytes - Minor clean up to dhcp function --- RF24Mesh.cpp | 94 +++++++++++++++++++--------------------------- RF24Mesh.h | 64 +++++++++++++++++++------------ library.properties | 2 +- 3 files changed, 80 insertions(+), 80 deletions(-) diff --git a/RF24Mesh.cpp b/RF24Mesh.cpp index 99f9017..1b160a9 100644 --- a/RF24Mesh.cpp +++ b/RF24Mesh.cpp @@ -128,7 +128,7 @@ bool RF24Mesh::checkConnection(){ /*****************************************************/ -uint16_t RF24Mesh::getAddress(uint8_t nodeID){ +int16_t RF24Mesh::getAddress(uint8_t nodeID){ //#if defined (ARDUINO_SAM_DUE) || defined (__linux) #if !defined RF24_TINY && !defined(MESH_NOMASTER) @@ -140,15 +140,16 @@ uint16_t RF24Mesh::getAddress(uint8_t nodeID){ return address; } } - return 0; + return -1; } #endif - if(mesh_address == MESH_DEFAULT_ADDRESS){ return 0; } + if(mesh_address == MESH_DEFAULT_ADDRESS){ return -1; } + if(!nodeID){return 0;} RF24NetworkHeader header( 00, MESH_ADDR_LOOKUP ); if(network.write(header,&nodeID,sizeof(nodeID)+1) ){ uint32_t timer=millis(), timeout = 500; while(network.update() != MESH_ADDR_LOOKUP){ - if(millis()-timer > timeout){ return 0; } + if(millis()-timer > timeout){ return -1; } } } uint16_t address; @@ -156,7 +157,7 @@ uint16_t RF24Mesh::getAddress(uint8_t nodeID){ return address; } -int RF24Mesh::getNodeID(uint16_t address){ +int16_t RF24Mesh::getNodeID(uint16_t address){ if(address == MESH_BLANK_ID){ return _nodeID; @@ -237,12 +238,7 @@ bool RF24Mesh::requestAddress(uint8_t level){ uint32_t timr = millis(); uint16_t *contactNode = 0; - struct addrResponseStruct{ - uint16_t requester; - uint16_t new_address; - }addrResponse; - - while(1){ + while(1){ bool goodSignal = radio.testRPD(); if(network.update() == NETWORK_POLL){ contactNode = (uint16_t*)(&network.frame_buffer); @@ -288,9 +284,8 @@ bool RF24Mesh::requestAddress(uint8_t level){ header.reserved = getNodeID(); header.to_node = *contactNode; - uint16_t addr = MESH_DEFAULT_ADDRESS; // Do a direct write (no ack) to the contact node. Include the nodeId and address. - network.write(header,&addr,sizeof(addrResponse),*contactNode); + network.write(header,0,0,*contactNode); #ifdef MESH_DEBUG_SERIAL Serial.print( millis() ); Serial.println(F(" MSH: Request address ")); #elif defined MESH_DEBUG_PRINTF @@ -315,19 +310,21 @@ bool RF24Mesh::requestAddress(uint8_t level){ #endif uint8_t registerAddrCount = 0; - memcpy(&addrResponse,network.frame_buffer+sizeof(RF24NetworkHeader),sizeof(addrResponse)); + uint16_t newAddress=0; + //memcpy(&addrResponse,network.frame_buffer+sizeof(RF24NetworkHeader),sizeof(addrResponse)); + memcpy(&newAddress,network.frame_buffer+sizeof(RF24NetworkHeader),sizeof(newAddress)); - if(!addrResponse.new_address || network.frame_buffer[7] != getNodeID() ){ + if(!newAddress || network.frame_buffer[7] != getNodeID() ){ #ifdef MESH_DEBUG_SERIAL Serial.print(millis()); Serial.println(F(" MSH: Response discarded, wrong node")); #elif defined MESH_DEBUG_PRINTF - printf("%u Response discarded, wrong node 0%o from node 0%o sending node 0%o\n",millis(),addrResponse.new_address,header.from_node,addrResponse.requester); + printf("%u Response discarded, wrong node 0%o from node 0%o sending node 0%o\n",millis(),newAddress,header.from_node,MESH_DEFAULT_ADDRESS); #endif return 0; } #ifdef MESH_DEBUG_SERIAL Serial.print( millis() );Serial.print(F(" Set address: ")); - newAddr = addrResponse.new_address; + newAddr = newAddress; while(newAddr){ addrs[count] = (newAddr & mask)+48; //get the individual Octal numbers, specified in chunks of 3 bits, convert to ASCII by adding 48 newAddr >>= 3; @@ -335,20 +332,17 @@ bool RF24Mesh::requestAddress(uint8_t level){ } Serial.println(addrs); #elif defined (MESH_DEBUG_PRINTF) - printf("Set address 0%o rcvd 0%o\n",mesh_address,addrResponse.new_address); + printf("Set address 0%o rcvd 0%o\n",mesh_address,newAddress); #endif - mesh_address = addrResponse.new_address; - //radio.begin(); + mesh_address = newAddress; + radio.stopListening(); delay(10); network.begin(mesh_address); header.to_node = 00; header.type = MESH_ADDR_CONFIRM; - //network.write(header,0,0); - //delay(55); + while( !network.write(header,0,0) ){ - //delay(55); - //printf("Retry register address...\n"); if(registerAddrCount++ >= 6 ){ return 0; } } @@ -452,39 +446,30 @@ void RF24Mesh::DHCP(){ RF24NetworkHeader header; memcpy(&header,network.frame_buffer,sizeof(RF24NetworkHeader)); - struct addrResponseStruct{ - uint16_t requester; - uint16_t new_address; - } addrResponse; - + uint16_t newAddress; + // Get the unique id of the requester uint8_t from_id = header.reserved; if(!from_id){ #ifdef MESH_DEBUG_PRINTF printf("MSH: Invalid id 0 rcvd\n"); #endif - //network.read(header,0,0); return; } - //network.read(header,&addrResponse,sizeof(addrResponse)); - memcpy(&addrResponse,network.frame_buffer+sizeof(RF24NetworkHeader),sizeof(addrResponse)); - - // Get the address of the sender (initial, or intermediary) - uint16_t fwd_by = header.from_node; + uint16_t fwd_by = 0; uint8_t shiftVal = 0; - - if(header.from_node == addrResponse.requester || header.from_node == MESH_DEFAULT_ADDRESS){ //Addresses 01-05 - fwd_by = 0; // No forwarding address - }else{ //Addresses 01111-05555 + + if( header.from_node != MESH_DEFAULT_ADDRESS){ + fwd_by = header.from_node; uint16_t m = fwd_by; uint8_t count = 0; while(m){ //Octal addresses convert nicely to binary in threes. Address 03 = B011 Address 033 = B011011 m >>= 3; //Find out how many digits are in the octal address count++; - } - shiftVal = count*3; //Now we know how many bits to shift when adding a child node 1-5 (B001 to B101) to any address + } + shiftVal = count*3; //Now we know how many bits to shift when adding a child node 1-5 (B001 to B101) to any address } #ifdef MESH_DEBUG_PRINTF @@ -494,8 +479,8 @@ void RF24Mesh::DHCP(){ for(int i=MESH_MAX_CHILDREN; i> 0; i--){ // For each of the possible addresses (5 max) bool found = 0; - addrResponse.new_address = fwd_by | (i << shiftVal); - if(!addrResponse.new_address ){ /*printf("dumped 0%o\n",addrResponse.new_address);*/ continue; } + newAddress = fwd_by | (i << shiftVal); + if(!newAddress ){ /*printf("dumped 0%o\n",newAddress);*/ continue; } for(uint8_t i=0; i < addrListTop; i++){ #if defined (MESH_DEBUG_MINIMAL) @@ -513,30 +498,29 @@ void RF24Mesh::DHCP(){ printf("ID: %d ADDR: 0%o\n", addrList[i].nodeID,addrList[i].address); #endif #endif - if( (addrList[i].address == addrResponse.new_address && addrList[i].nodeID != from_id ) || addrResponse.new_address == MESH_DEFAULT_ADDRESS){ + if( (addrList[i].address == newAddress && addrList[i].nodeID != from_id ) || newAddress == MESH_DEFAULT_ADDRESS){ found = 1; break; } } if(!found){ - + header.type = NETWORK_ADDR_RESPONSE; header.to_node = header.from_node; - //printf("Send resp %d\n",sizeof(addrResponse)); //This is a routed request to 00 - if(header.from_node != addrResponse.requester){ //Is NOT node 01 to 05 + if(header.from_node != MESH_DEFAULT_ADDRESS){ //Is NOT node 01 to 05 delay(2); - if( network.write(header,&addrResponse,sizeof(addrResponse)) ){ - //addrMap[from_id] = addrResponse.new_address; + if( network.write(header,&newAddress,sizeof(newAddress)) ){ + //addrMap[from_id] = newAddress; }else{ - network.write(header,&addrResponse,sizeof(addrResponse)); + network.write(header,&newAddress,sizeof(newAddress)); } }else{ delay(2); - network.write(header,&addrResponse,sizeof(addrResponse),header.to_node); + network.write(header,&newAddress,sizeof(newAddress),header.to_node); - //addrMap[from_id] = addrResponse.new_address; + //addrMap[from_id] = newAddress; } uint32_t timer=millis(); while(network.update() != MESH_ADDR_CONFIRM){ @@ -550,7 +534,7 @@ void RF24Mesh::DHCP(){ found = 0; for(uint8_t i=0; i < addrListTop; i++){ if( addrList[i].nodeID == from_id ){ - addrList[i].address = addrResponse.new_address; + addrList[i].address = newAddress; found = 1; #if defined (__linux) && !defined(__ARDUINO_X86__) if(millis()-lastFileSave > 300){ @@ -563,7 +547,7 @@ void RF24Mesh::DHCP(){ } if(!found){ addrList[addrListTop].nodeID = from_id; - addrList[addrListTop].address = addrResponse.new_address; + addrList[addrListTop].address = newAddress; #if defined (__linux) && !defined(__ARDUINO_X86__) if(millis()-lastFileSave > 300){ lastFileSave = millis(); @@ -577,7 +561,7 @@ void RF24Mesh::DHCP(){ #ifdef MESH_DEBUG_PRINTF - printf("Sent to 0%o phys: 0%o new: 0%o id: %d\n", header.to_node,addrResponse.requester,addrResponse.new_address,header.reserved); + printf("Sent to 0%o phys: 0%o new: 0%o id: %d\n", header.to_node,MESH_DEFAULT_ADDRESS,newAddress,header.reserved); #endif break; diff --git a/RF24Mesh.h b/RF24Mesh.h index a720612..071259b 100644 --- a/RF24Mesh.h +++ b/RF24Mesh.h @@ -87,7 +87,11 @@ class RF24Mesh * * @code mesh.begin(); @endcode * This may take a few moments to complete. - * The radio channel and data-rate can be specified optionally as well + * + * The following parameters are optional: + * @param channel The radio channel (1-127) default:97 + * @param data_rate The data rate (RF24_250KBPS,RF24_1MBPS,RF24_2MBPS) default:RF24_1MBPS + * @param timeout How long to attempt address renewal in milliseconds default:60000 */ bool begin(uint8_t channel = MESH_DEFAULT_CHANNEL, rf24_datarate_e data_rate = RF24_1MBPS, uint32_t timeout=MESH_RENEWAL_TIMEOUT ); @@ -98,20 +102,26 @@ class RF24Mesh uint8_t update(); /** - * Automatically construct a header and send a payload to the 'master' node. + * Automatically construct a header and send a payload * Very similar to the standard network.write() function, which can be used directly. - * @param data Send any type of data of any length (Very large payloads will be more error prone) + * + * @note Including the nodeID parameter will result in an automatic address lookup being performed. + * @note Message types 1-64 (decimal) will NOT be acknowledged by the network, types 65-127 will be. Use as appropriate to manage traffic: + * if expecting a response, no ack is needed. + * + * @param data Send any type of data of any length (Max length determined by RF24Network layer) * @param msg_type The user-defined (1-127) message header_type to send. Used to distinguish between different types of data being transmitted. * @param size The size of the data being sent - * @param nodeID Optional: The nodeID of the recipient if not sending to master + * @param nodeID **Optional**: The nodeID of the recipient if not sending to master * @return True if success, False if failed */ bool write(const void* data, uint8_t msg_type, size_t size, uint8_t nodeID=0); /** - * Set a unique nodeID for this node. This value, if changed, will be written to EEPROM on AVR so it will remain set, even after loss of power or code changes. - * Currently not saved on Due or RPi, so should be manually configured. - * This can generally be called before mesh.begin(), or set via serial connection or other methods if configuring a large number of nodes... + * Set a unique nodeID for this node. This value is stored in program memory, so is saved after loss of power. + * + * This should be called before mesh.begin(), or set via serial connection or other methods if configuring a large number of nodes... + * @note If using RF24Gateway and/or RF24Ethernet, nodeIDs 0 & 1 are used by the master node. * @param nodeID Can be any unique value ranging from 1 to 255. */ void setNodeID(uint8_t nodeID); @@ -132,14 +142,14 @@ class RF24Mesh /** * Convert an RF24Network address into a nodeId. - * When called on any node but the master node, this will result in a lookup request being sent to the master node - * + * @param address If no address is provided, returns the local nodeID, otherwise a lookup request is sent to the master node * @return Returns the unique identifier (1-255) or -1 if not found. */ - int getNodeID(uint16_t address=MESH_BLANK_ID); + int16_t getNodeID(uint16_t address=MESH_BLANK_ID); /** * Tests connectivity of this node to the mesh. + * @note If this function fails, the radio will be put into standby mode, and will not receive payloads until the address is renewed. * @return Return 1 if connected, 0 if mesh not responding after up to 1 second */ @@ -148,13 +158,19 @@ class RF24Mesh /** * Reconnect to the mesh and renew the current RF24Network address. Used to re-establish a connection to the mesh if physical location etc. has changed, or * a routing node goes down. - * @note Currently blocks until a connection is established and an address is received. + * @note Currently times out after 1 minute if address renewal fails. Network writes should not be attempted if address renewal fails. + * + * @note If all nodes are set to verify connectivity/reconnect at a specified period, leaving the master offline for this length of time should result + * in complete network/mesh reconvergence. + * @param timeout How long to attempt address renewal in milliseconds default:60000 + * @return Returns the newly assigned RF24Network address */ uint16_t renewAddress(uint32_t timeout=MESH_RENEWAL_TIMEOUT); /** * Releases the currently assigned address lease. Useful for nodes that will be sleeping etc. + * @note Nodes should ensure that addresses are releases successfully prior to renewal. * @return Returns 1 if successfully released, 0 if not */ bool releaseAddress(); @@ -167,14 +183,13 @@ class RF24Mesh /** * Convert a nodeID into an RF24Network address - * @note If printing or displaying the address, it needs to be converted to octal format. + * @note If printing or displaying the address, it needs to be converted to octal format: Serial.println(address,OCT); * - * When called on any node but the master node, this will result in a name lookup request being sent to the master node, and a response - * returned containing the address corresponding to the included nodeID. + * Results in a lookup request being sent to the master node. * @param nodeID - The unique identifier (1-255) of the node - * @return Returns the RF24Network address of the node or 0 if not found or lookup failed. + * @return Returns the RF24Network address of the node or -1 if not found or lookup failed. */ - uint16_t getAddress(uint8_t nodeID); + int16_t getAddress(uint8_t nodeID); /** * Write to a specific node by RF24Network address. @@ -188,9 +203,9 @@ class RF24Mesh void setChannel(uint8_t _channel); /** - * Set a static nodeID/RF24Network Address pair. - * Mainly for use with nodes not using RF24Mesh, but RF24Network only. - * Set a static address assignment, that will not be updated or re-assigned. + * Set a static nodeID/RF24Network Address pair on the master node. + * Mainly for use with nodes not using RF24Mesh at all, but RF24Network only. + * * @code * Set a static address for node 02, with nodeID 23, since it will just be a static routing node for example * running on an ATTiny chip. @@ -356,7 +371,7 @@ class RF24Mesh * @li Try it out! * @li Setup and Configuration * @li RF24Mesh Class Documentation - * @li RF24 Network -DEV- Class Documentation + * @li RF24 Network Class Documentation * @li Documentation and Downloads * @li Source Code * @@ -375,15 +390,15 @@ class RF24Mesh * * Software Requirements: * @li RF24 Core Radio Library - * @li RF24Network Development Library + * @li RF24Network Library * @li RF24Mesh - Dynamic Mesh Library * * @section Installation Installation - * 1. If not installed, download and install the RF24, RF24Network DEV, and RF24Mesh libraries per the above links
+ * 1. If not installed, use the Arduino Library Manager, or download and install the RF24, RF24Network, and RF24Mesh libraries per the above links
*
* 2. Configure and test the hardware using examples from RF24 and RF24Network prior to attempting to use RF24Mesh
* a: In Arduino IDE: File > Examples > RF24 > GettingStarted
- * b: RPi: Follow the Quick-Start instructions on GitHub
+ * b: RPi: Follow the RF24 instructions on GitHub
*
* 3. Once testing is complete:
* a: Arduino IDE: File > Examples > RF24Mesh > RF24Mesh_Example
@@ -426,7 +441,8 @@ class RF24Mesh * One of the recently introduced features is the ability to transmit payloads without the network returning a network-ack response. If solely using this method * of transmission, the node should also be configured to verify its connection via mesh.checkConnection(); periodically, to ensure connectivity. * - * Beyond requesting and releasing addresses, usage is as outlined in the RF24Network Development documentation at http://tmrh20.github.io + * Beyond requesting and releasing addresses, usage is outlined in the class documentation and further information regarding RF24Network is available at + * http://tmrh20.github.io/RF24Network * * * diff --git a/library.properties b/library.properties index d0e1670..0058fbe 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RF24Mesh -version=1.0.1 +version=1.0.2 author=TMRh20 maintainer=TMRh20 sentence=A library for NRF24L01(+) devices mesh.