David Rimer / RadioHead-148
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers RHRouter.cpp Source File

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