wardriver_uart.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. #include "wardriver_uart.h"
  2. static void removeSpaces(char* str) {
  3. int i = 0;
  4. while(isspace((unsigned char)str[i])) {
  5. i++;
  6. }
  7. int j = 0;
  8. while(str[i] != '\0') {
  9. str[j++] = str[i++];
  10. }
  11. str[j] = '\0';
  12. int len = strlen(str);
  13. while(len > 0 && isspace((unsigned char)str[len - 1])) {
  14. str[--len] = '\0';
  15. }
  16. }
  17. static void sort_access_points(Context* ctx) {
  18. for(int i = 0; i < ctx->access_points_count; i++) {
  19. for(int j = i + 1; j < ctx->access_points_count; j++) {
  20. if(strcmp(ctx->access_points[i].ssid, ctx->access_points[j].ssid) > 0) {
  21. AccessPoint temp = ctx->access_points[i];
  22. ctx->access_points[i] = ctx->access_points[j];
  23. ctx->access_points[j] = temp;
  24. }
  25. }
  26. }
  27. }
  28. static void set_index_from_access_points(Context* ctx) {
  29. for(int i = 0; i < ctx->access_points_count; i++) {
  30. if(ctx->access_points[i].bssid == ctx->active_access_point.bssid) {
  31. ctx->access_points_index = i;
  32. break;
  33. }
  34. }
  35. }
  36. static void uart_parse_esp(void* context, char* line) {
  37. Context* ctx = context;
  38. AccessPoint ap = {.ssid = malloc(MAX_SSID_LENGTH + 1), .bssid = malloc(MAX_BSSID_LENGTH + 1)};
  39. Packet pkt = {.recievedMac = malloc(18 + 1), .sentMac = malloc(18 + 1)};
  40. char* token = strtok(line, ",");
  41. int i = 0;
  42. bool isAp = false;
  43. bool isValid = false;
  44. while(token != NULL) {
  45. switch(i) {
  46. case 0:
  47. if(strcmp(token, "AR") == 0) {
  48. isAp = true;
  49. isValid = true;
  50. } else if(strcmp(token, "PK") == 0) {
  51. isValid = true;
  52. }
  53. break;
  54. case 1:
  55. if(isAp && isValid) {
  56. removeSpaces(token);
  57. strcpy(ap.ssid, token);
  58. } else if(!isAp && isValid) {
  59. strncpy(pkt.recievedMac, token, 18);
  60. pkt.recievedMac[18] = '\0';
  61. }
  62. break;
  63. case 2:
  64. if(isAp && isValid) {
  65. strcpy(ap.bssid, token);
  66. } else if(!isAp && isValid) {
  67. strncpy(pkt.sentMac, token, 18);
  68. pkt.sentMac[18] = '\0';
  69. }
  70. break;
  71. case 3:
  72. if(isAp && isValid) {
  73. ap.rssi = atoi(token);
  74. }
  75. break;
  76. case 4:
  77. if(isAp && isValid) {
  78. ap.channel = atoi(token);
  79. }
  80. break;
  81. }
  82. token = strtok(NULL, ",");
  83. i++;
  84. }
  85. if(isAp && isValid) {
  86. // free the packet
  87. free(pkt.recievedMac);
  88. free(pkt.sentMac);
  89. if(ctx->view_state == NO_APS) {
  90. ctx->view_state = NORMAL;
  91. }
  92. // check if values are valid
  93. // bssid needs an ":"
  94. // rssi needs to be negative
  95. // channel needs to be between 1 and 14
  96. // ssid needs to be at least 1 character long
  97. if(ap.bssid[2] != ':' || ap.bssid[5] != ':' || ap.bssid[8] != ':' || ap.bssid[11] != ':' ||
  98. ap.bssid[14] != ':' || ap.rssi > 0 || ap.channel < 1 || ap.channel > 14 ||
  99. strlen(ap.ssid) < 1) {
  100. free(ap.ssid);
  101. free(ap.bssid);
  102. return;
  103. }
  104. furi_hal_light_set(LightBlue, 0);
  105. furi_hal_light_set(LightGreen, 255);
  106. furi_hal_rtc_get_datetime(&ap.datetime);
  107. if(isnan(ctx->gps_data.latitude) || isnan(ctx->gps_data.longitude)) {
  108. ap.latitude = 0;
  109. ap.longitude = 0;
  110. } else {
  111. ap.latitude = ctx->gps_data.latitude;
  112. ap.longitude = ctx->gps_data.longitude;
  113. }
  114. // check if ap is already in the list otherwise add it but update the rssi
  115. bool found = false;
  116. for(size_t i = 0; i < ctx->access_points_count; i++) {
  117. if(strcmp(ctx->access_points[i].bssid, ap.bssid) == 0) {
  118. found = true;
  119. //update rssi channel datetime
  120. ctx->access_points[i].rssi = ap.rssi;
  121. ctx->access_points[i].channel = ap.channel;
  122. ctx->access_points[i].datetime = ap.datetime;
  123. ctx->access_points[i].latitude = ap.latitude;
  124. ctx->access_points[i].longitude = ap.longitude;
  125. if(strcmp(ctx->active_access_point.bssid, ap.bssid) == 0) {
  126. ctx->active_access_point.rssi = ap.rssi;
  127. ctx->active_access_point.channel = ap.channel;
  128. ctx->active_access_point.datetime = ap.datetime;
  129. ctx->active_access_point.latitude = ap.latitude;
  130. ctx->active_access_point.longitude = ap.longitude;
  131. }
  132. free(ap.ssid);
  133. free(ap.bssid);
  134. break;
  135. }
  136. }
  137. if(!found) {
  138. memcpy(&ctx->access_points[ctx->access_points_count], &ap, sizeof(AccessPoint));
  139. ctx->access_points_count++;
  140. }
  141. sort_access_points(ctx);
  142. set_index_from_access_points(ctx);
  143. } else {
  144. // it is a packet so screw the ap
  145. free(ap.ssid);
  146. free(ap.bssid);
  147. // check if values are valid
  148. // mac needs to be 6 characters long
  149. if(strlen(pkt.recievedMac) != 17 || strlen(pkt.sentMac) != 17 ||
  150. ctx->access_points_count == 0) {
  151. free(pkt.recievedMac);
  152. free(pkt.sentMac);
  153. return;
  154. }
  155. furi_hal_light_set(LightGreen, 0);
  156. furi_hal_light_set(LightBlue, 255);
  157. for(size_t i = 0; i < ctx->access_points_count; i++) {
  158. if(strcmp(ctx->access_points[i].bssid, pkt.recievedMac) == 0) {
  159. ctx->access_points[i].packetRxCount++;
  160. break;
  161. }
  162. }
  163. for(size_t i = 0; i < ctx->access_points_count; i++) {
  164. if(strcmp(ctx->access_points[i].bssid, pkt.sentMac) == 0) {
  165. ctx->access_points[i].packetTxCount++;
  166. break;
  167. }
  168. }
  169. free(pkt.recievedMac);
  170. free(pkt.sentMac);
  171. }
  172. }
  173. static void uart_cb_esp(UartIrqEvent ev, uint8_t data, void* context) {
  174. Context* ctx = (Context*)context;
  175. if(ev == UartIrqEventRXNE) {
  176. furi_stream_buffer_send(ctx->rx_stream_esp, &data, 1, 0);
  177. furi_thread_flags_set(furi_thread_get_id(ctx->thread_esp), WorkerEvtRxDone);
  178. }
  179. }
  180. static int32_t uart_worker_esp(void* context) {
  181. Context* ctx = (Context*)context;
  182. size_t rx_offset = 0;
  183. while(1) {
  184. uint32_t events =
  185. furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
  186. furi_check((events & FuriFlagError) == 0);
  187. if(events & WorkerEvtStop) {
  188. break;
  189. }
  190. if(events & WorkerEvtRxDone) {
  191. size_t len = 0;
  192. do {
  193. // receive serial bytes into rx_buf, starting at rx_offset from the start of the buffer
  194. // the maximum we can receive is RX_BUF_SIZE - 1 - rx_offset
  195. len = furi_stream_buffer_receive(
  196. ctx->rx_stream_esp,
  197. ctx->rx_buf_esp + rx_offset,
  198. RX_BUF_SIZE - 1 - rx_offset,
  199. 0);
  200. if(len > 0) {
  201. // increase rx_offset by the number of bytes received, and null-terminate rx_buf
  202. rx_offset += len;
  203. ctx->rx_buf_esp[rx_offset] = '\0';
  204. // look for strings ending in newlines, starting at the start of rx_buf
  205. char* line_current = (char*)ctx->rx_buf_esp;
  206. while(1) {
  207. // skip null characters
  208. while(*line_current == '\0' &&
  209. line_current < (char*)ctx->rx_buf_esp + rx_offset - 1) {
  210. line_current++;
  211. }
  212. // find the next newline
  213. char* newline = strchr(line_current, '\n');
  214. if(newline) // newline found
  215. {
  216. // put a null terminator in place of the newline, to delimit the line string
  217. *newline = '\0';
  218. uart_parse_esp(ctx, line_current);
  219. // move the cursor to the character after the newline
  220. line_current = newline + 1;
  221. } else // no more newlines found
  222. {
  223. if(line_current >
  224. (char*)ctx->rx_buf_esp) // at least one line was found
  225. {
  226. // clear parsed lines, and move any leftover bytes to the start of rx_buf
  227. rx_offset = 0;
  228. while(
  229. *line_current) // stop when the original rx_offset terminator is reached
  230. {
  231. ctx->rx_buf_esp[rx_offset++] = *(line_current++);
  232. }
  233. }
  234. break; // go back to receiving bytes from the serial stream
  235. }
  236. }
  237. }
  238. } while(len > 0);
  239. }
  240. }
  241. return 0;
  242. }
  243. static void uart_parse_gps(Context* ctx, char* line) {
  244. switch(minmea_sentence_id(line, false)) {
  245. case MINMEA_SENTENCE_RMC: {
  246. struct minmea_sentence_rmc frame;
  247. if(minmea_parse_rmc(&frame, line)) {
  248. ctx->gps_data.latitude = minmea_tocoord(&frame.latitude);
  249. ctx->gps_data.longitude = minmea_tocoord(&frame.longitude);
  250. ctx->gps_data.hour = frame.time.hours;
  251. ctx->gps_data.minute = frame.time.minutes;
  252. ctx->gps_data.second = frame.time.seconds;
  253. }
  254. } break;
  255. case MINMEA_SENTENCE_GGA: {
  256. struct minmea_sentence_gga frame;
  257. if(minmea_parse_gga(&frame, line)) {
  258. ctx->gps_data.latitude = minmea_tocoord(&frame.latitude);
  259. ctx->gps_data.longitude = minmea_tocoord(&frame.longitude);
  260. ctx->gps_data.hour = frame.time.hours;
  261. ctx->gps_data.minute = frame.time.minutes;
  262. ctx->gps_data.second = frame.time.seconds;
  263. ctx->gps_data.satelites = frame.satellites_tracked;
  264. }
  265. } break;
  266. case MINMEA_SENTENCE_GLL: {
  267. struct minmea_sentence_gll frame;
  268. if(minmea_parse_gll(&frame, line)) {
  269. ctx->gps_data.latitude = minmea_tocoord(&frame.latitude);
  270. ctx->gps_data.longitude = minmea_tocoord(&frame.longitude);
  271. ctx->gps_data.hour = frame.time.hours;
  272. ctx->gps_data.minute = frame.time.minutes;
  273. ctx->gps_data.second = frame.time.seconds;
  274. }
  275. } break;
  276. default:
  277. break;
  278. }
  279. }
  280. static void uart_cb_gps(UartIrqEvent ev, uint8_t data, void* context) {
  281. Context* ctx = (Context*)context;
  282. if(ev == UartIrqEventRXNE) {
  283. furi_stream_buffer_send(ctx->rx_stream_gps, &data, 1, 0);
  284. furi_thread_flags_set(furi_thread_get_id(ctx->thread_gps), WorkerEvtRxDone);
  285. }
  286. }
  287. static int32_t uart_worker_gps(void* context) {
  288. Context* ctx = (Context*)context;
  289. size_t rx_offset = 0;
  290. while(1) {
  291. uint32_t events =
  292. furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
  293. furi_check((events & FuriFlagError) == 0);
  294. if(events & WorkerEvtStop) {
  295. break;
  296. }
  297. if(events & WorkerEvtRxDone) {
  298. size_t len = 0;
  299. do {
  300. // receive serial bytes into rx_buf, starting at rx_offset from the start of the buffer
  301. // the maximum we can receive is RX_BUF_SIZE - 1 - rx_offset
  302. len = furi_stream_buffer_receive(
  303. ctx->rx_stream_gps,
  304. ctx->rx_buf_gps + rx_offset,
  305. RX_BUF_SIZE - 1 - rx_offset,
  306. 0);
  307. if(len > 0) {
  308. // increase rx_offset by the number of bytes received, and null-terminate rx_buf
  309. rx_offset += len;
  310. ctx->rx_buf_gps[rx_offset] = '\0';
  311. // look for strings ending in newlines, starting at the start of rx_buf
  312. char* line_current = (char*)ctx->rx_buf_gps;
  313. while(1) {
  314. // skip null characters
  315. while(*line_current == '\0' &&
  316. line_current < (char*)ctx->rx_buf_gps + rx_offset - 1) {
  317. line_current++;
  318. }
  319. // find the next newline
  320. char* newline = strchr(line_current, '\n');
  321. if(newline) // newline found
  322. {
  323. // put a null terminator in place of the newline, to delimit the line string
  324. *newline = '\0';
  325. uart_parse_gps(ctx, line_current);
  326. // move the cursor to the character after the newline
  327. line_current = newline + 1;
  328. } else // no more newlines found
  329. {
  330. if(line_current >
  331. (char*)ctx->rx_buf_gps) // at least one line was found
  332. {
  333. // clear parsed lines, and move any leftover bytes to the start of rx_buf
  334. rx_offset = 0;
  335. while(
  336. *line_current) // stop when the original rx_offset terminator is reached
  337. {
  338. ctx->rx_buf_gps[rx_offset++] = *(line_current++);
  339. }
  340. }
  341. break; // go back to receiving bytes from the serial stream
  342. }
  343. }
  344. }
  345. } while(len > 0);
  346. }
  347. }
  348. return 0;
  349. }
  350. void wardriver_uart_init(Context* ctx) {
  351. ctx->rx_stream_esp = furi_stream_buffer_alloc(RX_BUF_SIZE, 1);
  352. ctx->thread_esp = furi_thread_alloc();
  353. furi_thread_set_name(ctx->thread_esp, "LLwardriverUartWorkerESP");
  354. furi_thread_set_stack_size(ctx->thread_esp, 2048);
  355. furi_thread_set_context(ctx->thread_esp, ctx);
  356. furi_thread_set_callback(ctx->thread_esp, uart_worker_esp);
  357. furi_thread_start(ctx->thread_esp);
  358. if(UART_CH_ESP == FuriHalUartIdUSART1) {
  359. furi_hal_console_disable();
  360. } else if(UART_CH_ESP == FuriHalUartIdLPUART1) {
  361. furi_hal_uart_init(UART_CH_ESP, 115200);
  362. }
  363. furi_hal_uart_set_br(UART_CH_ESP, 115200);
  364. furi_hal_uart_set_irq_cb(UART_CH_ESP, uart_cb_esp, ctx);
  365. if(UART_CH_ESP != UART_CH_GPS) {
  366. ctx->rx_stream_gps = furi_stream_buffer_alloc(RX_BUF_SIZE, 1);
  367. ctx->thread_gps = furi_thread_alloc();
  368. furi_thread_set_name(ctx->thread_gps, "LLwardriverUartWorkerGPS");
  369. furi_thread_set_stack_size(ctx->thread_gps, 2048);
  370. furi_thread_set_context(ctx->thread_gps, ctx);
  371. furi_thread_set_callback(ctx->thread_gps, uart_worker_gps);
  372. furi_thread_start(ctx->thread_gps);
  373. if(UART_CH_GPS == FuriHalUartIdUSART1) {
  374. furi_hal_console_disable();
  375. } else if(UART_CH_GPS == FuriHalUartIdLPUART1) {
  376. furi_hal_uart_init(UART_CH_GPS, 9600);
  377. }
  378. furi_hal_uart_set_br(UART_CH_GPS, 9600);
  379. furi_hal_uart_set_irq_cb(UART_CH_GPS, uart_cb_gps, ctx);
  380. }
  381. return;
  382. }
  383. void wardriver_uart_deinit(Context* ctx) {
  384. furi_thread_flags_set(furi_thread_get_id(ctx->thread_esp), WorkerEvtStop);
  385. furi_thread_join(ctx->thread_esp);
  386. furi_thread_free(ctx->thread_esp);
  387. furi_hal_uart_set_irq_cb(UART_CH_ESP, NULL, NULL);
  388. furi_stream_buffer_free(ctx->rx_stream_esp);
  389. if(UART_CH_ESP != UART_CH_GPS) {
  390. furi_thread_flags_set(furi_thread_get_id(ctx->thread_gps), WorkerEvtStop);
  391. furi_thread_join(ctx->thread_gps);
  392. furi_thread_free(ctx->thread_gps);
  393. furi_hal_uart_set_irq_cb(UART_CH_GPS, NULL, NULL);
  394. furi_stream_buffer_free(ctx->rx_stream_gps);
  395. }
  396. if(UART_CH_ESP == FuriHalUartIdLPUART1) {
  397. furi_hal_uart_deinit(UART_CH_ESP);
  398. } else if(UART_CH_ESP == FuriHalUartIdUSART1) {
  399. furi_hal_console_enable();
  400. }
  401. if(UART_CH_GPS == FuriHalUartIdLPUART1) {
  402. furi_hal_uart_deinit(UART_CH_GPS);
  403. } else if(UART_CH_GPS == FuriHalUartIdUSART1) {
  404. furi_hal_console_enable();
  405. }
  406. return;
  407. }