Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
RHRouter.cpp
00001 // RHRouter.cpp 00002 // 00003 // Define addressed datagram 00004 // 00005 // Part of the Arduino RH library for operating with HopeRF RH compatible transceivers 00006 // (see http://www.hoperf.com) 00007 // RHDatagram will be received only by the addressed node or all nodes within range if the 00008 // to address is RH_BROADCAST_ADDRESS 00009 // 00010 // Author: Mike McCauley (mikem@airspayce.com) 00011 // Copyright (C) 2011 Mike McCauley 00012 // $Id: RHRouter.cpp,v 1.7 2015/08/13 02:45:47 mikem Exp $ 00013 00014 #include <RHRouter.h> 00015 00016 RHRouter::RoutedMessage RHRouter::_tmpMessage; 00017 00018 //////////////////////////////////////////////////////////////////// 00019 // Constructors 00020 RHRouter::RHRouter(RHGenericDriver& driver, uint8_t thisAddress) 00021 : RHReliableDatagram(driver, thisAddress) 00022 { 00023 _max_hops = RH_DEFAULT_MAX_HOPS; 00024 clearRoutingTable(); 00025 } 00026 00027 //////////////////////////////////////////////////////////////////// 00028 // Public methods 00029 bool RHRouter::init() 00030 { 00031 bool ret = RHReliableDatagram::init(); 00032 if (ret) 00033 _max_hops = RH_DEFAULT_MAX_HOPS; 00034 return ret; 00035 } 00036 00037 //////////////////////////////////////////////////////////////////// 00038 void RHRouter::setMaxHops(uint8_t max_hops) 00039 { 00040 _max_hops = max_hops; 00041 } 00042 00043 //////////////////////////////////////////////////////////////////// 00044 void RHRouter::addRouteTo(uint8_t dest, uint8_t next_hop, uint8_t state) 00045 { 00046 uint8_t i; 00047 00048 // First look for an existing entry we can update 00049 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++) 00050 { 00051 if (_routes[i].dest == dest) 00052 { 00053 _routes[i].dest = dest; 00054 _routes[i].next_hop = next_hop; 00055 _routes[i].state = state; 00056 return; 00057 } 00058 } 00059 00060 // Look for an invalid entry we can use 00061 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++) 00062 { 00063 if (_routes[i].state == Invalid) 00064 { 00065 _routes[i].dest = dest; 00066 _routes[i].next_hop = next_hop; 00067 _routes[i].state = state; 00068 return; 00069 } 00070 } 00071 00072 // Need to make room for a new one 00073 retireOldestRoute(); 00074 // Should be an invalid slot now 00075 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++) 00076 { 00077 if (_routes[i].state == Invalid) 00078 { 00079 _routes[i].dest = dest; 00080 _routes[i].next_hop = next_hop; 00081 _routes[i].state = state; 00082 } 00083 } 00084 } 00085 00086 //////////////////////////////////////////////////////////////////// 00087 RHRouter::RoutingTableEntry* RHRouter::getRouteTo(uint8_t dest) 00088 { 00089 uint8_t i; 00090 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++) 00091 if (_routes[i].dest == dest && _routes[i].state != Invalid) 00092 return &_routes[i]; 00093 return NULL; 00094 } 00095 00096 //////////////////////////////////////////////////////////////////// 00097 void RHRouter::deleteRoute(uint8_t index) 00098 { 00099 // Delete a route by copying following routes on top of it 00100 memcpy(&_routes[index], &_routes[index+1], 00101 sizeof(RoutingTableEntry) * (RH_ROUTING_TABLE_SIZE - index - 1)); 00102 _routes[RH_ROUTING_TABLE_SIZE - 1].state = Invalid; 00103 } 00104 00105 //////////////////////////////////////////////////////////////////// 00106 void RHRouter::printRoutingTable() 00107 { 00108 #ifdef RH_HAVE_SERIAL 00109 uint8_t i; 00110 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++) 00111 { 00112 Serial.print(i, DEC); 00113 Serial.print(" Dest: "); 00114 Serial.print(_routes[i].dest, DEC); 00115 Serial.print(" Next Hop: "); 00116 Serial.print(_routes[i].next_hop, DEC); 00117 Serial.print(" State: "); 00118 Serial.println(_routes[i].state, DEC); 00119 } 00120 #endif 00121 } 00122 00123 //////////////////////////////////////////////////////////////////// 00124 bool RHRouter::deleteRouteTo(uint8_t dest) 00125 { 00126 uint8_t i; 00127 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++) 00128 { 00129 if (_routes[i].dest == dest) 00130 { 00131 deleteRoute(i); 00132 return true; 00133 } 00134 } 00135 return false; 00136 } 00137 00138 //////////////////////////////////////////////////////////////////// 00139 void RHRouter::retireOldestRoute() 00140 { 00141 // We just obliterate the first in the table and clear the last 00142 deleteRoute(0); 00143 } 00144 00145 //////////////////////////////////////////////////////////////////// 00146 void RHRouter::clearRoutingTable() 00147 { 00148 uint8_t i; 00149 for (i = 0; i < RH_ROUTING_TABLE_SIZE; i++) 00150 _routes[i].state = Invalid; 00151 } 00152 00153 00154 uint8_t RHRouter::sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest, uint8_t flags) 00155 { 00156 return sendtoFromSourceWait(buf, len, dest, _thisAddress, flags); 00157 } 00158 00159 //////////////////////////////////////////////////////////////////// 00160 // Waits for delivery to the next hop (but not for delivery to the final destination) 00161 uint8_t RHRouter::sendtoFromSourceWait(uint8_t* buf, uint8_t len, uint8_t dest, uint8_t source, uint8_t flags) 00162 { 00163 if (((uint16_t)len + sizeof(RoutedMessageHeader)) > _driver.maxMessageLength()) 00164 return RH_ROUTER_ERROR_INVALID_LENGTH; 00165 00166 // Construct a RH RouterMessage message 00167 _tmpMessage.header.source = source; 00168 _tmpMessage.header.dest = dest; 00169 _tmpMessage.header.hops = 0; 00170 _tmpMessage.header.id = _lastE2ESequenceNumber++; 00171 _tmpMessage.header.flags = flags; 00172 memcpy(_tmpMessage.data, buf, len); 00173 00174 return route(&_tmpMessage, sizeof(RoutedMessageHeader)+len); 00175 } 00176 00177 //////////////////////////////////////////////////////////////////// 00178 uint8_t RHRouter::route(RoutedMessage* message, uint8_t messageLen) 00179 { 00180 // Reliably deliver it if possible. See if we have a route: 00181 uint8_t next_hop = RH_BROADCAST_ADDRESS; 00182 if (message->header.dest != RH_BROADCAST_ADDRESS) 00183 { 00184 RoutingTableEntry* route = getRouteTo(message->header.dest); 00185 if (!route) 00186 return RH_ROUTER_ERROR_NO_ROUTE; 00187 next_hop = route->next_hop; 00188 } 00189 00190 if (!RHReliableDatagram::sendtoWait((uint8_t*)message, messageLen, next_hop)) 00191 return RH_ROUTER_ERROR_UNABLE_TO_DELIVER; 00192 00193 return RH_ROUTER_ERROR_NONE; 00194 } 00195 00196 //////////////////////////////////////////////////////////////////// 00197 // Subclasses may want to override this to peek at messages going past 00198 void RHRouter::peekAtMessage(RoutedMessage* message, uint8_t messageLen) 00199 { 00200 // Default does nothing 00201 } 00202 00203 //////////////////////////////////////////////////////////////////// 00204 bool RHRouter::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags) 00205 { 00206 uint8_t tmpMessageLen = sizeof(_tmpMessage); 00207 uint8_t _from; 00208 uint8_t _to; 00209 uint8_t _id; 00210 uint8_t _flags; 00211 if (RHReliableDatagram::recvfromAck((uint8_t*)&_tmpMessage, &tmpMessageLen, &_from, &_to, &_id, &_flags)) 00212 { 00213 // Here we simulate networks with limited visibility between nodes 00214 // so we can test routing 00215 #ifdef RH_TEST_NETWORK 00216 if ( 00217 #if RH_TEST_NETWORK==1 00218 // This network looks like 1-2-3-4 00219 (_thisAddress == 1 && _from == 2) 00220 || (_thisAddress == 2 && (_from == 1 || _from == 3)) 00221 || (_thisAddress == 3 && (_from == 2 || _from == 4)) 00222 || (_thisAddress == 4 && _from == 3) 00223 00224 #elif RH_TEST_NETWORK==2 00225 // This network looks like 1-2-4 00226 // | | | 00227 // --3-- 00228 (_thisAddress == 1 && (_from == 2 || _from == 3)) 00229 || _thisAddress == 2 00230 || _thisAddress == 3 00231 || (_thisAddress == 4 && (_from == 2 || _from == 3)) 00232 00233 #elif RH_TEST_NETWORK==3 00234 // This network looks like 1-2-4 00235 // | | 00236 // --3-- 00237 (_thisAddress == 1 && (_from == 2 || _from == 3)) 00238 || (_thisAddress == 2 && (_from == 1 || _from == 4)) 00239 || (_thisAddress == 3 && (_from == 1 || _from == 4)) 00240 || (_thisAddress == 4 && (_from == 2 || _from == 3)) 00241 00242 #elif RH_TEST_NETWORK==4 00243 // This network looks like 1-2-3 00244 // | 00245 // 4 00246 (_thisAddress == 1 && _from == 2) 00247 || _thisAddress == 2 00248 || (_thisAddress == 3 && _from == 2) 00249 || (_thisAddress == 4 && _from == 2) 00250 00251 #endif 00252 ) 00253 { 00254 // OK 00255 } 00256 else 00257 { 00258 return false; // Pretend we got nothing 00259 } 00260 #endif 00261 00262 peekAtMessage(&_tmpMessage, tmpMessageLen); 00263 // See if its for us or has to be routed 00264 if (_tmpMessage.header.dest == _thisAddress || _tmpMessage.header.dest == RH_BROADCAST_ADDRESS) 00265 { 00266 // Deliver it here 00267 if (source) *source = _tmpMessage.header.source; 00268 if (dest) *dest = _tmpMessage.header.dest; 00269 if (id) *id = _tmpMessage.header.id; 00270 if (flags) *flags = _tmpMessage.header.flags; 00271 uint8_t msgLen = tmpMessageLen - sizeof(RoutedMessageHeader); 00272 if (*len > msgLen) 00273 *len = msgLen; 00274 memcpy(buf, _tmpMessage.data, *len); 00275 return true; // Its for you! 00276 } 00277 else if ( _tmpMessage.header.dest != RH_BROADCAST_ADDRESS 00278 && _tmpMessage.header.hops++ < _max_hops) 00279 { 00280 // Maybe it has to be routed to the next hop 00281 // REVISIT: if it fails due to no route or unable to deliver to the next hop, 00282 // tell the originator. BUT HOW? 00283 route(&_tmpMessage, tmpMessageLen); 00284 } 00285 // Discard it and maybe wait for another 00286 } 00287 return false; 00288 } 00289 00290 //////////////////////////////////////////////////////////////////// 00291 bool RHRouter::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags) 00292 { 00293 unsigned long starttime = millis(); 00294 int32_t timeLeft; 00295 while ((timeLeft = timeout - (millis() - starttime)) > 0) 00296 { 00297 if (waitAvailableTimeout(timeLeft)) 00298 { 00299 if (recvfromAck(buf, len, source, dest, id, flags)) 00300 return true; 00301 } 00302 YIELD; 00303 } 00304 return false; 00305 } 00306
Generated on Tue Jul 12 2022 18:05:56 by
