PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

307 satır
8.9KB

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