sniffer.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <gui/gui.h>
  4. #include <notification/notification_messages.h>
  5. #include <assets_icons.h>
  6. #include <toolbox/stream/file_stream.h>
  7. #include <xtreme.h>
  8. #include "helpers/minmea.h"
  9. #include "wifisniffer_icons.h"
  10. #define appname "ll-wifisniffer"
  11. #define RX_BUF_SIZE 2048
  12. #define MAX_ACCESS_POINTS 2048 // imagine getting this many access points
  13. #define MAX_SSID_LENGTH 32
  14. #define MAX_BSSID_LENGTH 18
  15. #define UART_CH_ESP \
  16. (xtreme_settings.uart_esp_channel == UARTDefault ? FuriHalUartIdUSART1 : FuriHalUartIdLPUART1)
  17. #define UART_CH_GPS \
  18. (xtreme_settings.uart_nmea_channel == UARTDefault ? FuriHalUartIdUSART1 : FuriHalUartIdLPUART1)
  19. #define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxDone)
  20. typedef enum {
  21. WorkerEvtStop = (1 << 0),
  22. WorkerEvtRxDone = (1 << 1),
  23. } WorkerEvtFlags;
  24. typedef enum {
  25. EventTypeKey,
  26. EventTypeTick,
  27. } EventType;
  28. typedef struct {
  29. EventType type;
  30. InputEvent input;
  31. } Event;
  32. typedef struct {
  33. char* recievedMac;
  34. char* sentMac;
  35. } Packet;
  36. typedef struct {
  37. char* ssid;
  38. char* bssid;
  39. int8_t rssi;
  40. uint8_t channel;
  41. FuriHalRtcDateTime datetime;
  42. uint16_t packetRxCount;
  43. uint16_t packetTxCount;
  44. float latitude;
  45. float longitude;
  46. } AccessPoint;
  47. typedef struct {
  48. FuriMessageQueue* queue;
  49. FuriMutex* mutex;
  50. FuriString* buffer;
  51. FuriString* buffer2;
  52. NotificationApp* notifications;
  53. FuriThread* thread_esp;
  54. FuriStreamBuffer* rx_stream_esp;
  55. uint8_t rx_buf_esp[2048];
  56. FuriThread* thread_gps;
  57. FuriStreamBuffer* rx_stream_gps;
  58. uint8_t rx_buf_gps[2048];
  59. File* file;
  60. char* dataString;
  61. uint16_t access_points_count;
  62. AccessPoint access_points[MAX_ACCESS_POINTS];
  63. int16_t access_points_index;
  64. AccessPoint active_access_point;
  65. bool extra_info;
  66. bool pressedButton;
  67. float last_latitude;
  68. float last_longitude;
  69. } Context;
  70. static void tick_callback(void* ctx_q) {
  71. furi_assert(ctx_q);
  72. FuriMessageQueue* queue = ctx_q;
  73. Event event = {.type = EventTypeTick};
  74. furi_message_queue_put(queue, &event, 0);
  75. }
  76. static void input_callback(InputEvent* input_event, FuriMessageQueue* queue) {
  77. furi_assert(queue);
  78. Event event = {.type = EventTypeKey, .input = *input_event};
  79. furi_message_queue_put(queue, &event, FuriWaitForever);
  80. }
  81. static void show_access_point(Canvas* canvas, Context* context) {
  82. Context* ctx = context;
  83. AccessPoint ap = ctx->active_access_point;
  84. canvas_draw_str_aligned(canvas, 62, 25, AlignCenter, AlignBottom, ap.ssid);
  85. canvas_set_font(canvas, FontSecondary);
  86. canvas_draw_str_aligned(
  87. canvas, 38 + (ctx->access_points_count > 99 ? 5 : 0), 12, AlignLeft, AlignBottom, ap.bssid);
  88. furi_string_printf(ctx->buffer, "Signal strength: %ddBm", ap.rssi);
  89. canvas_draw_str_aligned(
  90. canvas, 3, 35, AlignLeft, AlignBottom, furi_string_get_cstr(ctx->buffer));
  91. furi_string_printf(ctx->buffer, "CH: %d", ap.channel);
  92. canvas_draw_str_aligned(
  93. canvas, 3, 47, AlignLeft, AlignBottom, furi_string_get_cstr(ctx->buffer));
  94. if(ap.latitude == 0 && ap.longitude == 0) {
  95. canvas_draw_str_aligned(canvas, 29, 47, AlignLeft, AlignBottom, "X");
  96. } else {
  97. canvas_draw_str_aligned(canvas, 29, 47, AlignLeft, AlignBottom, "O");
  98. }
  99. furi_string_printf(ctx->buffer, "%d", ap.packetRxCount);
  100. canvas_draw_icon(canvas, 35, 39, &I_down);
  101. canvas_draw_str_aligned(
  102. canvas, 45, 47, AlignLeft, AlignBottom, furi_string_get_cstr(ctx->buffer));
  103. furi_string_printf(ctx->buffer, "%d", ap.packetTxCount);
  104. canvas_draw_icon(canvas, 85, 38, &I_up);
  105. canvas_draw_str_aligned(
  106. canvas, 95, 47, AlignLeft, AlignBottom, furi_string_get_cstr(ctx->buffer));
  107. furi_string_printf(
  108. ctx->buffer,
  109. "Seen: %d:%d:%d (%lds ago)",
  110. ap.datetime.hour,
  111. ap.datetime.minute,
  112. ap.datetime.second,
  113. furi_hal_rtc_get_timestamp() - furi_hal_rtc_datetime_to_timestamp(&ap.datetime));
  114. canvas_draw_str_aligned(
  115. canvas, 3, 59, AlignLeft, AlignBottom, furi_string_get_cstr(ctx->buffer));
  116. }
  117. static void render_callback(Canvas* canvas, void* context) {
  118. Context* ctx = context;
  119. canvas_draw_frame(canvas, 0, 0, 128, 64);
  120. canvas_set_font(canvas, FontPrimary);
  121. if(ctx->access_points_count >= MAX_ACCESS_POINTS) {
  122. canvas_draw_str(canvas, 118, 10, "!");
  123. }
  124. if(ctx->access_points_count == 0) {
  125. canvas_draw_str(canvas, 80, 30, "No AP's");
  126. canvas_draw_str(canvas, 80, 40, "Found!");
  127. canvas_draw_icon(canvas, 1, 4, &I_DolphinWait_61x59);
  128. } else {
  129. canvas_draw_frame(canvas, 0, 0, 35 + (ctx->access_points_count > 99 ? 5 : 0), 15);
  130. furi_string_printf(
  131. ctx->buffer, "%d/%d", ctx->access_points_index + 1, ctx->access_points_count);
  132. canvas_draw_str(canvas, 3, 12, furi_string_get_cstr(ctx->buffer));
  133. show_access_point(canvas, ctx);
  134. }
  135. // canvas_clear(canvas);
  136. furi_mutex_release(ctx->mutex);
  137. }
  138. // order ctx->access_points by ssid alphabetically
  139. static void sort_access_points(Context* ctx) {
  140. for(int i = 0; i < ctx->access_points_count; i++) {
  141. for(int j = i + 1; j < ctx->access_points_count; j++) {
  142. if(strcmp(ctx->access_points[i].ssid, ctx->access_points[j].ssid) > 0) {
  143. AccessPoint temp = ctx->access_points[i];
  144. ctx->access_points[i] = ctx->access_points[j];
  145. ctx->access_points[j] = temp;
  146. }
  147. }
  148. }
  149. }
  150. // set the index from the active access point
  151. static void set_index_from_access_points(Context* ctx) {
  152. for(int i = 0; i < ctx->access_points_count; i++) {
  153. if(ctx->access_points[i].bssid == ctx->active_access_point.bssid) {
  154. ctx->access_points_index = i;
  155. break;
  156. }
  157. }
  158. }
  159. static void removeSpaces(char* str) {
  160. // Remove spaces from the beginning of the string
  161. int i = 0;
  162. while(isspace((unsigned char)str[i])) {
  163. i++;
  164. }
  165. // Move the remaining characters to the beginning of the string
  166. int j = 0;
  167. while(str[i] != '\0') {
  168. str[j++] = str[i++];
  169. }
  170. str[j] = '\0';
  171. // Remove spaces from the end of the string
  172. int len = strlen(str);
  173. while(len > 0 && isspace((unsigned char)str[len - 1])) {
  174. str[--len] = '\0';
  175. }
  176. }
  177. static void parseLine(void* context, char* line) {
  178. Context* ctx = context;
  179. AccessPoint ap = {.ssid = malloc(MAX_SSID_LENGTH + 1), .bssid = malloc(MAX_BSSID_LENGTH + 1)};
  180. Packet pkt = {.recievedMac = malloc(18 + 1), .sentMac = malloc(18 + 1)};
  181. char* token = strtok(line, ",");
  182. int i = 0;
  183. bool isAp = false;
  184. bool isValid = true;
  185. UNUSED(isValid);
  186. while(token != NULL) {
  187. switch(i) {
  188. case 0:
  189. if(strcmp(token, "AR") == 0) {
  190. isAp = true;
  191. isValid = true;
  192. } else if(strcmp(token, "PK") == 0) {
  193. isAp = false;
  194. isValid = true;
  195. }
  196. break;
  197. case 1:
  198. if(isAp && isValid) {
  199. removeSpaces(token);
  200. strcpy(ap.ssid, token);
  201. } else if(!isAp && isValid) {
  202. strncpy(pkt.recievedMac, token, 18);
  203. pkt.recievedMac[18] = '\0';
  204. }
  205. break;
  206. case 2:
  207. if(isAp && isValid) {
  208. strcpy(ap.bssid, token);
  209. } else if(!isAp && isValid) {
  210. strncpy(pkt.sentMac, token, 18);
  211. pkt.sentMac[18] = '\0';
  212. }
  213. break;
  214. case 3:
  215. if(isAp && isValid) {
  216. ap.rssi = atoi(token);
  217. }
  218. break;
  219. case 4:
  220. if(isAp && isValid) {
  221. ap.channel = atoi(token);
  222. }
  223. break;
  224. }
  225. token = strtok(NULL, ",");
  226. i++;
  227. }
  228. if(isAp && isValid) {
  229. // free the packet
  230. free(pkt.recievedMac);
  231. free(pkt.sentMac);
  232. // check if values are valid
  233. // bssid needs an ":"
  234. // rssi needs to be negative
  235. // channel needs to be between 1 and 14
  236. // ssid needs to be at least 1 character long
  237. if(ap.bssid[2] != ':' || ap.bssid[5] != ':' || ap.bssid[8] != ':' || ap.bssid[11] != ':' ||
  238. ap.bssid[14] != ':' || ap.rssi > 0 || ap.channel < 1 || ap.channel > 14 ||
  239. strlen(ap.ssid) < 1) {
  240. free(ap.ssid);
  241. free(ap.bssid);
  242. return;
  243. }
  244. furi_hal_light_set(LightBlue, 0);
  245. furi_hal_light_set(LightGreen, 255);
  246. furi_hal_rtc_get_datetime(&ap.datetime);
  247. if(isnan(ctx->last_latitude) || isnan(ctx->last_longitude)) {
  248. ctx->last_latitude = 0;
  249. ctx->last_longitude = 0;
  250. } else {
  251. ap.latitude = ctx->last_latitude;
  252. ap.longitude = ctx->last_longitude;
  253. }
  254. // check if ap is already in the list otherwise add it but update the rssi
  255. bool found = false;
  256. for(size_t i = 0; i < ctx->access_points_count; i++) {
  257. if(strcmp(ctx->access_points[i].bssid, ap.bssid) == 0) {
  258. found = true;
  259. //update rssi channel datetime
  260. ctx->access_points[i].rssi = ap.rssi;
  261. ctx->access_points[i].channel = ap.channel;
  262. ctx->access_points[i].datetime = ap.datetime;
  263. ctx->access_points[i].latitude = ap.latitude;
  264. ctx->access_points[i].longitude = ap.longitude;
  265. if(strcmp(ctx->active_access_point.bssid, ap.bssid) == 0) {
  266. ctx->active_access_point.rssi = ap.rssi;
  267. ctx->active_access_point.channel = ap.channel;
  268. ctx->active_access_point.datetime = ap.datetime;
  269. ctx->active_access_point.latitude = ap.latitude;
  270. ctx->active_access_point.longitude = ap.longitude;
  271. }
  272. free(ap.ssid);
  273. free(ap.bssid);
  274. break;
  275. }
  276. }
  277. if(!found) {
  278. memcpy(&ctx->access_points[ctx->access_points_count], &ap, sizeof(AccessPoint));
  279. ctx->access_points_count++;
  280. }
  281. sort_access_points(ctx);
  282. set_index_from_access_points(ctx);
  283. } else {
  284. // it is a packet so screw the ap
  285. free(ap.ssid);
  286. free(ap.bssid);
  287. // check if values are valid
  288. // mac needs to be 6 characters long
  289. if(strlen(pkt.recievedMac) != 17 || strlen(pkt.sentMac) != 17 ||
  290. ctx->access_points_count == 0) {
  291. free(pkt.recievedMac);
  292. free(pkt.sentMac);
  293. return;
  294. }
  295. furi_hal_light_set(LightGreen, 0);
  296. furi_hal_light_set(LightBlue, 255);
  297. for(size_t i = 0; i < ctx->access_points_count; i++) {
  298. if(strcmp(ctx->access_points[i].bssid, pkt.recievedMac) == 0) {
  299. ctx->access_points[i].packetRxCount++;
  300. break;
  301. }
  302. }
  303. for(size_t i = 0; i < ctx->access_points_count; i++) {
  304. if(strcmp(ctx->access_points[i].bssid, pkt.sentMac) == 0) {
  305. ctx->access_points[i].packetTxCount++;
  306. break;
  307. }
  308. }
  309. free(pkt.recievedMac);
  310. free(pkt.sentMac);
  311. }
  312. }
  313. static void uart_cb_esp(UartIrqEvent ev, uint8_t data, void* context) {
  314. Context* ctx = (Context*)context;
  315. if(ev == UartIrqEventRXNE) {
  316. furi_stream_buffer_send(ctx->rx_stream_esp, &data, 1, 0);
  317. furi_thread_flags_set(furi_thread_get_id(ctx->thread_esp), WorkerEvtRxDone);
  318. }
  319. }
  320. static int32_t uart_worker_esp(void* context) {
  321. Context* ctx = (Context*)context;
  322. size_t rx_offset = 0;
  323. while(1) {
  324. uint32_t events =
  325. furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
  326. furi_check((events & FuriFlagError) == 0);
  327. if(events & WorkerEvtStop) {
  328. break;
  329. }
  330. if(events & WorkerEvtRxDone) {
  331. size_t len = 0;
  332. do {
  333. // receive serial bytes into rx_buf, starting at rx_offset from the start of the buffer
  334. // the maximum we can receive is RX_BUF_SIZE - 1 - rx_offset
  335. len = furi_stream_buffer_receive(
  336. ctx->rx_stream_esp,
  337. ctx->rx_buf_esp + rx_offset,
  338. RX_BUF_SIZE - 1 - rx_offset,
  339. 0);
  340. if(len > 0) {
  341. // increase rx_offset by the number of bytes received, and null-terminate rx_buf
  342. rx_offset += len;
  343. ctx->rx_buf_esp[rx_offset] = '\0';
  344. // look for strings ending in newlines, starting at the start of rx_buf
  345. char* line_current = (char*)ctx->rx_buf_esp;
  346. while(1) {
  347. // skip null characters
  348. while(*line_current == '\0' &&
  349. line_current < (char*)ctx->rx_buf_esp + rx_offset - 1) {
  350. line_current++;
  351. }
  352. // find the next newline
  353. char* newline = strchr(line_current, '\n');
  354. if(newline) // newline found
  355. {
  356. // put a null terminator in place of the newline, to delimit the line string
  357. *newline = '\0';
  358. parseLine(ctx, line_current);
  359. // move the cursor to the character after the newline
  360. line_current = newline + 1;
  361. } else // no more newlines found
  362. {
  363. if(line_current >
  364. (char*)ctx->rx_buf_esp) // at least one line was found
  365. {
  366. // clear parsed lines, and move any leftover bytes to the start of rx_buf
  367. rx_offset = 0;
  368. while(
  369. *line_current) // stop when the original rx_offset terminator is reached
  370. {
  371. ctx->rx_buf_esp[rx_offset++] = *(line_current++);
  372. }
  373. }
  374. break; // go back to receiving bytes from the serial stream
  375. }
  376. }
  377. }
  378. } while(len > 0);
  379. }
  380. }
  381. furi_hal_uart_set_irq_cb(UART_CH_ESP, NULL, NULL);
  382. furi_stream_buffer_free(ctx->rx_stream_esp);
  383. return 0;
  384. }
  385. static void gps_uart_parse_nmea(Context* ctx, char* line) {
  386. switch(minmea_sentence_id(line, false)) {
  387. case MINMEA_SENTENCE_RMC: {
  388. struct minmea_sentence_rmc frame;
  389. if(minmea_parse_rmc(&frame, line)) {
  390. ctx->last_latitude = minmea_tocoord(&frame.latitude);
  391. ctx->last_longitude = minmea_tocoord(&frame.longitude);
  392. }
  393. } break;
  394. case MINMEA_SENTENCE_GGA: {
  395. struct minmea_sentence_gga frame;
  396. if(minmea_parse_gga(&frame, line)) {
  397. ctx->last_latitude = minmea_tocoord(&frame.latitude);
  398. ctx->last_longitude = minmea_tocoord(&frame.longitude);
  399. }
  400. } break;
  401. case MINMEA_SENTENCE_GLL: {
  402. struct minmea_sentence_gll frame;
  403. if(minmea_parse_gll(&frame, line)) {
  404. ctx->last_latitude = minmea_tocoord(&frame.latitude);
  405. ctx->last_longitude = minmea_tocoord(&frame.longitude);
  406. }
  407. } break;
  408. default:
  409. break;
  410. }
  411. }
  412. static void uart_cb_gps(UartIrqEvent ev, uint8_t data, void* context) {
  413. Context* ctx = (Context*)context;
  414. if(ev == UartIrqEventRXNE) {
  415. furi_stream_buffer_send(ctx->rx_stream_gps, &data, 1, 0);
  416. furi_thread_flags_set(furi_thread_get_id(ctx->thread_gps), WorkerEvtRxDone);
  417. }
  418. }
  419. static int32_t uart_worker_gps(void* context) {
  420. Context* ctx = (Context*)context;
  421. size_t rx_offset = 0;
  422. while(1) {
  423. uint32_t events =
  424. furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
  425. furi_check((events & FuriFlagError) == 0);
  426. if(events & WorkerEvtStop) {
  427. break;
  428. }
  429. if(events & WorkerEvtRxDone) {
  430. size_t len = 0;
  431. do {
  432. // receive serial bytes into rx_buf, starting at rx_offset from the start of the buffer
  433. // the maximum we can receive is RX_BUF_SIZE - 1 - rx_offset
  434. len = furi_stream_buffer_receive(
  435. ctx->rx_stream_gps,
  436. ctx->rx_buf_gps + rx_offset,
  437. RX_BUF_SIZE - 1 - rx_offset,
  438. 0);
  439. if(len > 0) {
  440. // increase rx_offset by the number of bytes received, and null-terminate rx_buf
  441. rx_offset += len;
  442. ctx->rx_buf_gps[rx_offset] = '\0';
  443. // look for strings ending in newlines, starting at the start of rx_buf
  444. char* line_current = (char*)ctx->rx_buf_gps;
  445. while(1) {
  446. // skip null characters
  447. while(*line_current == '\0' &&
  448. line_current < (char*)ctx->rx_buf_gps + rx_offset - 1) {
  449. line_current++;
  450. }
  451. // find the next newline
  452. char* newline = strchr(line_current, '\n');
  453. if(newline) // newline found
  454. {
  455. // put a null terminator in place of the newline, to delimit the line string
  456. *newline = '\0';
  457. // FURI_LOG_I(appname, "Received line: %s", line_current);
  458. gps_uart_parse_nmea(ctx, line_current);
  459. // move the cursor to the character after the newline
  460. line_current = newline + 1;
  461. } else // no more newlines found
  462. {
  463. if(line_current >
  464. (char*)ctx->rx_buf_gps) // at least one line was found
  465. {
  466. // clear parsed lines, and move any leftover bytes to the start of rx_buf
  467. rx_offset = 0;
  468. while(
  469. *line_current) // stop when the original rx_offset terminator is reached
  470. {
  471. ctx->rx_buf_gps[rx_offset++] = *(line_current++);
  472. }
  473. }
  474. break; // go back to receiving bytes from the serial stream
  475. }
  476. }
  477. }
  478. } while(len > 0);
  479. }
  480. }
  481. furi_hal_uart_set_irq_cb(UART_CH_GPS, NULL, NULL);
  482. furi_stream_buffer_free(ctx->rx_stream_gps);
  483. return 0;
  484. }
  485. int32_t wifisniffer_app(void* p) {
  486. UNUSED(p);
  487. // if(UART_CH_ESP == UART_CH_GPS) {
  488. // FURI_LOG_I(appname, "ESP and GPS uart can't be the same");
  489. // return -1;
  490. // }
  491. // turn off 5v, so it gets reset on startup
  492. if(furi_hal_power_is_otg_enabled()) {
  493. furi_hal_power_disable_otg();
  494. }
  495. // Enable 5v on startup
  496. uint8_t attempts = 0;
  497. while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
  498. furi_hal_power_enable_otg();
  499. furi_delay_ms(10);
  500. }
  501. furi_delay_ms(200);
  502. // alloc everything
  503. Context* ctx = malloc(sizeof(Context));
  504. ctx->queue = furi_message_queue_alloc(8, sizeof(Event));
  505. ctx->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  506. ctx->buffer = furi_string_alloc();
  507. ctx->buffer2 = furi_string_alloc();
  508. ctx->notifications = furi_record_open(RECORD_NOTIFICATION);
  509. ctx->access_points_count = 0;
  510. ctx->access_points_index = 0;
  511. ctx->pressedButton = false;
  512. //esp uart
  513. ctx->rx_stream_esp = furi_stream_buffer_alloc(RX_BUF_SIZE * 5, 1);
  514. ctx->thread_esp = furi_thread_alloc();
  515. furi_thread_set_name(ctx->thread_esp, "LLwifiSnifferUartWorkerESP");
  516. furi_thread_set_stack_size(ctx->thread_esp, 2048);
  517. furi_thread_set_context(ctx->thread_esp, ctx);
  518. furi_thread_set_callback(ctx->thread_esp, uart_worker_esp);
  519. furi_thread_start(ctx->thread_esp);
  520. if(UART_CH_ESP == FuriHalUartIdUSART1) {
  521. furi_hal_console_disable();
  522. } else if(UART_CH_ESP == FuriHalUartIdLPUART1) {
  523. furi_hal_uart_init(UART_CH_ESP, 115200);
  524. }
  525. furi_hal_uart_set_br(UART_CH_ESP, 115200);
  526. furi_hal_uart_set_irq_cb(UART_CH_ESP, uart_cb_esp, ctx);
  527. furi_hal_uart_tx(UART_CH_ESP, (uint8_t*)"XFW#WIFISNIFF=1\r\n", strlen("XFW#WIFISNIFF=1\r\n"));
  528. //end esp uart
  529. //gps uart
  530. if(UART_CH_ESP != UART_CH_GPS) {
  531. ctx->rx_stream_gps = furi_stream_buffer_alloc(RX_BUF_SIZE * 5, 1);
  532. ctx->thread_gps = furi_thread_alloc();
  533. furi_thread_set_name(ctx->thread_gps, "LLwifiSnifferUartWorkerGPS");
  534. furi_thread_set_stack_size(ctx->thread_gps, 2048);
  535. furi_thread_set_context(ctx->thread_gps, ctx);
  536. furi_thread_set_callback(ctx->thread_gps, uart_worker_gps);
  537. furi_thread_start(ctx->thread_gps);
  538. if(UART_CH_GPS == FuriHalUartIdUSART1) {
  539. furi_hal_console_disable();
  540. } else if(UART_CH_GPS == FuriHalUartIdLPUART1) {
  541. furi_hal_uart_init(UART_CH_GPS, 9600);
  542. }
  543. furi_hal_uart_set_br(UART_CH_GPS, 9600);
  544. furi_hal_uart_set_irq_cb(UART_CH_GPS, uart_cb_gps, ctx);
  545. }
  546. //end gps uart
  547. ViewPort* view_port = view_port_alloc();
  548. view_port_draw_callback_set(view_port, render_callback, ctx);
  549. view_port_input_callback_set(view_port, input_callback, ctx->queue);
  550. Gui* gui = furi_record_open(RECORD_GUI);
  551. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  552. FuriTimer* timer = furi_timer_alloc(tick_callback, FuriTimerTypePeriodic, ctx->queue);
  553. furi_timer_start(timer, 100);
  554. // application loop
  555. Event event;
  556. bool processing = true;
  557. do {
  558. if(furi_message_queue_get(ctx->queue, &event, FuriWaitForever) == FuriStatusOk) {
  559. furi_mutex_acquire(ctx->mutex, FuriWaitForever);
  560. switch(event.type) {
  561. case EventTypeKey:
  562. // applicatie verlaten
  563. if(event.input.type == InputTypeShort && event.input.key == InputKeyBack) {
  564. processing = false;
  565. } else if(event.input.type == InputTypeLong && event.input.key == InputKeyBack) {
  566. processing = false;
  567. } else if(event.input.type == InputTypeLong && event.input.key == InputKeyOk) {
  568. // remove accespoint
  569. if(ctx->access_points_count > 0) {
  570. for(int i = ctx->access_points_index; i < ctx->access_points_count - 1;
  571. i++) {
  572. ctx->access_points[i] = ctx->access_points[i + 1];
  573. }
  574. ctx->access_points_count--;
  575. if(ctx->access_points_index >= ctx->access_points_count) {
  576. ctx->access_points_index = ctx->access_points_count - 1;
  577. }
  578. }
  579. } else if(event.input.type == InputTypePress && event.input.key == InputKeyDown) {
  580. ctx->access_points_index--;
  581. if(ctx->access_points_index < 0) {
  582. ctx->access_points_index = ctx->access_points_count - 1;
  583. }
  584. ctx->active_access_point = ctx->access_points[ctx->access_points_index];
  585. } else if(event.input.type == InputTypePress && event.input.key == InputKeyUp) {
  586. ctx->access_points_index++;
  587. if(ctx->access_points_index >= ctx->access_points_count) {
  588. ctx->access_points_index = 0;
  589. }
  590. ctx->active_access_point = ctx->access_points[ctx->access_points_index];
  591. } else if(event.input.type == InputTypePress && event.input.key == InputKeyLeft) {
  592. } else if(event.input.type == InputTypePress && event.input.key == InputKeyRight) {
  593. }
  594. ctx->pressedButton = true;
  595. break;
  596. case EventTypeTick:
  597. // fix for the empty active access point when there was no interaction
  598. if(!ctx->pressedButton) {
  599. ctx->access_points_index = 0;
  600. ctx->active_access_point = ctx->access_points[ctx->access_points_index];
  601. }
  602. break;
  603. default:
  604. break;
  605. }
  606. view_port_update(view_port);
  607. } else {
  608. processing = false;
  609. }
  610. } while(processing);
  611. // save the data to the file
  612. Storage* storage = furi_record_open(RECORD_STORAGE);
  613. FuriHalRtcDateTime datetime;
  614. furi_hal_rtc_get_datetime(&datetime);
  615. FuriString* filename = furi_string_alloc();
  616. furi_string_printf(
  617. filename,
  618. "%d_%d_%d_%d_%d_%d.txt",
  619. datetime.year,
  620. datetime.month,
  621. datetime.day,
  622. datetime.hour,
  623. datetime.minute,
  624. datetime.second);
  625. FuriString* path = furi_string_alloc();
  626. furi_string_printf(path, "/ext/apps_data/llsniffer/%s", furi_string_get_cstr(filename));
  627. // open file
  628. ctx->file = storage_file_alloc(storage);
  629. if(!storage_common_exists(storage, EXT_PATH("apps_data/llsniffer"))) {
  630. storage_common_mkdir(storage, EXT_PATH("apps_data/llsniffer"));
  631. }
  632. if(!storage_file_open(ctx->file, furi_string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_ALWAYS)) {
  633. FURI_LOG_E(appname, "Failed to open file");
  634. }
  635. for(int i = 0; i < ctx->access_points_count; i++) {
  636. AccessPoint ap = ctx->access_points[i];
  637. furi_string_printf(
  638. ctx->buffer2,
  639. "%s,%s,%s,%d,%d,%d,%d,%d,%d,%d,%d,%f,%f\r\n",
  640. "Accesspoint",
  641. ap.ssid,
  642. ap.bssid,
  643. ap.rssi,
  644. ap.channel,
  645. ap.datetime.year,
  646. ap.datetime.month,
  647. ap.datetime.day,
  648. ap.datetime.hour,
  649. ap.datetime.minute,
  650. ap.datetime.second,
  651. (double)ap.latitude,
  652. (double)ap.longitude);
  653. if(!storage_file_write(
  654. ctx->file,
  655. furi_string_get_cstr(ctx->buffer2),
  656. strlen(furi_string_get_cstr(ctx->buffer2)))) {
  657. FURI_LOG_E(appname, "Failed to write AP to file");
  658. }
  659. }
  660. // free everything
  661. furi_record_close(RECORD_NOTIFICATION);
  662. furi_timer_free(timer);
  663. view_port_enabled_set(view_port, false);
  664. gui_remove_view_port(gui, view_port);
  665. view_port_free(view_port);
  666. furi_record_close(RECORD_GUI);
  667. furi_message_queue_free(ctx->queue);
  668. furi_mutex_free(ctx->mutex);
  669. furi_thread_flags_set(furi_thread_get_id(ctx->thread_esp), WorkerEvtStop);
  670. furi_thread_join(ctx->thread_esp);
  671. furi_thread_free(ctx->thread_esp);
  672. if(UART_CH_ESP != UART_CH_GPS) {
  673. furi_thread_flags_set(furi_thread_get_id(ctx->thread_gps), WorkerEvtStop);
  674. furi_thread_join(ctx->thread_gps);
  675. furi_thread_free(ctx->thread_gps);
  676. }
  677. storage_file_close(ctx->file);
  678. storage_file_free(ctx->file);
  679. furi_record_close(RECORD_STORAGE);
  680. free(ctx);
  681. furi_hal_light_set(LightBlue, 0);
  682. furi_hal_light_set(LightGreen, 0);
  683. if(UART_CH_ESP == FuriHalUartIdLPUART1) {
  684. furi_hal_uart_deinit(UART_CH_ESP);
  685. } else if(UART_CH_ESP == FuriHalUartIdUSART1) {
  686. furi_hal_console_enable();
  687. }
  688. if(UART_CH_GPS == FuriHalUartIdLPUART1) {
  689. furi_hal_uart_deinit(UART_CH_GPS);
  690. } else if(UART_CH_GPS == FuriHalUartIdUSART1) {
  691. furi_hal_console_enable();
  692. }
  693. if(furi_hal_power_is_otg_enabled()) {
  694. furi_hal_power_disable_otg();
  695. }
  696. return 0;
  697. }