00001 // RF22Mesh.h 00002 // 00003 // Author: Mike McCauley (mikem@open.com.au) 00004 // Copyright (C) 2011 Mike McCauley 00005 // $Id: RF22Mesh.h,v 1.3 2011/02/15 04:51:59 mikem Exp $ 00006 00007 #ifndef RF22Mesh_h 00008 #define RF22Mesh_h 00009 00010 #include <RF22Router.h> 00011 00012 // Types of RF22Mesh message, used to set msgType in the RF22MeshHeader 00013 #define RF22_MESH_MESSAGE_TYPE_APPLICATION 0 00014 #define RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST 1 00015 #define RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE 2 00016 #define RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE 3 00017 00018 ///////////////////////////////////////////////////////////////////// 00019 /// \class RF22Mesh RF22Mesh.h <RF22Mesh.h> 00020 /// \brief RF22 subclass for sending addressed, optionally acknowledged datagrams 00021 /// multi-hop routed across a network, with automatic route discovery 00022 /// 00023 /// Extends RF22Router to add automatic route discovery within a mesh of adjacent nodes, 00024 /// and route signalling. 00025 /// 00026 /// Unlike RF22Router, RF22Mesh can be used in networks where the network topology is fluid, or unknown, 00027 /// or if nodes can mode around or go in or out of service. When a node wants to send a 00028 /// message to another node, it will automcatically discover a route to the destaintion node and use it. 00029 /// If the route becomes unavailable, a new route will be discovered. 00030 /// 00031 /// \par Route Discovery 00032 /// 00033 /// When a RF22Mesh mesh node is initialised, it doe not know any routes to any other nodes 00034 /// (see RF22Router for details on route and the routing table). 00035 /// When you attempt to send a message with sendtoWait, will first check to see if there is a route to the 00036 /// destinastion node in the routing tabl;e. If not, it wil initialite 'Route Discovery'. 00037 /// When a node needs to discover a route to another node, it broadcasts MeshRouteDiscoveryMessage 00038 /// with a message type of RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST. 00039 /// Any node that receives such a request checks to see if it is a request for a route to itself 00040 /// (in which case it makes a unicast reply to the originating node with a 00041 /// MeshRouteDiscoveryMessage 00042 /// with a message type of RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE) 00043 /// otherwise it rebroadcasts the request, after adding itself to the list of nodes visited so 00044 /// far by the request. 00045 /// 00046 /// If a node receives a RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST that already has itself 00047 /// listed in the visited nodes, it knows it has already seen and rebroadcast this request, 00048 /// and threfore ignores it. This prevents broadcast storms. 00049 /// When a node receives a RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST it can use the list of 00050 /// nodes aready visited to deduce routes back towards the originating (requesting node). 00051 /// This also means that when the destination node of the request is reached, it (and all 00052 /// the previous nodes the request visited) will have a route back to the originating node. 00053 /// This means the unicast RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE 00054 /// reply will be routed successfully back to the original route requester. 00055 /// 00056 /// The RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE sent back by the destination node contains 00057 /// the full list of nodes that were visited on the way to the destination. 00058 /// Therefore, intermediate nodes that route the reply back towards the originating node can use the 00059 /// node list in the reply to deduce routes to all the nodes between it and the destination node. 00060 /// 00061 /// Therefore, RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST and 00062 /// RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE together ensure the original requester and all 00063 /// the intermediate nodes know how to route to the source and destination nodes and every node along the path. 00064 /// 00065 /// Note that there is a race condition here that can effect routing on multipath routes. For example, 00066 /// if the route to the destination can traverse several paths, last reply from the destination 00067 /// will be the one used. 00068 /// 00069 /// \par Route Failure 00070 /// 00071 /// RF22Router (and therefore RF22Mesh) use reliable hop-to-hop delivery of messages using 00072 /// hop-to-hop acknowledgements, but not end-to-end acknowledgements. When sendtoWait() returns, 00073 /// you know that the message has been delivered to the next hop, but not if it is (or even if it can be) 00074 /// delivered to the destination node. If during the course of hop-to-hop routing of a message, 00075 /// one of the intermediate RF22Mesh nodes finds it cannot deliver to the next hop 00076 /// (say due to a lost route or no acknwledgement from the next hop), it replies to the 00077 /// originator with a unicast MeshRouteFailureMessage RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE message. 00078 /// Intermediate nodes (on the way beack to the originator) 00079 /// and the originating node use this message to delete the route to the destination 00080 /// node of the original message. This means that if a route to a destination becomes unusable 00081 /// (either because an intermediate node is off the air, or has moved out of range) a new route 00082 /// will be established the next time a message is to be sent. 00083 /// 00084 /// \par Message Format 00085 /// 00086 /// RF22Mesh uses a number of message formats layered on top of RF22Router: 00087 /// - MeshApplicationMessage (message type RF22_MESH_MESSAGE_TYPE_APPLICATION). 00088 /// Carries an application layer message for the caller of RF22Mesh 00089 /// - MeshRouteDiscoveryMessage (message types RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST 00090 /// and RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE). Carries Route Discovery messages 00091 /// (broadcast) and replies (unicast). 00092 /// - MeshRouteFailureMessage (message type RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE) Informs nodes of 00093 /// route failures. 00094 /// 00095 /// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers 00096 /// (see http://www.hoperf.com) 00097 class RF22Mesh : public RF22Router 00098 { 00099 public: 00100 00101 /// The maximum length permitted for the application payload data in a RF22Mesh message 00102 #define RF22_MESH_MAX_MESSAGE_LEN (RF22_ROUTER_MAX_MESSAGE_LEN - sizeof(RF22Mesh::MeshMessageHeader)) 00103 00104 /// Structure of the basic RF22Mesh header. 00105 typedef struct 00106 { 00107 uint8_t msgType; ///< Type of RF22Mesh message, one of RF22_MESH_MESSAGE_TYPE_* 00108 } MeshMessageHeader; 00109 00110 /// Signals an application layer message for the caller of RF22Mesh 00111 typedef struct 00112 { 00113 MeshMessageHeader header; ///< msgType = RF22_MESH_MESSAGE_TYPE_APPLICATION 00114 uint8_t data[RF22_MESH_MAX_MESSAGE_LEN]; ///< Applicaiotn layer payload data 00115 } MeshApplicationMessage; 00116 00117 /// Signals a route discovery request or reply 00118 /// At present only supports physical dest addresses of length 1 octet 00119 typedef struct 00120 { 00121 MeshMessageHeader header; ///< msgType = RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_* 00122 uint8_t destlen; ///< Reserved. Must be 1. 00123 uint8_t dest; ///< The address of the destination node whose route is being sought 00124 uint8_t route[RF22_MESH_MAX_MESSAGE_LEN - 1]; ///< List of node addresses visited so far. Length is implcit 00125 } MeshRouteDiscoveryMessage; 00126 00127 /// Signals a route failure 00128 typedef struct 00129 { 00130 MeshMessageHeader header; ///< msgType = RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE 00131 uint8_t dest; ///< The address of the destination towards which the route failed 00132 } MeshRouteFailureMessage; 00133 00134 /// Constructor. 00135 /// \param[in] thisAddress The address to assign to this node. Defaults to 0 00136 /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the RF22 before 00137 /// accessing it 00138 /// \param[in] interrupt The interrupt number to use. Default is interrupt 0 (Arduino input pin 2) 00139 RF22Mesh(uint8_t thisAddress = 0, uint8_t slaveSelectPin = 10, uint8_t interrupt = 0); 00140 00141 /// Sends a message to the destination node. Initialises the RF22Router message header 00142 /// (the SOURCE address is set to the address of this node, HOPS to 0) and calls 00143 /// route() which looks up in the routing table the next hop to deliver to. 00144 /// If no route is known, initiates route discovery and waits for a reply. 00145 /// Then sends the message to the next hop 00146 /// Then waits for an acknowledgement from the next hop 00147 /// (but not from the destination node (if that is different). 00148 /// \param [in] buf The application message data 00149 /// \param [in] len Number of octets in the application message data. 0 is permitted 00150 /// \param [in] dest The destination node address 00151 /// \return The result code: 00152 /// - RF22_ROUTER_ERROR_NONE Message was routed and deliverd to the next hop 00153 /// (not necessarily to the final dest address) 00154 /// - RF22_ROUTER_ERROR_NO_ROUTE There was no route for dest in the local routing table 00155 /// - RF22_ROUTER_ERROR_UNABLE_TO_DELIVER Noyt able to deliver to the next hop 00156 /// (usually because it dod not acknowledge due to being off the air or out of range 00157 uint8_t sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest); 00158 00159 /// Starts the receiver if it is not running already. 00160 /// If there is a valid application layer message available for this node (or RF22_BROADCAST_ADDRESS), 00161 /// send an acknowledgement to the last hop 00162 /// address (blocking until this is complete), then copy the application message payload data 00163 /// to buf and return true 00164 /// else return false. 00165 /// If a message is copied, *len is set to the length.. 00166 /// If from is not NULL, the originator SOURCE address is placed in *source. 00167 /// If to is not NULL, the DEST address is placed in *dest. This might be this nodes address or 00168 /// RF22_BROADCAST_ADDRESS. 00169 /// This is the preferred function for getting messages addressed to this node. 00170 /// If the message is not a broadcast, acknowledge to the sender before returning. 00171 /// \param[in] buf Location to copy the received message 00172 /// \param[in,out] len Available space in buf. Set to the actual number of octets copied. 00173 /// \param[in] source If present and not NULL, the referenced uint8_t will be set to the SOURCE address 00174 /// \param[in] dest If present and not NULL, the referenced uint8_t will be set to the DEST address 00175 /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID 00176 /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS 00177 /// (not just those addressed to this node). 00178 /// \return true if a valid message was recvived for this node and copied to buf 00179 boolean recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source = NULL, uint8_t* dest = NULL, uint8_t* id = NULL, uint8_t* flags = NULL); 00180 00181 /// Starts the receiver if it is not running already. 00182 /// Similar to recvfromAck(), this will block until either a valid application layer 00183 /// message available for this node 00184 /// or the timeout expires. 00185 /// \param[in] buf Location to copy the received message 00186 /// \param[in,out] len Available space in buf. Set to the actual number of octets copied. 00187 /// \param[in] timeout Maximum time to wait in milliseconds 00188 /// \param[in] source If present and not NULL, the referenced uint8_t will be set to the SOURCE address 00189 /// \param[in] dest If present and not NULL, the referenced uint8_t will be set to the DEST address 00190 /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID 00191 /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS 00192 /// (not just those addressed to this node). 00193 /// \return true if a valid message was copied to buf 00194 boolean recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* source = NULL, uint8_t* dest = NULL, uint8_t* id = NULL, uint8_t* flags = NULL); 00195 00196 protected: 00197 00198 /// Internal function that inspects messages being received and adjusts the routing table if necessary. 00199 /// Called by recvfromAck() immediately after it gets the message from RF22ReliableDatagram 00200 /// \param [in] message Pointer to the RF22Router message that was received. 00201 /// \param [in] messageLen Length of message in octets 00202 virtual void peekAtMessage(RoutedMessage* message, uint8_t messageLen); 00203 00204 /// Internal function that inspects messages being received and adjusts the routing table if necessary. 00205 /// This is virtual, which lets subclasses override or intercept the route() function. 00206 /// Called by sendtoWait after the message header has been filled in. 00207 /// \param [in] message Pointer to the RF22Router message to be sent. 00208 /// \param [in] messageLen Length of message in octets 00209 virtual uint8_t route(RoutedMessage* message, uint8_t messageLen); 00210 00211 /// Try to resolve a route for the given address. Blocks while discovering the route 00212 /// which may take up to 4000 msec. 00213 /// Virtual so subclasses can override. 00214 /// \param [in] address The physical addres to resolve 00215 /// \return true if the address was resolved and added to the local routing table 00216 virtual boolean doArp(uint8_t address); 00217 00218 /// Tests if the given address of length addresslen is indentical to the 00219 /// physical addres of this node. 00220 /// RF22Mesh always ikmplements p[hysical addresses as the 1 octet address of the node 00221 /// given by _thisAddress 00222 /// Called by recvfromAck() to test whether a RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST 00223 /// is for this node. 00224 /// Subclasses may want to override to implemnt mode complicated or longer physical addresses 00225 /// \param [in] address Address of the pyysical addres being tested 00226 /// \param [in] addresslen Lengthof the address in bytes 00227 /// \return true if the physical address of this node is identical to address 00228 virtual boolean isPhysicalAddress(uint8_t* address, uint8_t addresslen); 00229 00230 private: 00231 /// Temporary mesage buffer 00232 static uint8_t _tmpMessage[RF22_ROUTER_MAX_MESSAGE_LEN]; 00233 00234 }; 00235 00236 #endif 00237