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.
Dependents: Threaded_LoRa_Modem
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 Thu Jul 14 2022 12:14:50 by
1.7.2