PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/SensorController/lpc1758_freertos/L5_Application/source/cmd_handlers/wireless_handlers.cpp

https://gitlab.com/ajaik91/Team_AutoNav
C++ | 343 lines | 257 code | 51 blank | 35 comment | 49 complexity | e3906722b59995101fec5e095474f69a MD5 | raw file
  1. #include <stdint.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include "command_handler.hpp"
  5. #include "wireless.h"
  6. #include "nrf_stream.hpp"
  7. #include "ff.h"
  8. #if MESH_USE_STATISTICS
  9. static void wirelessHandlerPrintStats(CharDev& output, mesh_stats_t *s, uint8_t node)
  10. {
  11. output.printf("N%u: Rx/Tx, Rte/Ovt, Retried/Mesh Retried/Repeated: \n", node);
  12. output.printf(" %3u/%-3u %u/%u, %u/%u/%u\n",
  13. s->pkts_intercepted, s->pkts_sent,
  14. s->rte_entries, s->rte_overwritten,
  15. s->pkts_retried, s->pkts_retried_others, s->pkts_repeated);
  16. }
  17. #endif
  18. static CMD_HANDLER_FUNC(wsStreamHandler)
  19. {
  20. const int outBlockTime = 1;
  21. const int timeout_ms = 1000;
  22. int addr = 0;
  23. cmdParams.scanf("%i", &addr);
  24. cmdParams.eraseFirstWords(1);
  25. if (0 == addr || 0 == cmdParams.getLen())
  26. {
  27. output.putline("Parse error: try: 'stream <addr> <command>'");
  28. }
  29. else
  30. {
  31. // Send the command to another nordic
  32. NordicStream &n = NordicStream::getInstance();
  33. // Flush any stale data:
  34. char c = 0;
  35. while (n.getChar(&c, 5)) {
  36. ;
  37. }
  38. n.setDestAddr(addr);
  39. n.putline(cmdParams());
  40. n.flush();
  41. // Terminal sends unique last four chars to indicate end of output
  42. const char endOfTx[] = TERMINAL_END_CHARS;
  43. char lastChars[sizeof(endOfTx)] = { 0 };
  44. int count = 0;
  45. int dropped = 0;
  46. /**
  47. * Output the response
  48. * @warning We collect data from nordic and output to possibly UART0 @ 38400bps
  49. * If nordic floods us with data, our UART output may block because it is slow,
  50. * therefore you may want to look at the possible suggestions :
  51. * - Use faster UART (115200bps, but you still won't match Nordic's 2000Kbps)
  52. * - Use higher UART Tx queue size (but you may still overflow eventually)
  53. * See SYS_CFG_UART0_TXQ_SIZE at sys_config.h
  54. * - Increase the WIRELESS_RX_QUEUE_SIZE at sys_config.h and increase outBlockTime
  55. * This will guarantee you can output 24 * N bytes before we overflow data.
  56. * - At nrf_stream.cpp, slow down the output rate. The best hack is to
  57. * putchar() each data byte, which slows down the data rate to UART0
  58. */
  59. while (n.getChar(&c, timeout_ms))
  60. {
  61. /*
  62. * Terminate loop early if we see end of output characters
  63. * We intentionally will not print the last terminating character such that the
  64. * parent command handler can print that instead to indicate end of output.
  65. */
  66. memmove(&lastChars[0], &lastChars[1], sizeof(endOfTx) - 1);
  67. lastChars[sizeof(endOfTx) - 1] = c;
  68. if (0 == memcmp(&lastChars[0], &endOfTx[0], sizeof(endOfTx))) {
  69. break;
  70. }
  71. ++count;
  72. if (!output.putChar(c, outBlockTime)) {
  73. dropped++;
  74. }
  75. }
  76. int pkts = count / MESH_DATA_PAYLOAD_SIZE;
  77. if (0 != (count % MESH_DATA_PAYLOAD_SIZE)) {
  78. pkts++;
  79. }
  80. output.printf(" Received %i bytes over %i packets\n", count, pkts);
  81. if (dropped > 0) {
  82. output.printf("Whoops! Approximately %i bytes could not be printed because the output "
  83. "channel is too slow. Please follow the suggestions at "
  84. "file: %s a little bit above while loop at line number %i\n",
  85. dropped, __FILE__, __LINE__);
  86. }
  87. }
  88. return true;
  89. }
  90. static CMD_HANDLER_FUNC(wsFileTxHandler)
  91. {
  92. /**
  93. * If other node is running same software, we will just use its "file" handler:
  94. * buffer <offset> <num bytes> ...
  95. * commit <filename> <file offset> <num bytes from buffer>
  96. */
  97. char srcFile[128] = { 0 };
  98. char dstFile[128] = { 0 };
  99. int timeout = 1000;
  100. int addr = 0;
  101. FIL file;
  102. if (3 != cmdParams.scanf("%128s %128s %i", &srcFile[0], &dstFile[0], &addr)) {
  103. return false;
  104. }
  105. if (FR_OK != f_open(&file, srcFile, FA_OPEN_EXISTING | FA_READ)) {
  106. return false;
  107. }
  108. NordicStream &n = NordicStream::getInstance();
  109. n.setDestAddr(addr);
  110. char c = 0;
  111. char buffer[512];
  112. int expectedChecksum = 0;
  113. unsigned int bytesRead = 0;
  114. unsigned int fileOffset = 0;
  115. unsigned int retries = 0;
  116. unsigned int retriesMax = 3;
  117. STR_ON_STACK(response, 128);
  118. // Sorry for the dirty hack #define
  119. #define doRetry() ++retries; n.printf("\n"); n.flush(); while (n.getChar(&c, timeout)); goto retry
  120. output.printf("Transfer %s --> %i:%s\n", srcFile, addr, dstFile);
  121. while(FR_OK == f_read(&file, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0)
  122. {
  123. retry:
  124. if (retries >= retriesMax) {
  125. break;
  126. }
  127. n.printf("file buffer 0 %i\n", bytesRead);
  128. n.flush();
  129. expectedChecksum = 0;
  130. for (unsigned int i=0; i < bytesRead; i++) {
  131. n.putChar(buffer[i]);
  132. expectedChecksum += buffer[i];
  133. }
  134. n.flush();
  135. // Confirm the checksum: response should be something like "Checksum: 123"
  136. n.gets((char*) response(), response.getCapacity(), timeout);
  137. response.eraseFirstWords(1);
  138. if ( (int)response != expectedChecksum) {
  139. output.printf("ERROR: Checksum Expected %i Actual %i\n", expectedChecksum, (int) response);
  140. doRetry();
  141. }
  142. // Make sure the file was written correctly, response should be "OK"
  143. n.printf("file commit %s %i %i\n", dstFile, fileOffset, bytesRead);
  144. n.flush();
  145. n.gets((char*) response(), response.getCapacity(), timeout);
  146. if (!response.containsIgnoreCase("ok")) {
  147. output.printf("ERROR: Remote node did not acknowledge file write (%s)\n", response());
  148. doRetry();
  149. }
  150. response = "";
  151. fileOffset += bytesRead;
  152. output.printf("Sent %i/%i\n", fileOffset, file.fsize);
  153. // Reset the retries such that only if we fail continuously we will give up
  154. if (retries > 0) {
  155. --retries;
  156. }
  157. }
  158. f_close(&file);
  159. return true;
  160. }
  161. static CMD_HANDLER_FUNC(wsRxHandler)
  162. {
  163. bool rx = false;
  164. int timeout_ms = 1000;
  165. mesh_packet_t pkt;
  166. cmdParams.scanf("%i", &timeout_ms);
  167. while (wireless_get_rx_pkt(&pkt, timeout_ms)) {
  168. output.printf("Received data from %i\n", pkt.nwk.src);
  169. for (int i = 0; i < pkt.info.data_len; i++) {
  170. output.putChar(pkt.data[i]);
  171. }
  172. output.printf("\n");
  173. rx = true;
  174. }
  175. if (!rx) {
  176. output.putline("No data received");
  177. }
  178. return true;
  179. }
  180. static CMD_HANDLER_FUNC(wsAddrHandler)
  181. {
  182. int addr = (int) cmdParams;
  183. output.printf("Set address to %i: %s\n", addr, mesh_set_node_address(addr) ? "OK" : "FAILED");
  184. return true;
  185. }
  186. CMD_HANDLER_FUNC(wsRteHandler)
  187. {
  188. const char * const line = "-------------------------\n";
  189. const int routes = mesh_get_num_routing_entries();
  190. output.printf(line);
  191. output.printf("Routing table size is %i\n", routes);
  192. output.printf(line);
  193. if (routes > 0)
  194. {
  195. output.printf("| DST | Next HOP | HOPS |\n");
  196. output.printf(line);
  197. const mesh_rte_table_t *e = NULL;
  198. uint8_t i = 0;
  199. while ((e = mesh_get_routing_entry(i++))) {
  200. output.printf("| %3i | %3i | %3i |\n", e->dst, e->next_hop, e->num_hops);
  201. }
  202. output.printf(line);
  203. }
  204. return true;
  205. }
  206. #if MESH_USE_STATISTICS
  207. static CMD_HANDLER_FUNC(wsStatsHandler)
  208. {
  209. mesh_stats_t stats = mesh_get_stats();
  210. wirelessHandlerPrintStats(output, &stats, mesh_get_node_address());
  211. return true;
  212. }
  213. #endif
  214. static CMD_HANDLER_FUNC(wsTxHandler)
  215. {
  216. char *addr_str = NULL;
  217. char *data_str = NULL;
  218. const bool ack = pDataParam;
  219. const int max_hops_to_use = 2;
  220. int timeout_ms = 1000;
  221. mesh_packet_t pkt;
  222. #if MESH_USE_STATISTICS
  223. mesh_stats_t stats = { 0 };
  224. #endif
  225. if (cmdParams.tokenize(" ", 2, &addr_str, &data_str) < 1) {
  226. return false;
  227. }
  228. /* Data is optional */
  229. const uint8_t dst_addr = atoi(addr_str);
  230. const uint8_t len = data_str ? strlen(data_str) : 0;
  231. // Flush any packets
  232. while (wireless_get_rx_pkt(&pkt, 0)) {
  233. output.putline("Discarded a stale wireless packet");
  234. ;
  235. }
  236. if (! wireless_send(dst_addr, ack ? mesh_pkt_ack : mesh_pkt_nack, data_str, len, max_hops_to_use)) {
  237. output.putline("Error sending packet, check parameters!");
  238. }
  239. /* If ack was requested, then we wait for the ack */
  240. else if (ack)
  241. {
  242. if(wireless_get_ack_pkt(&pkt, timeout_ms) && dst_addr == pkt.nwk.src)
  243. {
  244. #if MESH_USE_STATISTICS
  245. if (sizeof(stats) == pkt.info.data_len) {
  246. mesh_stats_t *p = (mesh_stats_t*) &(pkt.data[0]);
  247. wirelessHandlerPrintStats(output, p, pkt.nwk.src);
  248. }
  249. #endif
  250. /* Response to ping packet, so print the node name: */
  251. if (0 == len) {
  252. output.printf("Remote node name: '");
  253. for (int i=0; i<pkt.info.data_len; i++) {
  254. output.putChar(pkt.data[i]);
  255. }
  256. output.printf("'\n");
  257. }
  258. else {
  259. output.putline("Received the acknowledgment!");
  260. }
  261. }
  262. else {
  263. output.printf("Packet sent to %s but no ACK received", addr_str);
  264. }
  265. }
  266. return true;
  267. }
  268. CMD_HANDLER_FUNC(wirelessHandler)
  269. {
  270. static CommandProcessor *pCmdProcessor = NULL;
  271. if (NULL == pCmdProcessor)
  272. {
  273. pCmdProcessor = new CommandProcessor(8);
  274. pCmdProcessor->addHandler(wsStreamHandler, "stream", "'stream <addr> <msg>' : Stream a command to another board");
  275. pCmdProcessor->addHandler(wsFileTxHandler, "transfer", "'transfer <src filename> <dst filename> <naddr>' : Transfer a file to another board");
  276. pCmdProcessor->addHandler(wsRxHandler, "rx", "'rx <time_ms>' : Poll for a packet");
  277. pCmdProcessor->addHandler(wsAddrHandler, "addr", "'addr <addr> : Set the wireless address");
  278. pCmdProcessor->addHandler(wsRteHandler, "routes", "'routes' : See the wireless routes");
  279. void *ack = (void*) 1;
  280. void *nack = 0;
  281. pCmdProcessor->addHandler(wsTxHandler, "ack", "'ack <addr> <data>' : Send a packet and wait for acknowledgment", ack);
  282. pCmdProcessor->addHandler(wsTxHandler, "nack", "'nack <addr> <data>' : Send a packet", nack);
  283. #if MESH_USE_STATISTICS
  284. pCmdProcessor->addHandler(wsStatsHandler, "stats", "'stats' : See the wireless stats");
  285. #endif
  286. }
  287. /* Display help for empty command */
  288. if (cmdParams == "") {
  289. cmdParams = "help";
  290. }
  291. return pCmdProcessor->handleCommand(cmdParams, output);
  292. }