i2ctools.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <gui/gui.h>
  4. #include <input/input.h>
  5. #include <notification/notification.h>
  6. #include <notification/notification_messages.h>
  7. #include <stdbool.h> // Header-file for boolean data-type.
  8. #define MAX_I2C_ADDR 0x7F
  9. #define APP_NAME "I2C Tools"
  10. #define SCAN_MENU_TEXT "Scan"
  11. #define SCAN_MENU_X 75
  12. #define SCAN_MENU_Y 6
  13. #define SNIFF_MENU_TEXT "Sniff"
  14. #define SNIFF_MENU_X 75
  15. #define SNIFF_MENU_Y 20
  16. #define SEND_MENU_TEXT "Send"
  17. #define SEND_MENU_X 75
  18. #define SEND_MENU_Y 34
  19. #define RECORD_MENU_TEXT "Record"
  20. #define RECORD_MENU_X 70
  21. #define RECORD_MENU_Y 48
  22. // Sniffer Pins
  23. #define pinSCL &gpio_ext_pc0
  24. #define pinSDA &gpio_ext_pc1
  25. typedef enum {
  26. MAIN_VIEW,
  27. SCAN_VIEW,
  28. SNIFF_VIEW,
  29. SEND_VIEW,
  30. RECORD_VIEW,
  31. /* Know menu Size*/
  32. MENU_SIZE
  33. } i2cToolsMainMenu;
  34. typedef enum { I2C_IDLE, I2C_START, I2C_PAUSE, I2C_STOP } i2cStates;
  35. #define MAX_FRAMES 32
  36. typedef struct {
  37. i2cStates state;
  38. uint8_t address;
  39. bool pending;
  40. bool rw; // true = read
  41. bool ack; // true = ACK, false = NACK
  42. uint8_t data[MAX_FRAMES];
  43. uint8_t bit_count;
  44. uint8_t frame_count;
  45. uint32_t lastSCLtime;
  46. uint32_t period;
  47. } sniffStruct;
  48. typedef struct {
  49. ViewPort* view_port;
  50. uint8_t available_addr[MAX_I2C_ADDR + 1];
  51. uint8_t nb_available;
  52. bool scanned;
  53. i2cToolsMainMenu current_menu;
  54. uint8_t main_menu_index;
  55. uint8_t scan_view_index;
  56. uint8_t send_view_addr_index;
  57. uint8_t send_view_to_send;
  58. bool send_view_must_send;
  59. uint8_t send_last_recv[2];
  60. bool send_get_return;
  61. bool send_started;
  62. bool sniff_started;
  63. sniffStruct sniff;
  64. } i2cToolsData;
  65. NotificationApp* notifications;
  66. void get_available_i2c(i2cToolsData* data) {
  67. data->nb_available = 0;
  68. furi_hal_i2c_acquire(&furi_hal_i2c_handle_external);
  69. for(uint8_t addr = 0x01; addr < MAX_I2C_ADDR; addr++) {
  70. if(addr % 2 != 0) {
  71. continue;
  72. }
  73. bool ret = furi_hal_i2c_is_device_ready(&furi_hal_i2c_handle_external, addr, 2);
  74. if(ret) {
  75. data->available_addr[data->nb_available] = (addr >> 1);
  76. data->nb_available++;
  77. }
  78. }
  79. furi_hal_i2c_release(&furi_hal_i2c_handle_external);
  80. data->scanned = true;
  81. }
  82. void i2ctools_draw_main_menu(Canvas* canvas, i2cToolsData* data) {
  83. canvas_clear(canvas);
  84. canvas_set_color(canvas, ColorBlack);
  85. canvas_draw_rframe(canvas, 0, 0, 128, 64, 3);
  86. canvas_draw_icon(canvas, 2, 13, &I_passport_bad3_46x49);
  87. canvas_set_font(canvas, FontPrimary);
  88. canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, APP_NAME);
  89. switch(data->main_menu_index) {
  90. case 0:
  91. canvas_set_color(canvas, ColorBlack);
  92. canvas_draw_str_aligned(
  93. canvas, SNIFF_MENU_X, SNIFF_MENU_Y, AlignLeft, AlignTop, SNIFF_MENU_TEXT);
  94. canvas_draw_str_aligned(
  95. canvas, SEND_MENU_X, SEND_MENU_Y, AlignLeft, AlignTop, SEND_MENU_TEXT);
  96. canvas_draw_str_aligned(
  97. canvas, RECORD_MENU_X, RECORD_MENU_Y, AlignLeft, AlignTop, RECORD_MENU_TEXT);
  98. canvas_draw_rbox(canvas, 60, SCAN_MENU_Y - 2, 60, 13, 3);
  99. canvas_set_color(canvas, ColorWhite);
  100. canvas_draw_str_aligned(
  101. canvas, SCAN_MENU_X, SCAN_MENU_Y, AlignLeft, AlignTop, SCAN_MENU_TEXT);
  102. break;
  103. case 1:
  104. canvas_set_color(canvas, ColorBlack);
  105. canvas_draw_str_aligned(
  106. canvas, SCAN_MENU_X, SCAN_MENU_Y, AlignLeft, AlignTop, SCAN_MENU_TEXT);
  107. canvas_draw_str_aligned(
  108. canvas, SEND_MENU_X, SEND_MENU_Y, AlignLeft, AlignTop, SEND_MENU_TEXT);
  109. canvas_draw_str_aligned(
  110. canvas, RECORD_MENU_X, RECORD_MENU_Y, AlignLeft, AlignTop, RECORD_MENU_TEXT);
  111. canvas_draw_rbox(canvas, 60, SNIFF_MENU_Y - 2, 60, 13, 3);
  112. canvas_set_color(canvas, ColorWhite);
  113. canvas_draw_str_aligned(
  114. canvas, SNIFF_MENU_X, SNIFF_MENU_Y, AlignLeft, AlignTop, SNIFF_MENU_TEXT);
  115. break;
  116. case 2:
  117. canvas_set_color(canvas, ColorBlack);
  118. canvas_draw_str_aligned(
  119. canvas, SCAN_MENU_X, SCAN_MENU_Y, AlignLeft, AlignTop, SCAN_MENU_TEXT);
  120. canvas_draw_str_aligned(
  121. canvas, SNIFF_MENU_X, SNIFF_MENU_Y, AlignLeft, AlignTop, SNIFF_MENU_TEXT);
  122. canvas_draw_str_aligned(
  123. canvas, RECORD_MENU_X, RECORD_MENU_Y, AlignLeft, AlignTop, RECORD_MENU_TEXT);
  124. canvas_draw_rbox(canvas, 60, SEND_MENU_Y - 2, 60, 13, 3);
  125. canvas_set_color(canvas, ColorWhite);
  126. canvas_draw_str_aligned(
  127. canvas, SEND_MENU_X, SEND_MENU_Y, AlignLeft, AlignTop, SEND_MENU_TEXT);
  128. break;
  129. case 3:
  130. canvas_set_color(canvas, ColorBlack);
  131. canvas_draw_str_aligned(
  132. canvas, SCAN_MENU_X, SCAN_MENU_Y, AlignLeft, AlignTop, SCAN_MENU_TEXT);
  133. canvas_draw_str_aligned(
  134. canvas, SNIFF_MENU_X, SNIFF_MENU_Y, AlignLeft, AlignTop, SNIFF_MENU_TEXT);
  135. canvas_draw_str_aligned(
  136. canvas, SEND_MENU_X, SEND_MENU_Y, AlignLeft, AlignTop, SEND_MENU_TEXT);
  137. canvas_draw_rbox(canvas, 60, RECORD_MENU_Y - 2, 60, 13, 3);
  138. canvas_set_color(canvas, ColorWhite);
  139. canvas_draw_str_aligned(
  140. canvas, RECORD_MENU_X, RECORD_MENU_Y, AlignLeft, AlignTop, RECORD_MENU_TEXT);
  141. break;
  142. default:
  143. break;
  144. }
  145. }
  146. static void input_isr_SDA(void* ctx) {
  147. i2cToolsData* data = ctx;
  148. switch(data->sniff.state) {
  149. case I2C_STOP:
  150. if(!furi_hal_gpio_read(pinSDA) && furi_hal_gpio_read(pinSCL)) {
  151. data->sniff.state = I2C_START;
  152. data->sniff.address = 0;
  153. data->sniff.frame_count = 0;
  154. data->sniff.bit_count = 0;
  155. data->sniff.pending = false;
  156. }
  157. break;
  158. case I2C_START:
  159. if(furi_hal_gpio_read(pinSDA) && furi_hal_gpio_read(pinSCL)) {
  160. data->sniff.state = I2C_STOP;
  161. }
  162. break;
  163. default:
  164. break;
  165. }
  166. view_port_update(data->view_port);
  167. }
  168. static void input_isr_SCL(void* ctx) {
  169. i2cToolsData* data = ctx;
  170. switch(data->sniff.state) {
  171. case I2C_START:
  172. data->sniff.period = furi_get_tick() - data->sniff.lastSCLtime;
  173. if(!data->sniff.pending && data->sniff.address == 0 && data->sniff.bit_count <= 6) {
  174. data->sniff.data[0] += furi_hal_gpio_read(pinSDA) * pow(2, data->sniff.bit_count);
  175. } else if(!data->sniff.pending && data->sniff.address != 0 && data->sniff.bit_count <= 7) {
  176. data->sniff.data[data->sniff.frame_count] +=
  177. furi_hal_gpio_read(pinSDA) * pow(2, data->sniff.bit_count);
  178. }
  179. if(data->sniff.bit_count == 6 && data->sniff.address == 0) {
  180. data->sniff.address = (data->sniff.data[0] << 1);
  181. data->sniff.pending = true;
  182. } else if(data->sniff.pending && data->sniff.bit_count == 7) {
  183. data->sniff.rw = !furi_hal_gpio_read(pinSDA);
  184. } else if(data->sniff.pending && data->sniff.bit_count == 8) {
  185. data->sniff.ack = !furi_hal_gpio_read(pinSDA);
  186. data->sniff.pending = false;
  187. data->sniff.bit_count = 0;
  188. } else if(!data->sniff.pending && data->sniff.bit_count == 7) {
  189. data->sniff.pending = true;
  190. data->sniff.frame_count++;
  191. }
  192. data->sniff.bit_count++;
  193. break;
  194. default:
  195. break;
  196. }
  197. data->sniff.lastSCLtime = furi_get_tick();
  198. view_port_update(data->view_port);
  199. }
  200. void i2ctools_draw_sniff_view(Canvas* canvas, i2cToolsData* data) {
  201. if(!data->sniff_started) {
  202. // Add Rise Interrupt on SCL pin
  203. furi_hal_gpio_init(pinSCL, GpioModeInterruptRise, GpioPullNo, GpioSpeedVeryHigh);
  204. furi_hal_gpio_add_int_callback(pinSCL, input_isr_SCL, data);
  205. // Add Rise and Fall Interrupt on SDA pin
  206. furi_hal_gpio_init(pinSDA, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedVeryHigh);
  207. furi_hal_gpio_add_int_callback(pinSDA, input_isr_SDA, data);
  208. data->sniff_started = true;
  209. }
  210. canvas_clear(canvas);
  211. canvas_set_color(canvas, ColorBlack);
  212. canvas_draw_rframe(canvas, 0, 0, 128, 64, 3);
  213. canvas_draw_icon(canvas, 2, 13, &I_passport_happy2_46x49);
  214. canvas_set_font(canvas, FontPrimary);
  215. canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, SNIFF_MENU_TEXT);
  216. canvas_set_font(canvas, FontSecondary);
  217. char addr_text[8];
  218. snprintf(addr_text, sizeof(addr_text), "%#4x", (int)data->sniff.address);
  219. canvas_draw_str_aligned(canvas, 50, 3, AlignLeft, AlignTop, addr_text);
  220. if(data->sniff.rw) {
  221. canvas_draw_str_aligned(canvas, 75, 3, AlignLeft, AlignTop, "W");
  222. } else {
  223. canvas_draw_str_aligned(canvas, 75, 3, AlignLeft, AlignTop, "R");
  224. }
  225. if(data->sniff.ack) {
  226. canvas_draw_str_aligned(canvas, 83, 3, AlignLeft, AlignTop, "A");
  227. } else {
  228. canvas_draw_str_aligned(canvas, 83, 3, AlignLeft, AlignTop, "N");
  229. }
  230. for(uint8_t i = 0; i < data->sniff.frame_count; i++) {
  231. snprintf(addr_text, sizeof(addr_text), "%#4x", (int)data->sniff.data[i]);
  232. canvas_draw_str_aligned(canvas, 50 + i * 25, 43, AlignLeft, AlignTop, addr_text);
  233. }
  234. switch(data->sniff.state) {
  235. case I2C_IDLE:
  236. canvas_draw_str_aligned(canvas, 50, 33, AlignLeft, AlignTop, "IDLE");
  237. break;
  238. case I2C_START:
  239. canvas_draw_str_aligned(canvas, 50, 33, AlignLeft, AlignTop, "START");
  240. break;
  241. case I2C_STOP:
  242. canvas_draw_str_aligned(canvas, 50, 33, AlignLeft, AlignTop, "STOP");
  243. break;
  244. default:
  245. break;
  246. }
  247. canvas_draw_str_aligned(canvas, 50, 53, AlignLeft, AlignTop, "size: ");
  248. snprintf(addr_text, sizeof(addr_text), "%d", (int)data->sniff.frame_count);
  249. canvas_draw_str_aligned(canvas, 70, 53, AlignLeft, AlignTop, addr_text);
  250. canvas_draw_str_aligned(canvas, 80, 53, AlignLeft, AlignTop, "period: ");
  251. snprintf(addr_text, sizeof(addr_text), "%d", (int)data->sniff.lastSCLtime);
  252. canvas_draw_str_aligned(canvas, 110, 53, AlignLeft, AlignTop, addr_text);
  253. }
  254. void i2ctools_draw_record_view(Canvas* canvas, i2cToolsData* data) {
  255. UNUSED(data);
  256. canvas_clear(canvas);
  257. canvas_set_color(canvas, ColorBlack);
  258. canvas_draw_rframe(canvas, 0, 0, 128, 64, 3);
  259. canvas_draw_icon(canvas, 2, 13, &I_passport_happy2_46x49);
  260. canvas_set_font(canvas, FontPrimary);
  261. canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, RECORD_MENU_TEXT);
  262. }
  263. void i2ctools_draw_send_view(Canvas* canvas, i2cToolsData* data) {
  264. if(!data->scanned) {
  265. get_available_i2c(data);
  266. }
  267. canvas_clear(canvas);
  268. canvas_set_color(canvas, ColorBlack);
  269. canvas_draw_rframe(canvas, 0, 0, 128, 64, 3);
  270. canvas_draw_icon(canvas, 2, 13, &I_passport_happy2_46x49);
  271. canvas_set_font(canvas, FontPrimary);
  272. canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, SEND_MENU_TEXT);
  273. canvas_set_font(canvas, FontSecondary);
  274. if(data->nb_available <= 0) {
  275. canvas_draw_str_aligned(canvas, 60, 5, AlignLeft, AlignTop, "No peripherals");
  276. canvas_draw_str_aligned(canvas, 60, 15, AlignLeft, AlignTop, "Found");
  277. return;
  278. }
  279. canvas_draw_rbox(canvas, 70, 48, 45, 13, 3);
  280. canvas_set_color(canvas, ColorWhite);
  281. canvas_draw_icon(canvas, 75, 50, &I_Ok_btn_9x9);
  282. canvas_draw_str_aligned(canvas, 85, 51, AlignLeft, AlignTop, "Send");
  283. canvas_set_color(canvas, ColorBlack);
  284. canvas_draw_str_aligned(canvas, 50, 5, AlignLeft, AlignTop, "Addr: ");
  285. canvas_draw_icon(canvas, 80, 5, &I_ButtonLeft_4x7);
  286. canvas_draw_icon(canvas, 115, 5, &I_ButtonRight_4x7);
  287. char addr_text[8];
  288. snprintf(
  289. addr_text,
  290. sizeof(addr_text),
  291. "%#04x",
  292. (int)data->available_addr[data->send_view_addr_index]);
  293. canvas_draw_str_aligned(canvas, 90, 5, AlignLeft, AlignTop, addr_text);
  294. canvas_draw_str_aligned(canvas, 50, 15, AlignLeft, AlignTop, "Value: ");
  295. canvas_draw_icon(canvas, 80, 17, &I_ButtonUp_7x4);
  296. canvas_draw_icon(canvas, 115, 17, &I_ButtonDown_7x4);
  297. snprintf(addr_text, sizeof(addr_text), "%#04x", (int)data->send_view_to_send);
  298. canvas_draw_str_aligned(canvas, 90, 15, AlignLeft, AlignTop, addr_text);
  299. if(data->send_view_must_send) {
  300. furi_hal_i2c_acquire(&furi_hal_i2c_handle_external);
  301. data->send_get_return = furi_hal_i2c_trx(
  302. &furi_hal_i2c_handle_external,
  303. data->available_addr[data->send_view_addr_index] << 1,
  304. &data->send_view_to_send,
  305. 1,
  306. data->send_last_recv,
  307. sizeof(data->send_last_recv),
  308. 3);
  309. furi_hal_i2c_release(&furi_hal_i2c_handle_external);
  310. data->send_view_must_send = false;
  311. data->send_started = true;
  312. }
  313. canvas_draw_str_aligned(canvas, 50, 25, AlignLeft, AlignTop, "Result: ");
  314. if(data->send_started) {
  315. if(data->send_get_return) {
  316. for(uint8_t i = 0; i < sizeof(data->send_last_recv); i++) {
  317. snprintf(addr_text, sizeof(addr_text), "%#04x", (int)data->send_last_recv[i]);
  318. canvas_draw_str_aligned(canvas, 90, 25 + (i * 10), AlignLeft, AlignTop, addr_text);
  319. }
  320. } else {
  321. canvas_draw_str_aligned(canvas, 90, 25, AlignLeft, AlignTop, "Error");
  322. }
  323. }
  324. }
  325. void i2ctools_draw_scan_view(Canvas* canvas, i2cToolsData* data) {
  326. canvas_clear(canvas);
  327. canvas_set_color(canvas, ColorBlack);
  328. canvas_draw_rframe(canvas, 0, 0, 128, 64, 3);
  329. canvas_draw_icon(canvas, 2, 13, &I_passport_happy3_46x49);
  330. canvas_set_font(canvas, FontPrimary);
  331. canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, SCAN_MENU_TEXT);
  332. char count_text[46];
  333. char count_text_fmt[] = "Found: %d";
  334. canvas_set_font(canvas, FontSecondary);
  335. snprintf(count_text, sizeof(count_text), count_text_fmt, (int)data->nb_available);
  336. canvas_draw_str_aligned(canvas, 50, 3, AlignLeft, AlignTop, count_text);
  337. uint8_t x_pos = 0;
  338. uint8_t y_pos = 0;
  339. uint8_t idx_to_print = 0;
  340. for(uint8_t i = 0; i < (int)data->nb_available; i++) {
  341. idx_to_print = i + data->scan_view_index * 3;
  342. if(idx_to_print >= MAX_I2C_ADDR) {
  343. break;
  344. }
  345. snprintf(
  346. count_text, sizeof(count_text), "%#04x ", (int)data->available_addr[idx_to_print]);
  347. if(i < 3) {
  348. x_pos = 50 + (i * 26);
  349. y_pos = 15;
  350. } else if(i < 6) {
  351. x_pos = 50 + ((i - 3) * 26);
  352. y_pos = 25;
  353. } else if(i < 9) {
  354. x_pos = 50 + ((i - 6) * 26);
  355. y_pos = 35;
  356. } else if(i < 12) {
  357. x_pos = 50 + ((i - 9) * 26);
  358. y_pos = 45;
  359. } else if(i < 15) {
  360. x_pos = 50 + ((i - 12) * 26);
  361. y_pos = 55;
  362. } else {
  363. break;
  364. }
  365. canvas_draw_str_aligned(canvas, x_pos, y_pos, AlignLeft, AlignTop, count_text);
  366. }
  367. // Right cursor
  368. y_pos = 14 + data->scan_view_index;
  369. canvas_draw_rbox(canvas, 125, y_pos, 3, 10, 1);
  370. }
  371. void i2ctools_draw_callback(Canvas* canvas, void* ctx) {
  372. i2cToolsData* i2c_addr = acquire_mutex((ValueMutex*)ctx, 25);
  373. switch(i2c_addr->current_menu) {
  374. case MAIN_VIEW:
  375. i2ctools_draw_main_menu(canvas, i2c_addr);
  376. break;
  377. case SCAN_VIEW:
  378. i2ctools_draw_scan_view(canvas, i2c_addr);
  379. break;
  380. case SNIFF_VIEW:
  381. i2ctools_draw_sniff_view(canvas, i2c_addr);
  382. break;
  383. case SEND_VIEW:
  384. i2ctools_draw_send_view(canvas, i2c_addr);
  385. break;
  386. case RECORD_VIEW:
  387. i2ctools_draw_record_view(canvas, i2c_addr);
  388. break;
  389. default:
  390. break;
  391. }
  392. release_mutex((ValueMutex*)ctx, i2c_addr);
  393. }
  394. void i2ctools_input_callback(InputEvent* input_event, void* ctx) {
  395. furi_assert(ctx);
  396. FuriMessageQueue* event_queue = ctx;
  397. furi_message_queue_put(event_queue, input_event, FuriWaitForever);
  398. }
  399. int32_t i2ctools_app(void* p) {
  400. UNUSED(p);
  401. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
  402. i2cToolsData* i2caddrs = malloc(sizeof(i2cToolsData));
  403. ValueMutex i2caddrs_mutex;
  404. if(!init_mutex(&i2caddrs_mutex, i2caddrs, sizeof(i2cToolsData))) {
  405. FURI_LOG_E(APP_NAME, "cannot create mutex\r\n");
  406. free(i2caddrs);
  407. return -1;
  408. }
  409. notifications = furi_record_open(RECORD_NOTIFICATION);
  410. i2caddrs->view_port = view_port_alloc();
  411. view_port_draw_callback_set(i2caddrs->view_port, i2ctools_draw_callback, &i2caddrs_mutex);
  412. view_port_input_callback_set(i2caddrs->view_port, i2ctools_input_callback, event_queue);
  413. // Register view port in GUI
  414. Gui* gui = furi_record_open(RECORD_GUI);
  415. gui_add_view_port(gui, i2caddrs->view_port, GuiLayerFullscreen);
  416. InputEvent event;
  417. i2caddrs->scanned = false;
  418. i2caddrs->send_view_addr_index = 0;
  419. i2caddrs->send_view_to_send = 0x01;
  420. i2caddrs->send_view_must_send = false;
  421. i2caddrs->send_started = false;
  422. i2caddrs->sniff_started = false;
  423. i2caddrs->sniff.state = I2C_STOP;
  424. while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) {
  425. if(event.key == InputKeyBack && event.type == InputTypeRelease) {
  426. if(i2caddrs->current_menu == MAIN_VIEW) {
  427. break;
  428. } else {
  429. if(i2caddrs->current_menu == SNIFF_VIEW) {
  430. furi_hal_gpio_remove_int_callback(pinSCL);
  431. furi_hal_gpio_remove_int_callback(pinSDA);
  432. i2caddrs->sniff_started = false;
  433. i2caddrs->sniff.state = I2C_STOP;
  434. }
  435. i2caddrs->current_menu = MAIN_VIEW;
  436. }
  437. } else if(event.key == InputKeyUp && event.type == InputTypeRelease) {
  438. if(i2caddrs->current_menu == MAIN_VIEW) {
  439. if(i2caddrs->main_menu_index > 0) {
  440. i2caddrs->main_menu_index--;
  441. }
  442. } else if(i2caddrs->current_menu == SCAN_VIEW) {
  443. if(i2caddrs->scan_view_index > 0) {
  444. i2caddrs->scan_view_index--;
  445. }
  446. } else if(i2caddrs->current_menu == SEND_VIEW) {
  447. if(i2caddrs->send_view_to_send < 0xFF) {
  448. i2caddrs->send_view_to_send++;
  449. i2caddrs->send_started = false;
  450. }
  451. }
  452. } else if(
  453. event.key == InputKeyUp &&
  454. (event.type == InputTypeLong || event.type == InputTypeRepeat)) {
  455. if(i2caddrs->current_menu == SEND_VIEW) {
  456. if(i2caddrs->send_view_to_send < 0xF9) {
  457. i2caddrs->send_view_to_send += 5;
  458. i2caddrs->send_started = false;
  459. }
  460. }
  461. } else if(event.key == InputKeyDown && event.type == InputTypeRelease) {
  462. if(i2caddrs->current_menu == MAIN_VIEW) {
  463. if(i2caddrs->main_menu_index < 3) {
  464. i2caddrs->main_menu_index++;
  465. }
  466. } else if(i2caddrs->current_menu == SCAN_VIEW) {
  467. if(i2caddrs->scan_view_index < ((int)i2caddrs->nb_available / 3)) {
  468. i2caddrs->scan_view_index++;
  469. }
  470. } else if(i2caddrs->current_menu == SEND_VIEW) {
  471. if(i2caddrs->send_view_to_send > 0x00) {
  472. i2caddrs->send_view_to_send--;
  473. i2caddrs->send_started = false;
  474. }
  475. }
  476. } else if(event.key == InputKeyDown && event.type == InputTypeLong) {
  477. if(i2caddrs->current_menu == SEND_VIEW) {
  478. if(i2caddrs->send_view_to_send > 0x05) {
  479. i2caddrs->send_view_to_send -= 5;
  480. i2caddrs->send_started = false;
  481. }
  482. }
  483. } else if(event.key == InputKeyOk && event.type == InputTypeRelease) {
  484. if(i2caddrs->current_menu == MAIN_VIEW) {
  485. if(i2caddrs->main_menu_index == 0) {
  486. get_available_i2c(i2caddrs);
  487. i2caddrs->current_menu = SCAN_VIEW;
  488. } else if(i2caddrs->main_menu_index == 1) {
  489. i2caddrs->current_menu = SNIFF_VIEW;
  490. } else if(i2caddrs->main_menu_index == 2) {
  491. i2caddrs->current_menu = SEND_VIEW;
  492. } else if(i2caddrs->main_menu_index == 3) {
  493. i2caddrs->current_menu = RECORD_VIEW;
  494. }
  495. } else if(i2caddrs->current_menu == SCAN_VIEW) {
  496. get_available_i2c(i2caddrs);
  497. } else if(i2caddrs->current_menu == SEND_VIEW) {
  498. i2caddrs->send_view_must_send = true;
  499. }
  500. } else if(event.key == InputKeyRight && event.type == InputTypeRelease) {
  501. if(i2caddrs->current_menu == SEND_VIEW) {
  502. if(i2caddrs->send_view_addr_index < (i2caddrs->nb_available - 1)) {
  503. i2caddrs->send_view_addr_index++;
  504. i2caddrs->send_started = false;
  505. }
  506. }
  507. } else if(event.key == InputKeyLeft && event.type == InputTypeRelease) {
  508. if(i2caddrs->current_menu == SEND_VIEW) {
  509. if(i2caddrs->send_view_addr_index > 0) {
  510. i2caddrs->send_view_addr_index--;
  511. i2caddrs->send_started = false;
  512. }
  513. }
  514. }
  515. view_port_update(i2caddrs->view_port);
  516. }
  517. gui_remove_view_port(gui, i2caddrs->view_port);
  518. view_port_free(i2caddrs->view_port);
  519. furi_message_queue_free(event_queue);
  520. free(i2caddrs);
  521. furi_record_close(RECORD_NOTIFICATION);
  522. furi_record_close(RECORD_GUI);
  523. return 0;
  524. }