This driver is a stripped down version of the Radiohead 1.45 driver, and covers fewer radios. Threading and an event queue have been added to make the ISR's more stable across architectures. Specifically The STM32L4 parts

Dependents:   Threaded_LoRa_Modem

Committer:
davidr99
Date:
Thu Oct 15 01:27:00 2015 +0000
Revision:
0:ab4e012489ef
Messy start, but a port for RadioHead.; Currently the SPI modulus are the only ones that work.

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