V148

Fork of RadioHead-148 by David Rimer

Committer:
ilkaykozak
Date:
Wed Oct 25 05:14:09 2017 +0000
Revision:
1:b7641da2b203
Parent:
0:ab4e012489ef
V148

Who changed what in which revision?

UserRevisionLine numberNew contents of line
davidr99 0:ab4e012489ef 1 // RHRouter.cpp
davidr99 0:ab4e012489ef 2 //
davidr99 0:ab4e012489ef 3 // Define addressed datagram
davidr99 0:ab4e012489ef 4 //
davidr99 0:ab4e012489ef 5 // Part of the Arduino RH library for operating with HopeRF RH compatible transceivers
davidr99 0:ab4e012489ef 6 // (see http://www.hoperf.com)
davidr99 0:ab4e012489ef 7 // RHDatagram will be received only by the addressed node or all nodes within range if the
davidr99 0:ab4e012489ef 8 // to address is RH_BROADCAST_ADDRESS
davidr99 0:ab4e012489ef 9 //
davidr99 0:ab4e012489ef 10 // Author: Mike McCauley (mikem@airspayce.com)
davidr99 0:ab4e012489ef 11 // Copyright (C) 2011 Mike McCauley
davidr99 0:ab4e012489ef 12 // $Id: RHRouter.cpp,v 1.7 2015/08/13 02:45:47 mikem Exp $
davidr99 0:ab4e012489ef 13
davidr99 0:ab4e012489ef 14 #include <RHRouter.h>
davidr99 0:ab4e012489ef 15
davidr99 0:ab4e012489ef 16 RHRouter::RoutedMessage RHRouter::_tmpMessage;
davidr99 0:ab4e012489ef 17
davidr99 0:ab4e012489ef 18 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 19 // Constructors
davidr99 0:ab4e012489ef 20 RHRouter::RHRouter(RHGenericDriver& driver, uint8_t thisAddress)
davidr99 0:ab4e012489ef 21 : RHReliableDatagram(driver, thisAddress)
davidr99 0:ab4e012489ef 22 {
davidr99 0:ab4e012489ef 23 _max_hops = RH_DEFAULT_MAX_HOPS;
davidr99 0:ab4e012489ef 24 clearRoutingTable();
davidr99 0:ab4e012489ef 25 }
davidr99 0:ab4e012489ef 26
davidr99 0:ab4e012489ef 27 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 28 // Public methods
davidr99 0:ab4e012489ef 29 bool RHRouter::init()
davidr99 0:ab4e012489ef 30 {
davidr99 0:ab4e012489ef 31 bool ret = RHReliableDatagram::init();
davidr99 0:ab4e012489ef 32 if (ret)
davidr99 0:ab4e012489ef 33 _max_hops = RH_DEFAULT_MAX_HOPS;
davidr99 0:ab4e012489ef 34 return ret;
davidr99 0:ab4e012489ef 35 }
davidr99 0:ab4e012489ef 36
davidr99 0:ab4e012489ef 37 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 38 void RHRouter::setMaxHops(uint8_t max_hops)
davidr99 0:ab4e012489ef 39 {
davidr99 0:ab4e012489ef 40 _max_hops = max_hops;
davidr99 0:ab4e012489ef 41 }
davidr99 0:ab4e012489ef 42
davidr99 0:ab4e012489ef 43 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 44 void RHRouter::addRouteTo(uint8_t dest, uint8_t next_hop, uint8_t state)
davidr99 0:ab4e012489ef 45 {
davidr99 0:ab4e012489ef 46 uint8_t i;
davidr99 0:ab4e012489ef 47
davidr99 0:ab4e012489ef 48 // First look for an existing entry we can update
davidr99 0:ab4e012489ef 49 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++)
davidr99 0:ab4e012489ef 50 {
davidr99 0:ab4e012489ef 51 if (_routes[i].dest == dest)
davidr99 0:ab4e012489ef 52 {
davidr99 0:ab4e012489ef 53 _routes[i].dest = dest;
davidr99 0:ab4e012489ef 54 _routes[i].next_hop = next_hop;
davidr99 0:ab4e012489ef 55 _routes[i].state = state;
davidr99 0:ab4e012489ef 56 return;
davidr99 0:ab4e012489ef 57 }
davidr99 0:ab4e012489ef 58 }
davidr99 0:ab4e012489ef 59
davidr99 0:ab4e012489ef 60 // Look for an invalid entry we can use
davidr99 0:ab4e012489ef 61 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++)
davidr99 0:ab4e012489ef 62 {
davidr99 0:ab4e012489ef 63 if (_routes[i].state == Invalid)
davidr99 0:ab4e012489ef 64 {
davidr99 0:ab4e012489ef 65 _routes[i].dest = dest;
davidr99 0:ab4e012489ef 66 _routes[i].next_hop = next_hop;
davidr99 0:ab4e012489ef 67 _routes[i].state = state;
davidr99 0:ab4e012489ef 68 return;
davidr99 0:ab4e012489ef 69 }
davidr99 0:ab4e012489ef 70 }
davidr99 0:ab4e012489ef 71
davidr99 0:ab4e012489ef 72 // Need to make room for a new one
davidr99 0:ab4e012489ef 73 retireOldestRoute();
davidr99 0:ab4e012489ef 74 // Should be an invalid slot now
davidr99 0:ab4e012489ef 75 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++)
davidr99 0:ab4e012489ef 76 {
davidr99 0:ab4e012489ef 77 if (_routes[i].state == Invalid)
davidr99 0:ab4e012489ef 78 {
davidr99 0:ab4e012489ef 79 _routes[i].dest = dest;
davidr99 0:ab4e012489ef 80 _routes[i].next_hop = next_hop;
davidr99 0:ab4e012489ef 81 _routes[i].state = state;
davidr99 0:ab4e012489ef 82 }
davidr99 0:ab4e012489ef 83 }
davidr99 0:ab4e012489ef 84 }
davidr99 0:ab4e012489ef 85
davidr99 0:ab4e012489ef 86 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 87 RHRouter::RoutingTableEntry* RHRouter::getRouteTo(uint8_t dest)
davidr99 0:ab4e012489ef 88 {
davidr99 0:ab4e012489ef 89 uint8_t i;
davidr99 0:ab4e012489ef 90 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++)
davidr99 0:ab4e012489ef 91 if (_routes[i].dest == dest && _routes[i].state != Invalid)
davidr99 0:ab4e012489ef 92 return &_routes[i];
davidr99 0:ab4e012489ef 93 return NULL;
davidr99 0:ab4e012489ef 94 }
davidr99 0:ab4e012489ef 95
davidr99 0:ab4e012489ef 96 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 97 void RHRouter::deleteRoute(uint8_t index)
davidr99 0:ab4e012489ef 98 {
davidr99 0:ab4e012489ef 99 // Delete a route by copying following routes on top of it
davidr99 0:ab4e012489ef 100 memcpy(&_routes[index], &_routes[index+1],
davidr99 0:ab4e012489ef 101 sizeof(RoutingTableEntry) * (RH_ROUTING_TABLE_SIZE - index - 1));
davidr99 0:ab4e012489ef 102 _routes[RH_ROUTING_TABLE_SIZE - 1].state = Invalid;
davidr99 0:ab4e012489ef 103 }
davidr99 0:ab4e012489ef 104
davidr99 0:ab4e012489ef 105 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 106 void RHRouter::printRoutingTable()
davidr99 0:ab4e012489ef 107 {
davidr99 0:ab4e012489ef 108 #ifdef RH_HAVE_SERIAL
davidr99 0:ab4e012489ef 109 uint8_t i;
davidr99 0:ab4e012489ef 110 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++)
davidr99 0:ab4e012489ef 111 {
davidr99 0:ab4e012489ef 112 Serial.print(i, DEC);
davidr99 0:ab4e012489ef 113 Serial.print(" Dest: ");
davidr99 0:ab4e012489ef 114 Serial.print(_routes[i].dest, DEC);
davidr99 0:ab4e012489ef 115 Serial.print(" Next Hop: ");
davidr99 0:ab4e012489ef 116 Serial.print(_routes[i].next_hop, DEC);
davidr99 0:ab4e012489ef 117 Serial.print(" State: ");
davidr99 0:ab4e012489ef 118 Serial.println(_routes[i].state, DEC);
davidr99 0:ab4e012489ef 119 }
davidr99 0:ab4e012489ef 120 #endif
davidr99 0:ab4e012489ef 121 }
davidr99 0:ab4e012489ef 122
davidr99 0:ab4e012489ef 123 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 124 bool RHRouter::deleteRouteTo(uint8_t dest)
davidr99 0:ab4e012489ef 125 {
davidr99 0:ab4e012489ef 126 uint8_t i;
davidr99 0:ab4e012489ef 127 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++)
davidr99 0:ab4e012489ef 128 {
davidr99 0:ab4e012489ef 129 if (_routes[i].dest == dest)
davidr99 0:ab4e012489ef 130 {
davidr99 0:ab4e012489ef 131 deleteRoute(i);
davidr99 0:ab4e012489ef 132 return true;
davidr99 0:ab4e012489ef 133 }
davidr99 0:ab4e012489ef 134 }
davidr99 0:ab4e012489ef 135 return false;
davidr99 0:ab4e012489ef 136 }
davidr99 0:ab4e012489ef 137
davidr99 0:ab4e012489ef 138 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 139 void RHRouter::retireOldestRoute()
davidr99 0:ab4e012489ef 140 {
davidr99 0:ab4e012489ef 141 // We just obliterate the first in the table and clear the last
davidr99 0:ab4e012489ef 142 deleteRoute(0);
davidr99 0:ab4e012489ef 143 }
davidr99 0:ab4e012489ef 144
davidr99 0:ab4e012489ef 145 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 146 void RHRouter::clearRoutingTable()
davidr99 0:ab4e012489ef 147 {
davidr99 0:ab4e012489ef 148 uint8_t i;
davidr99 0:ab4e012489ef 149 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++)
davidr99 0:ab4e012489ef 150 _routes[i].state = Invalid;
davidr99 0:ab4e012489ef 151 }
davidr99 0:ab4e012489ef 152
davidr99 0:ab4e012489ef 153
davidr99 0:ab4e012489ef 154 uint8_t RHRouter::sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest, uint8_t flags)
davidr99 0:ab4e012489ef 155 {
davidr99 0:ab4e012489ef 156 return sendtoFromSourceWait(buf, len, dest, _thisAddress, flags);
davidr99 0:ab4e012489ef 157 }
davidr99 0:ab4e012489ef 158
davidr99 0:ab4e012489ef 159 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 160 // Waits for delivery to the next hop (but not for delivery to the final destination)
davidr99 0:ab4e012489ef 161 uint8_t RHRouter::sendtoFromSourceWait(uint8_t* buf, uint8_t len, uint8_t dest, uint8_t source, uint8_t flags)
davidr99 0:ab4e012489ef 162 {
davidr99 0:ab4e012489ef 163 if (((uint16_t)len + sizeof(RoutedMessageHeader)) > _driver.maxMessageLength())
davidr99 0:ab4e012489ef 164 return RH_ROUTER_ERROR_INVALID_LENGTH;
davidr99 0:ab4e012489ef 165
davidr99 0:ab4e012489ef 166 // Construct a RH RouterMessage message
davidr99 0:ab4e012489ef 167 _tmpMessage.header.source = source;
davidr99 0:ab4e012489ef 168 _tmpMessage.header.dest = dest;
davidr99 0:ab4e012489ef 169 _tmpMessage.header.hops = 0;
davidr99 0:ab4e012489ef 170 _tmpMessage.header.id = _lastE2ESequenceNumber++;
davidr99 0:ab4e012489ef 171 _tmpMessage.header.flags = flags;
davidr99 0:ab4e012489ef 172 memcpy(_tmpMessage.data, buf, len);
davidr99 0:ab4e012489ef 173
davidr99 0:ab4e012489ef 174 return route(&_tmpMessage, sizeof(RoutedMessageHeader)+len);
davidr99 0:ab4e012489ef 175 }
davidr99 0:ab4e012489ef 176
davidr99 0:ab4e012489ef 177 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 178 uint8_t RHRouter::route(RoutedMessage* message, uint8_t messageLen)
davidr99 0:ab4e012489ef 179 {
davidr99 0:ab4e012489ef 180 // Reliably deliver it if possible. See if we have a route:
davidr99 0:ab4e012489ef 181 uint8_t next_hop = RH_BROADCAST_ADDRESS;
davidr99 0:ab4e012489ef 182 if (message->header.dest != RH_BROADCAST_ADDRESS)
davidr99 0:ab4e012489ef 183 {
davidr99 0:ab4e012489ef 184 RoutingTableEntry* route = getRouteTo(message->header.dest);
davidr99 0:ab4e012489ef 185 if (!route)
davidr99 0:ab4e012489ef 186 return RH_ROUTER_ERROR_NO_ROUTE;
davidr99 0:ab4e012489ef 187 next_hop = route->next_hop;
davidr99 0:ab4e012489ef 188 }
davidr99 0:ab4e012489ef 189
davidr99 0:ab4e012489ef 190 if (!RHReliableDatagram::sendtoWait((uint8_t*)message, messageLen, next_hop))
davidr99 0:ab4e012489ef 191 return RH_ROUTER_ERROR_UNABLE_TO_DELIVER;
davidr99 0:ab4e012489ef 192
davidr99 0:ab4e012489ef 193 return RH_ROUTER_ERROR_NONE;
davidr99 0:ab4e012489ef 194 }
davidr99 0:ab4e012489ef 195
davidr99 0:ab4e012489ef 196 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 197 // Subclasses may want to override this to peek at messages going past
davidr99 0:ab4e012489ef 198 void RHRouter::peekAtMessage(RoutedMessage* message, uint8_t messageLen)
davidr99 0:ab4e012489ef 199 {
davidr99 0:ab4e012489ef 200 // Default does nothing
davidr99 0:ab4e012489ef 201 }
davidr99 0:ab4e012489ef 202
davidr99 0:ab4e012489ef 203 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 204 bool RHRouter::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags)
davidr99 0:ab4e012489ef 205 {
davidr99 0:ab4e012489ef 206 uint8_t tmpMessageLen = sizeof(_tmpMessage);
davidr99 0:ab4e012489ef 207 uint8_t _from;
davidr99 0:ab4e012489ef 208 uint8_t _to;
davidr99 0:ab4e012489ef 209 uint8_t _id;
davidr99 0:ab4e012489ef 210 uint8_t _flags;
davidr99 0:ab4e012489ef 211 if (RHReliableDatagram::recvfromAck((uint8_t*)&_tmpMessage, &tmpMessageLen, &_from, &_to, &_id, &_flags))
davidr99 0:ab4e012489ef 212 {
davidr99 0:ab4e012489ef 213 // Here we simulate networks with limited visibility between nodes
davidr99 0:ab4e012489ef 214 // so we can test routing
davidr99 0:ab4e012489ef 215 #ifdef RH_TEST_NETWORK
davidr99 0:ab4e012489ef 216 if (
davidr99 0:ab4e012489ef 217 #if RH_TEST_NETWORK==1
davidr99 0:ab4e012489ef 218 // This network looks like 1-2-3-4
davidr99 0:ab4e012489ef 219 (_thisAddress == 1 && _from == 2)
davidr99 0:ab4e012489ef 220 || (_thisAddress == 2 && (_from == 1 || _from == 3))
davidr99 0:ab4e012489ef 221 || (_thisAddress == 3 && (_from == 2 || _from == 4))
davidr99 0:ab4e012489ef 222 || (_thisAddress == 4 && _from == 3)
davidr99 0:ab4e012489ef 223
davidr99 0:ab4e012489ef 224 #elif RH_TEST_NETWORK==2
davidr99 0:ab4e012489ef 225 // This network looks like 1-2-4
davidr99 0:ab4e012489ef 226 // | | |
davidr99 0:ab4e012489ef 227 // --3--
davidr99 0:ab4e012489ef 228 (_thisAddress == 1 && (_from == 2 || _from == 3))
davidr99 0:ab4e012489ef 229 || _thisAddress == 2
davidr99 0:ab4e012489ef 230 || _thisAddress == 3
davidr99 0:ab4e012489ef 231 || (_thisAddress == 4 && (_from == 2 || _from == 3))
davidr99 0:ab4e012489ef 232
davidr99 0:ab4e012489ef 233 #elif RH_TEST_NETWORK==3
davidr99 0:ab4e012489ef 234 // This network looks like 1-2-4
davidr99 0:ab4e012489ef 235 // | |
davidr99 0:ab4e012489ef 236 // --3--
davidr99 0:ab4e012489ef 237 (_thisAddress == 1 && (_from == 2 || _from == 3))
davidr99 0:ab4e012489ef 238 || (_thisAddress == 2 && (_from == 1 || _from == 4))
davidr99 0:ab4e012489ef 239 || (_thisAddress == 3 && (_from == 1 || _from == 4))
davidr99 0:ab4e012489ef 240 || (_thisAddress == 4 && (_from == 2 || _from == 3))
davidr99 0:ab4e012489ef 241
davidr99 0:ab4e012489ef 242 #elif RH_TEST_NETWORK==4
davidr99 0:ab4e012489ef 243 // This network looks like 1-2-3
davidr99 0:ab4e012489ef 244 // |
davidr99 0:ab4e012489ef 245 // 4
davidr99 0:ab4e012489ef 246 (_thisAddress == 1 && _from == 2)
davidr99 0:ab4e012489ef 247 || _thisAddress == 2
davidr99 0:ab4e012489ef 248 || (_thisAddress == 3 && _from == 2)
davidr99 0:ab4e012489ef 249 || (_thisAddress == 4 && _from == 2)
davidr99 0:ab4e012489ef 250
davidr99 0:ab4e012489ef 251 #endif
davidr99 0:ab4e012489ef 252 )
davidr99 0:ab4e012489ef 253 {
davidr99 0:ab4e012489ef 254 // OK
davidr99 0:ab4e012489ef 255 }
davidr99 0:ab4e012489ef 256 else
davidr99 0:ab4e012489ef 257 {
davidr99 0:ab4e012489ef 258 return false; // Pretend we got nothing
davidr99 0:ab4e012489ef 259 }
davidr99 0:ab4e012489ef 260 #endif
davidr99 0:ab4e012489ef 261
davidr99 0:ab4e012489ef 262 peekAtMessage(&_tmpMessage, tmpMessageLen);
davidr99 0:ab4e012489ef 263 // See if its for us or has to be routed
davidr99 0:ab4e012489ef 264 if (_tmpMessage.header.dest == _thisAddress || _tmpMessage.header.dest == RH_BROADCAST_ADDRESS)
davidr99 0:ab4e012489ef 265 {
davidr99 0:ab4e012489ef 266 // Deliver it here
davidr99 0:ab4e012489ef 267 if (source) *source = _tmpMessage.header.source;
davidr99 0:ab4e012489ef 268 if (dest) *dest = _tmpMessage.header.dest;
davidr99 0:ab4e012489ef 269 if (id) *id = _tmpMessage.header.id;
davidr99 0:ab4e012489ef 270 if (flags) *flags = _tmpMessage.header.flags;
davidr99 0:ab4e012489ef 271 uint8_t msgLen = tmpMessageLen - sizeof(RoutedMessageHeader);
davidr99 0:ab4e012489ef 272 if (*len > msgLen)
davidr99 0:ab4e012489ef 273 *len = msgLen;
davidr99 0:ab4e012489ef 274 memcpy(buf, _tmpMessage.data, *len);
davidr99 0:ab4e012489ef 275 return true; // Its for you!
davidr99 0:ab4e012489ef 276 }
davidr99 0:ab4e012489ef 277 else if ( _tmpMessage.header.dest != RH_BROADCAST_ADDRESS
davidr99 0:ab4e012489ef 278 && _tmpMessage.header.hops++ < _max_hops)
davidr99 0:ab4e012489ef 279 {
davidr99 0:ab4e012489ef 280 // Maybe it has to be routed to the next hop
davidr99 0:ab4e012489ef 281 // REVISIT: if it fails due to no route or unable to deliver to the next hop,
davidr99 0:ab4e012489ef 282 // tell the originator. BUT HOW?
davidr99 0:ab4e012489ef 283 route(&_tmpMessage, tmpMessageLen);
davidr99 0:ab4e012489ef 284 }
davidr99 0:ab4e012489ef 285 // Discard it and maybe wait for another
davidr99 0:ab4e012489ef 286 }
davidr99 0:ab4e012489ef 287 return false;
davidr99 0:ab4e012489ef 288 }
davidr99 0:ab4e012489ef 289
davidr99 0:ab4e012489ef 290 ////////////////////////////////////////////////////////////////////
davidr99 0:ab4e012489ef 291 bool RHRouter::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags)
davidr99 0:ab4e012489ef 292 {
davidr99 0:ab4e012489ef 293 unsigned long starttime = millis();
davidr99 0:ab4e012489ef 294 int32_t timeLeft;
davidr99 0:ab4e012489ef 295 while ((timeLeft = timeout - (millis() - starttime)) > 0)
davidr99 0:ab4e012489ef 296 {
davidr99 0:ab4e012489ef 297 if (waitAvailableTimeout(timeLeft))
davidr99 0:ab4e012489ef 298 {
davidr99 0:ab4e012489ef 299 if (recvfromAck(buf, len, source, dest, id, flags))
davidr99 0:ab4e012489ef 300 return true;
davidr99 0:ab4e012489ef 301 }
davidr99 0:ab4e012489ef 302 YIELD;
davidr99 0:ab4e012489ef 303 }
davidr99 0:ab4e012489ef 304 return false;
davidr99 0:ab4e012489ef 305 }
davidr99 0:ab4e012489ef 306