/** * @file RF24Mesh.h * * Class declaration for RF24Mesh */ #ifndef __RF24MESH_H__ #define __RF24MESH_H__ #include #include /** * Network/Mesh Response Types * The network will determine whether to automatically acknowledge payloads based on their type * RF24Mesh uses pre-defined system types for interacting with RF24Network at the system level * */ // Network ACK types // None defined // No Network ACK types #define MESH_ADDR_LOOKUP 196 #define MESH_ADDR_RELEASE 197 #define MESH_ID_LOOKUP 198 #define MESH_BLANK_ID 65535 #if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny84__) #define RF24_TINY #endif #include "RF24Mesh_config.h" #if defined(__linux) && !defined(__ARDUINO_X86__) && !defined(USE_RF24_LIB_SRC) #include #include #define RF24_LINUX #else #include #if defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_NRF54L15) #include #endif #include #endif #include #include class RF24; #if defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52833) || defined(ARDUINO_NRF54L15) class nrf_to_nrf; #endif template class ESBNetwork; /** * @tparam network_t The `network` object's type. Defaults to `RF24Network` for legacy behavior. * This new abstraction is really meant for using the nRF52840 SoC as a drop-in replacement * for the nRF24L01 radio. For more detail, see the * [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf). * @tparam radio_t The `radio` object's type. Defaults to `RF24` for legacy behavior. * This new abstraction is really meant for using the nRF52840 SoC as a drop-in replacement * for the nRF24L01 radio. For more detail, see the * [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf). */ template, class radio_t = RF24> class ESBMesh { /** * @name RF24Mesh * * The mesh library and class documentation is currently in active development and usage may change. */ /**@{*/ public: /** * Construct the mesh. * * v2.0 supports a backward compatible constructor: * @code * RF24 radio(7, 8); * RF24Network network(radio); * RF24Mesh mesh(radio, network); // for nRF24L01 * * nrf_to_nrf radio1; * RF52Network network1(radio1); * RF52Mesh mesh1(network1, radio1); // for nRF52xxx family * @endcode * * @see v2.0 supports [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf) * for nrf52 chips' internal radio. * @param _radio The underlying radio driver instance * @param _network The underlying network instance */ ESBMesh(radio_t& _radio, network_t& _network); /** * Call this in setup() to configure the mesh and request an address.
* * @code mesh.begin(); @endcode * This may take a few moments to complete. * * The following parameters are optional: * @param channel The radio channel (0 - 125). Default is 97. * @param data_rate The data rate (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS). Default is RF24_1MBPS. * @param timeout How long to attempt address renewal in milliseconds. Default is 7500. */ bool begin(uint8_t channel = MESH_DEFAULT_CHANNEL, rf24_datarate_e data_rate = RF24_1MBPS, uint32_t timeout = MESH_RENEWAL_TIMEOUT); /** * Very similar to network.update(), it needs to be called regularly to keep the network * and the mesh going. */ uint8_t update(); /** * Automatically construct a header and send a payload. * Very similar to the standard network.write() function, which can be used directly. * * @note Including the @ref _nodeID "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 (maximum 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 @ref _nodeID "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 @ref _nodeID "nodeID" for this node. * * This needs to be called before ESBMesh::begin(). The parameter value passed can be fetched * via serial connection, EEPROM, etc when 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 (reserving 0 for the master node). */ void setNodeID(uint8_t nodeID); /** * @brief Reconnect to the mesh and renew the current RF24Network address. * * This is used to re-establish a connection to the mesh network if physical location of a node * or surrounding nodes has changed (or a routing node becomes unavailable). * * @note If all nodes are set to verify connectivity and reconnect at a specified period, then * restarting the master (and deleting dhcplist.txt on Linux) will result in complete * network/mesh re-convergence. * @param timeout How long to attempt address renewal in milliseconds. Default is 7500 * @return The newly assigned RF24Network address. If the connecting process fails, then * MESH_DEFAULT_ADDRESS is returned because all consciously unconnected nodes use that address. */ uint16_t renewAddress(uint32_t timeout = MESH_RENEWAL_TIMEOUT); #if !defined(MESH_NOMASTER) /** * This is only to be used on the master node because it manages allocation of network addresses * for any requesting (non-master) node's ID, similar to DHCP. * * @warning On master nodes, It is required to call this function immediately after calling * ESBMesh::update() to ensure address requests are handled appropriately. */ void DHCP(); #endif /**@}*/ /** * @name Advanced Operation * * For advanced configuration and usage of the mesh */ /**@{*/ /** * Convert an RF24Network address into a nodeId. * @param address If no address is provided, returns the local @ref _nodeID "nodeID", * otherwise a lookup request is sent to the master node * @return The unique identifier of the node in the range [1, 255] or -1 if node was not found. */ int16_t getNodeID(uint16_t address = MESH_BLANK_ID); /** * Tests connectivity of this node to the mesh. * @note If this function fails, address renewal should typically be done. * * The current behavior will only ping this node's parent to validate connection to mesh. * Previously, this function would validate connection by looking up this node's assigned address with * the master node's `RF24Mesh::addrList`. * The old behavior can be mandated by changing @ref RF24MESH_CONN_CHECK_TYPE in RF24Mesh_config.h, * although a large mesh network might suffer a performance cost using the old behavior. * * @return * - True if connected. * - False if not connected, mesh is not responding, or this node is the master node. */ bool checkConnection(); /** * Releases the currently assigned address lease. Useful for nodes that will be sleeping etc. * @note Nodes should ensure that addresses are released successfully prior to going offline. * @return True if successfully released, otherwise false. */ bool releaseAddress(); /** * The assigned RF24Network (Octal) address of this node * @return An unsigned 16-bit integer containing the RF24Network address in octal format. */ uint16_t mesh_address; /** * @brief Convert a @ref _nodeID "nodeID" into an RF24Network address * @note If printing or displaying the address, it needs to be converted to octal format: * @code{.ino} Serial.println(address, OCT); @endcode * * Results in a lookup request being sent to the master node. * @param nodeID The unique identifier of the node in the range [1, 255]. * @return The RF24Network address of the node, -2 if successful but not in list, -1 if failed. */ int16_t getAddress(uint8_t nodeID); /** @brief Write to a specific node by RF24Network address. */ bool write(uint16_t to_node, const void* data, uint8_t msg_type, size_t size); /** * Change the active radio channel after the mesh has been started. * @param _channel The value passed to `RF24::setChannel()` */ void setChannel(uint8_t _channel); /** * Allow child nodes to discover and attach to this node. * @param allow True to allow children, False to prevent children from attaching automatically. */ void setChild(bool allow); /** * RF24Mesh ID and Address lookups as well as address renewal can take some time. * Set a callback function to enable additional processing while the mesh is working * * @code * void myCallbackFunction(){ * someValue = someOtherValue; * } * mesh.setCallback(myCallbackFunction); * @endcode * * @param meshCallback The name of a function to call. This function should consume no required input parameters. */ void setCallback(void (*meshCallback)(void)); #define MESH_CALLBACK \ if (meshCallback) meshCallback(); /** * Set or change a @ref _nodeID "nodeID" : node address (key : value) pair manually. * This function is for use on the master node 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. * mesh.setAddress(23, 02); * @endcode * @code * // Change or set the nodeID for an existing address * uint16_t address = 012; * mesh.setAddress(3, address, true); * @endcode * * @param nodeID The @ref _nodeID "nodeID" to assign * @param address The octal RF24Network address to assign * @param searchBy Optional parameter. Default is search by @ref _nodeID "nodeID" and * set the address. True allows searching by address and setting @ref _nodeID "nodeID". */ void setAddress(uint8_t nodeID, uint16_t address, bool searchBy = false); #if !defined(MESH_NOMASTER) /** * Save the @ref addrList to a binary file named "dhcplist.txt". * @note This function is for use on the master node only and only on Linux or x86 platforms. */ void saveDHCP(); /** * Load the @ref addrList from a binary file named "dhcplist.txt". * @note This function is for use on the master node only and only on Linux or x86 platforms. */ void loadDHCP(); /** * @name Deprecated * * Methods provided for backwards compatibility with old/testing code. */ /**@{*/ /** @deprecated For backward compatibility with older code. Use the synonymous setAddress() instead. */ void setStaticAddress(uint8_t nodeID, uint16_t address); #endif // !defined(MESH_NOMASTER) /**@}*/ /** * The unique identifying number used to differentiate mesh nodes' from their assigned network * address. Ideally, this is set before calling begin() or renewAddress(). It is up to the * network administrator to make sure that this number is unique to each mesh/network node. * * This nodeID number is typically in the range [0, 255], but remember that `0` is reserved for * the master node. Other external systems may reserve other node ID numbers, for instance * RF24Gateway/RF24Ethernet reserves the node ID number `1` in addition to the master node ID * `0`. */ uint8_t _nodeID; #if !defined(MESH_NOMASTER) /** * @brief A struct for storing a @ref _nodeID "nodeID" and an address in a single element of * the ESBMesh::addrList array. * * @note This array only exists on the mesh network's master node. */ typedef struct { /** @brief The @ref _nodeID "nodeID" of an network node (child) */ uint8_t nodeID; /** @brief The logical address of an network node (child) */ uint16_t address; } addrListStruct; /** * @name Address list struct * @brief helping members for managing the list of assigned addresses * @see the addrListStruct struct reference */ /**@{*/ // Pointer used for dynamic memory allocation of address list /** * @brief A array of addrListStruct elements for assigned addresses. * @see addrListStruct class reference */ addrListStruct* addrList; /** @brief The number of entries in the addrListStruct of assigned addresses. */ uint8_t addrListTop; /** * Releases the specified address if leased to a mesh node's ID. * * This is specific to master nodes, so network administrators can * manage assigned addresses without notifying the nodes that * might be appropriating them. * * @param address The address to release from any mesh node. * @return True if successfully released, otherwise false. */ bool releaseAddress(uint16_t address); #endif /**@}*/ private: radio_t& radio; network_t& network; /** Function pointer for customized callback usage in long running algorithms. */ void (*meshCallback)(void); /** Actual requesting of the address once a contact node is discovered or supplied **/ bool requestAddress(uint8_t level); #if !defined(MESH_NOMASTER) /** Indicator that an address request is available. */ bool doDHCP; #endif /** Starts up the network layer with default address. */ void beginDefault(); /** A flag asserted in begin() after putting the radio in TX mode. */ bool meshStarted; /** Returns the number of octal digits in the specified address. */ uint8_t getLevel(uint16_t address); }; /** * A type definition of the template class `ESBMesh` to maintain backward compatibility. * * ```.cpp * RF24 radio(7, 8); * RF24Network network(radio); * * RF24Mesh mesh(radio, network); * // is equivalent to * ESBMesh, RF24> mesh(radio, network); * ``` */ typedef ESBMesh, RF24> RF24Mesh; #if defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52833) || defined(ARDUINO_NRF54L15) typedef ESBMesh, nrf_to_nrf> RF52Mesh; #endif /** * @example RF24Mesh_Example.ino * Arduino Example Sketch
* This example sketch shows how to manually configure a node via RF24Mesh, and send data to the * master node. * The nodes will refresh their network address as soon as a single write fails. This allows the * nodes to change position in relation to each other and the master node. */ /** * @example RF24Mesh_Example_Master.ino * Arduino Example Sketch
* @note This sketch only functions on -Arduino Due- * * This example sketch shows how to manually configure a node via RF24Mesh as a master node, which * will receive all data from sensor nodes. * * The nodes can change physical or logical position in the network, and reconnect through different * routing nodes as required. The master node manages the address assignments for the individual nodes * in a manner similar to DHCP. * */ /** * @example RF24Mesh_Example_Node2Node.ino * Example of node to node communication using RF24Mesh */ /** * @example RF24Mesh_Example_Node2NodeExtra.ino * Extended Example of node to node communication using RF24Mesh */ /** * @example RF24Mesh_SerialConfig.ino * * This example sketch shows how the same sketch can be written to a large number of devices, which are * configured later via Serial input. * */ /** * @example RF24Mesh_Example.cpp * * Raspberry Pi Example Sketch
* This example sketch shows how to manually configure a node via RF24Mesh, and send data to the * master node. * The nodes will refresh their network address as soon as a single write fails. This allows the * nodes to change position in relation to each other and the master node. */ /** * @example RF24Mesh_Example_Master.cpp * * Raspberry Pi Example Sketch
* * This example sketch shows how to manually configure a node via RF24Mesh as a master node, which * will receive all data from sensor nodes. * * The nodes can change physical or logical position in the network, and reconnect through different * routing nodes as required. The master node manages the address assignments for the individual nodes * in a manner similar to DHCP. * */ /** * @example RF24Mesh_Ncurses_Master.cpp * A very limited ncurses interface used for initial monitoring/testing of RF24Mesh * @image html "images/RF24Mesh_Ncurses.JPG" */ #endif // define __RF24MESH_H__