i2ctools.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <gui/gui.h>
  4. #include <input/input.h>
  5. #define MAX_I2C_ADDR 0x7F
  6. #define APP_NAME "I2C Tools"
  7. #define SCAN_MENU_TEXT "Scan"
  8. #define SCAN_MENU_X 75
  9. #define SCAN_MENU_Y 6
  10. #define SNIFF_MENU_TEXT "Sniff"
  11. #define SNIFF_MENU_X 75
  12. #define SNIFF_MENU_Y 20
  13. #define SEND_MENU_TEXT "Send"
  14. #define SEND_MENU_X 75
  15. #define SEND_MENU_Y 34
  16. #define PLAY_MENU_TEXT "Play"
  17. #define PLAY_MENU_X 75
  18. #define PLAY_MENU_Y 48
  19. // Sniffer Pins
  20. #define pinSCL &gpio_ext_pc0
  21. #define pinSDA &gpio_ext_pc1
  22. // I2C BUS
  23. #define I2C_BUS &furi_hal_i2c_handle_external
  24. typedef enum {
  25. MAIN_VIEW,
  26. SCAN_VIEW,
  27. SNIFF_VIEW,
  28. SEND_VIEW,
  29. PLAY_VIEW,
  30. /* Know menu Size*/
  31. MENU_SIZE
  32. } i2cToolsMainMenu;
  33. // Bus Sniffer
  34. typedef enum { I2C_BUS_IDLE, I2C_BUS_STARTED } i2cBusStates;
  35. #define MAX_FRAMES 32
  36. typedef struct {
  37. uint8_t i2ctools[MAX_FRAMES];
  38. bool ack[MAX_FRAMES];
  39. uint8_t bit_index;
  40. uint8_t data_index;
  41. } i2cFrame;
  42. typedef struct {
  43. bool started;
  44. bool first;
  45. i2cBusStates state;
  46. i2cFrame frames[MAX_FRAMES];
  47. uint8_t frame_index;
  48. uint8_t menu_index;
  49. } _sniffer;
  50. // Bus scanner
  51. typedef struct {
  52. uint8_t addresses[MAX_I2C_ADDR + 1];
  53. uint8_t found;
  54. uint8_t menu_index;
  55. bool scanned;
  56. } _scanner;
  57. // Sender
  58. typedef struct {
  59. uint8_t address_idx;
  60. uint8_t value;
  61. uint8_t recv[2];
  62. bool must_send;
  63. bool sended;
  64. bool error;
  65. } _sender;
  66. typedef struct {
  67. ViewPort* view_port;
  68. i2cToolsMainMenu current_menu;
  69. uint8_t main_menu_index;
  70. _scanner scanner;
  71. _sniffer sniffer;
  72. _sender sender;
  73. } i2cTools;
  74. void scan_i2c_bus(i2cTools* i2ctools) {
  75. i2ctools->scanner.found = 0;
  76. i2ctools->scanner.scanned = true;
  77. furi_hal_i2c_acquire(I2C_BUS);
  78. // scan
  79. for(uint8_t addr = 0x01; addr < MAX_I2C_ADDR; addr++) {
  80. // Check for peripherals
  81. if(furi_hal_i2c_is_device_ready(I2C_BUS, addr, 2)) {
  82. // skip even 8-bit addr
  83. if(addr % 2 != 0) {
  84. continue;
  85. }
  86. // convert addr to 7-bits
  87. i2ctools->scanner.addresses[i2ctools->scanner.found] = addr >> 1;
  88. i2ctools->scanner.found++;
  89. }
  90. }
  91. furi_hal_i2c_release(I2C_BUS);
  92. }
  93. void i2ctools_draw_main_menu(Canvas* canvas, i2cTools* i2ctools) {
  94. canvas_clear(canvas);
  95. canvas_set_color(canvas, ColorBlack);
  96. canvas_draw_rframe(canvas, 0, 0, 128, 64, 3);
  97. canvas_draw_icon(canvas, 2, 13, &I_passport_bad3_46x49);
  98. canvas_set_font(canvas, FontPrimary);
  99. canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, APP_NAME);
  100. switch(i2ctools->main_menu_index) {
  101. case 0:
  102. canvas_set_color(canvas, ColorBlack);
  103. canvas_draw_str_aligned(
  104. canvas, SNIFF_MENU_X, SNIFF_MENU_Y, AlignLeft, AlignTop, SNIFF_MENU_TEXT);
  105. canvas_draw_str_aligned(
  106. canvas, SEND_MENU_X, SEND_MENU_Y, AlignLeft, AlignTop, SEND_MENU_TEXT);
  107. canvas_draw_str_aligned(
  108. canvas, PLAY_MENU_X, PLAY_MENU_Y, AlignLeft, AlignTop, PLAY_MENU_TEXT);
  109. canvas_draw_rbox(canvas, 60, SCAN_MENU_Y - 2, 60, 13, 3);
  110. canvas_set_color(canvas, ColorWhite);
  111. canvas_draw_str_aligned(
  112. canvas, SCAN_MENU_X, SCAN_MENU_Y, AlignLeft, AlignTop, SCAN_MENU_TEXT);
  113. break;
  114. case 1:
  115. canvas_set_color(canvas, ColorBlack);
  116. canvas_draw_str_aligned(
  117. canvas, SCAN_MENU_X, SCAN_MENU_Y, AlignLeft, AlignTop, SCAN_MENU_TEXT);
  118. canvas_draw_str_aligned(
  119. canvas, SEND_MENU_X, SEND_MENU_Y, AlignLeft, AlignTop, SEND_MENU_TEXT);
  120. canvas_draw_str_aligned(
  121. canvas, PLAY_MENU_X, PLAY_MENU_Y, AlignLeft, AlignTop, PLAY_MENU_TEXT);
  122. canvas_draw_rbox(canvas, 60, SNIFF_MENU_Y - 2, 60, 13, 3);
  123. canvas_set_color(canvas, ColorWhite);
  124. canvas_draw_str_aligned(
  125. canvas, SNIFF_MENU_X, SNIFF_MENU_Y, AlignLeft, AlignTop, SNIFF_MENU_TEXT);
  126. break;
  127. case 2:
  128. canvas_set_color(canvas, ColorBlack);
  129. canvas_draw_str_aligned(
  130. canvas, SCAN_MENU_X, SCAN_MENU_Y, AlignLeft, AlignTop, SCAN_MENU_TEXT);
  131. canvas_draw_str_aligned(
  132. canvas, SNIFF_MENU_X, SNIFF_MENU_Y, AlignLeft, AlignTop, SNIFF_MENU_TEXT);
  133. canvas_draw_str_aligned(
  134. canvas, PLAY_MENU_X, PLAY_MENU_Y, AlignLeft, AlignTop, PLAY_MENU_TEXT);
  135. canvas_draw_rbox(canvas, 60, SEND_MENU_Y - 2, 60, 13, 3);
  136. canvas_set_color(canvas, ColorWhite);
  137. canvas_draw_str_aligned(
  138. canvas, SEND_MENU_X, SEND_MENU_Y, AlignLeft, AlignTop, SEND_MENU_TEXT);
  139. break;
  140. case 3:
  141. canvas_set_color(canvas, ColorBlack);
  142. canvas_draw_str_aligned(
  143. canvas, SCAN_MENU_X, SCAN_MENU_Y, AlignLeft, AlignTop, SCAN_MENU_TEXT);
  144. canvas_draw_str_aligned(
  145. canvas, SNIFF_MENU_X, SNIFF_MENU_Y, AlignLeft, AlignTop, SNIFF_MENU_TEXT);
  146. canvas_draw_str_aligned(
  147. canvas, SEND_MENU_X, SEND_MENU_Y, AlignLeft, AlignTop, SEND_MENU_TEXT);
  148. canvas_draw_rbox(canvas, 60, PLAY_MENU_Y - 2, 60, 13, 3);
  149. canvas_set_color(canvas, ColorWhite);
  150. canvas_draw_str_aligned(
  151. canvas, PLAY_MENU_X, PLAY_MENU_Y, AlignLeft, AlignTop, PLAY_MENU_TEXT);
  152. break;
  153. default:
  154. break;
  155. }
  156. }
  157. void clearSnifferBuffers(void* ctx) {
  158. i2cTools* i2ctools = ctx;
  159. for(uint8_t i = 0; i < MAX_FRAMES; i++) {
  160. for(uint8_t j = 0; j < MAX_FRAMES; j++) {
  161. i2ctools->sniffer.frames[i].ack[j] = false;
  162. i2ctools->sniffer.frames[i].i2ctools[j] = 0;
  163. }
  164. i2ctools->sniffer.frames[i].bit_index = 0;
  165. i2ctools->sniffer.frames[i].data_index = 0;
  166. }
  167. i2ctools->sniffer.frame_index = 0;
  168. i2ctools->sniffer.state = I2C_BUS_IDLE;
  169. i2ctools->sniffer.first = true;
  170. }
  171. // Called on Fallin/Rising SDA
  172. // Used to monitor i2c bus state
  173. static void SDAcallback(void* ctx) {
  174. i2cTools* i2ctools = ctx;
  175. // SCL is low maybe cclock strecching
  176. if(furi_hal_gpio_read(pinSCL) == false) {
  177. return;
  178. }
  179. // Check for stop condition: SDA rising while SCL is High
  180. if(i2ctools->sniffer.state == I2C_BUS_STARTED) {
  181. if(furi_hal_gpio_read(pinSDA) == true) {
  182. i2ctools->sniffer.state = I2C_BUS_IDLE;
  183. view_port_update(i2ctools->view_port);
  184. }
  185. }
  186. // Check for start condition: SDA falling while SCL is high
  187. else if(furi_hal_gpio_read(pinSDA) == false) {
  188. i2ctools->sniffer.state = I2C_BUS_STARTED;
  189. if(i2ctools->sniffer.first) {
  190. i2ctools->sniffer.first = false;
  191. return;
  192. }
  193. i2ctools->sniffer.frame_index++;
  194. if(i2ctools->sniffer.frame_index >= MAX_FRAMES) {
  195. clearSnifferBuffers(ctx);
  196. }
  197. }
  198. return;
  199. }
  200. // Called on Rising SCL
  201. // Used to read bus datas
  202. static void SCLcallback(void* ctx) {
  203. i2cTools* i2ctools = ctx;
  204. if(i2ctools->sniffer.state == I2C_BUS_IDLE) {
  205. return;
  206. }
  207. uint8_t frame = i2ctools->sniffer.frame_index;
  208. uint8_t bit = i2ctools->sniffer.frames[frame].bit_index;
  209. uint8_t data_idx = i2ctools->sniffer.frames[frame].data_index;
  210. if(bit < 8) {
  211. i2ctools->sniffer.frames[frame].i2ctools[data_idx] <<= 1;
  212. i2ctools->sniffer.frames[frame].i2ctools[data_idx] |= (int)furi_hal_gpio_read(pinSDA);
  213. i2ctools->sniffer.frames[frame].bit_index++;
  214. } else {
  215. i2ctools->sniffer.frames[frame].ack[data_idx] = !furi_hal_gpio_read(pinSDA);
  216. i2ctools->sniffer.frames[frame].data_index++;
  217. i2ctools->sniffer.frames[frame].bit_index = 0;
  218. }
  219. }
  220. void start_interrupts(i2cTools* i2ctools) {
  221. furi_hal_gpio_init(pinSCL, GpioModeInterruptRise, GpioPullNo, GpioSpeedHigh);
  222. furi_hal_gpio_add_int_callback(pinSCL, SCLcallback, i2ctools);
  223. // Add Rise and Fall Interrupt on SDA pin
  224. furi_hal_gpio_init(pinSDA, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedHigh);
  225. furi_hal_gpio_add_int_callback(pinSDA, SDAcallback, i2ctools);
  226. }
  227. void stop_interrupts() {
  228. furi_hal_gpio_remove_int_callback(pinSCL);
  229. furi_hal_gpio_remove_int_callback(pinSDA);
  230. }
  231. void i2ctools_draw_sniff_view(Canvas* canvas, i2cTools* i2ctools) {
  232. canvas_clear(canvas);
  233. canvas_set_color(canvas, ColorBlack);
  234. canvas_draw_rframe(canvas, 0, 0, 128, 64, 3);
  235. canvas_draw_icon(canvas, 2, 13, &I_passport_happy2_46x49);
  236. canvas_set_font(canvas, FontPrimary);
  237. canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, SNIFF_MENU_TEXT);
  238. canvas_set_font(canvas, FontSecondary);
  239. // Button
  240. canvas_draw_rbox(canvas, 70, 48, 45, 13, 3);
  241. canvas_set_color(canvas, ColorWhite);
  242. canvas_draw_icon(canvas, 75, 50, &I_Ok_btn_9x9);
  243. if(!i2ctools->sniffer.started) {
  244. canvas_draw_str_aligned(canvas, 85, 51, AlignLeft, AlignTop, "Start");
  245. } else {
  246. canvas_draw_str_aligned(canvas, 85, 51, AlignLeft, AlignTop, "Stop");
  247. }
  248. canvas_set_color(canvas, ColorBlack);
  249. // Address text
  250. char addr_text[8];
  251. snprintf(
  252. addr_text,
  253. sizeof(addr_text),
  254. "0x%02x",
  255. (int)(i2ctools->sniffer.frames[i2ctools->sniffer.menu_index].i2ctools[0] >> 1));
  256. canvas_draw_str_aligned(canvas, 50, 3, AlignLeft, AlignTop, "Addr: ");
  257. canvas_draw_str_aligned(canvas, 75, 3, AlignLeft, AlignTop, addr_text);
  258. // R/W
  259. if((int)(i2ctools->sniffer.frames[i2ctools->sniffer.menu_index].i2ctools[0]) % 2 == 0) {
  260. canvas_draw_str_aligned(canvas, 105, 3, AlignLeft, AlignTop, "W");
  261. } else {
  262. canvas_draw_str_aligned(canvas, 105, 3, AlignLeft, AlignTop, "R");
  263. }
  264. // nbFrame text
  265. canvas_draw_str_aligned(canvas, 50, 13, AlignLeft, AlignTop, "Frames: ");
  266. snprintf(addr_text, sizeof(addr_text), "%d", (int)i2ctools->sniffer.menu_index + 1);
  267. canvas_draw_str_aligned(canvas, 90, 13, AlignLeft, AlignTop, addr_text);
  268. canvas_draw_str_aligned(canvas, 100, 13, AlignLeft, AlignTop, "/");
  269. snprintf(addr_text, sizeof(addr_text), "%d", (int)i2ctools->sniffer.frame_index + 1);
  270. canvas_draw_str_aligned(canvas, 110, 13, AlignLeft, AlignTop, addr_text);
  271. // Frames content
  272. uint8_t x_pos = 0;
  273. uint8_t y_pos = 23;
  274. for(uint8_t i = 1; i < i2ctools->sniffer.frames[i2ctools->sniffer.menu_index].data_index;
  275. i++) {
  276. snprintf(
  277. addr_text,
  278. sizeof(addr_text),
  279. "0x%02x",
  280. (int)i2ctools->sniffer.frames[i2ctools->sniffer.menu_index].i2ctools[i]);
  281. x_pos = 50 + (i - 1) * 35;
  282. canvas_draw_str_aligned(canvas, x_pos, y_pos, AlignLeft, AlignTop, addr_text);
  283. if(i2ctools->sniffer.frames[i2ctools->sniffer.menu_index].ack[i]) {
  284. canvas_draw_str_aligned(canvas, x_pos + 24, y_pos, AlignLeft, AlignTop, "A");
  285. } else {
  286. canvas_draw_str_aligned(canvas, x_pos + 24, y_pos, AlignLeft, AlignTop, "N");
  287. }
  288. }
  289. }
  290. void i2ctools_draw_record_view(Canvas* canvas, i2cTools* i2ctools) {
  291. UNUSED(i2ctools);
  292. canvas_clear(canvas);
  293. canvas_set_color(canvas, ColorBlack);
  294. canvas_draw_rframe(canvas, 0, 0, 128, 64, 3);
  295. canvas_draw_icon(canvas, 2, 13, &I_passport_happy2_46x49);
  296. canvas_set_font(canvas, FontPrimary);
  297. canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, PLAY_MENU_TEXT);
  298. }
  299. void i2ctools_draw_send_view(Canvas* canvas, i2cTools* i2ctools) {
  300. canvas_clear(canvas);
  301. canvas_set_color(canvas, ColorBlack);
  302. canvas_draw_rframe(canvas, 0, 0, 128, 64, 3);
  303. canvas_draw_icon(canvas, 2, 13, &I_passport_happy2_46x49);
  304. canvas_set_font(canvas, FontPrimary);
  305. canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, SEND_MENU_TEXT);
  306. if(!i2ctools->scanner.scanned) {
  307. scan_i2c_bus(i2ctools);
  308. }
  309. canvas_set_font(canvas, FontSecondary);
  310. if(i2ctools->scanner.found <= 0) {
  311. canvas_draw_str_aligned(canvas, 60, 5, AlignLeft, AlignTop, "No peripherals");
  312. canvas_draw_str_aligned(canvas, 60, 15, AlignLeft, AlignTop, "Found");
  313. return;
  314. }
  315. canvas_draw_rbox(canvas, 70, 48, 45, 13, 3);
  316. canvas_set_color(canvas, ColorWhite);
  317. canvas_draw_icon(canvas, 75, 50, &I_Ok_btn_9x9);
  318. canvas_draw_str_aligned(canvas, 85, 51, AlignLeft, AlignTop, "Send");
  319. canvas_set_color(canvas, ColorBlack);
  320. canvas_draw_str_aligned(canvas, 50, 5, AlignLeft, AlignTop, "Addr: ");
  321. canvas_draw_icon(canvas, 80, 5, &I_ButtonLeft_4x7);
  322. canvas_draw_icon(canvas, 115, 5, &I_ButtonRight_4x7);
  323. char addr_text[8];
  324. snprintf(
  325. addr_text,
  326. sizeof(addr_text),
  327. "0x%02x",
  328. (int)i2ctools->scanner.addresses[i2ctools->sender.address_idx]);
  329. canvas_draw_str_aligned(canvas, 90, 5, AlignLeft, AlignTop, addr_text);
  330. canvas_draw_str_aligned(canvas, 50, 15, AlignLeft, AlignTop, "Value: ");
  331. canvas_draw_icon(canvas, 80, 17, &I_ButtonUp_7x4);
  332. canvas_draw_icon(canvas, 115, 17, &I_ButtonDown_7x4);
  333. snprintf(addr_text, sizeof(addr_text), "0x%02x", (int)i2ctools->sender.value);
  334. canvas_draw_str_aligned(canvas, 90, 15, AlignLeft, AlignTop, addr_text);
  335. if(i2ctools->sender.must_send) {
  336. furi_hal_i2c_acquire(&furi_hal_i2c_handle_external);
  337. i2ctools->sender.error = furi_hal_i2c_trx(
  338. &furi_hal_i2c_handle_external,
  339. i2ctools->scanner.addresses[i2ctools->sender.address_idx] << 1,
  340. &i2ctools->sender.value,
  341. 1,
  342. i2ctools->sender.recv,
  343. sizeof(i2ctools->sender.recv),
  344. 3);
  345. furi_hal_i2c_release(&furi_hal_i2c_handle_external);
  346. i2ctools->sender.must_send = false;
  347. i2ctools->sender.sended = true;
  348. }
  349. canvas_draw_str_aligned(canvas, 50, 25, AlignLeft, AlignTop, "Result: ");
  350. if(i2ctools->sender.sended) {
  351. for(uint8_t i = 0; i < sizeof(i2ctools->sender.recv); i++) {
  352. snprintf(addr_text, sizeof(addr_text), "0x%02x", (int)i2ctools->sender.recv[i]);
  353. canvas_draw_str_aligned(canvas, 90, 25 + (i * 10), AlignLeft, AlignTop, addr_text);
  354. }
  355. }
  356. }
  357. void i2ctools_draw_scan_view(Canvas* canvas, i2cTools* i2ctools) {
  358. canvas_clear(canvas);
  359. canvas_set_color(canvas, ColorBlack);
  360. canvas_draw_rframe(canvas, 0, 0, 128, 64, 3);
  361. canvas_draw_icon(canvas, 2, 13, &I_passport_happy3_46x49);
  362. canvas_set_font(canvas, FontPrimary);
  363. canvas_draw_str_aligned(canvas, 3, 3, AlignLeft, AlignTop, SCAN_MENU_TEXT);
  364. char count_text[46];
  365. char count_text_fmt[] = "Found: %d";
  366. canvas_set_font(canvas, FontSecondary);
  367. snprintf(count_text, sizeof(count_text), count_text_fmt, (int)i2ctools->scanner.found);
  368. canvas_draw_str_aligned(canvas, 50, 3, AlignLeft, AlignTop, count_text);
  369. uint8_t x_pos = 0;
  370. uint8_t y_pos = 0;
  371. uint8_t idx_to_print = 0;
  372. for(uint8_t i = 0; i < (int)i2ctools->scanner.found; i++) {
  373. idx_to_print = i + i2ctools->scanner.menu_index * 3;
  374. if(idx_to_print >= MAX_I2C_ADDR) {
  375. break;
  376. }
  377. snprintf(
  378. count_text,
  379. sizeof(count_text),
  380. "0x%02x ",
  381. (int)i2ctools->scanner.addresses[idx_to_print]);
  382. if(i < 3) {
  383. x_pos = 50 + (i * 26);
  384. y_pos = 15;
  385. } else if(i < 6) {
  386. x_pos = 50 + ((i - 3) * 26);
  387. y_pos = 25;
  388. } else if(i < 9) {
  389. x_pos = 50 + ((i - 6) * 26);
  390. y_pos = 35;
  391. } else if(i < 12) {
  392. x_pos = 50 + ((i - 9) * 26);
  393. y_pos = 45;
  394. } else if(i < 15) {
  395. x_pos = 50 + ((i - 12) * 26);
  396. y_pos = 55;
  397. } else {
  398. break;
  399. }
  400. canvas_draw_str_aligned(canvas, x_pos, y_pos, AlignLeft, AlignTop, count_text);
  401. }
  402. // Right cursor
  403. y_pos = 14 + i2ctools->scanner.menu_index;
  404. canvas_draw_rbox(canvas, 125, y_pos, 3, 10, 1);
  405. // Button
  406. canvas_draw_rbox(canvas, 70, 48, 45, 13, 3);
  407. canvas_set_color(canvas, ColorWhite);
  408. canvas_draw_icon(canvas, 75, 50, &I_Ok_btn_9x9);
  409. canvas_draw_str_aligned(canvas, 85, 51, AlignLeft, AlignTop, "Scan");
  410. }
  411. void i2ctools_draw_callback(Canvas* canvas, void* ctx) {
  412. i2cTools* i2c_addr = acquire_mutex((ValueMutex*)ctx, 25);
  413. switch(i2c_addr->current_menu) {
  414. case MAIN_VIEW:
  415. i2ctools_draw_main_menu(canvas, i2c_addr);
  416. break;
  417. case SCAN_VIEW:
  418. i2ctools_draw_scan_view(canvas, i2c_addr);
  419. break;
  420. case SNIFF_VIEW:
  421. i2ctools_draw_sniff_view(canvas, i2c_addr);
  422. break;
  423. case SEND_VIEW:
  424. i2ctools_draw_send_view(canvas, i2c_addr);
  425. break;
  426. case PLAY_VIEW:
  427. i2ctools_draw_record_view(canvas, i2c_addr);
  428. break;
  429. default:
  430. break;
  431. }
  432. release_mutex((ValueMutex*)ctx, i2c_addr);
  433. }
  434. void i2ctools_input_callback(InputEvent* input_event, void* ctx) {
  435. furi_assert(ctx);
  436. FuriMessageQueue* event_queue = ctx;
  437. furi_message_queue_put(event_queue, input_event, FuriWaitForever);
  438. }
  439. int32_t i2ctools_app(void* p) {
  440. UNUSED(p);
  441. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
  442. i2cTools* i2ctools = malloc(sizeof(i2cTools));
  443. ValueMutex i2ctools_mutex;
  444. if(!init_mutex(&i2ctools_mutex, i2ctools, sizeof(i2cTools))) {
  445. FURI_LOG_E(APP_NAME, "cannot create mutex\r\n");
  446. free(i2ctools);
  447. return -1;
  448. }
  449. printf(APP_NAME);
  450. printf("\r\n");
  451. i2ctools->view_port = view_port_alloc();
  452. view_port_draw_callback_set(i2ctools->view_port, i2ctools_draw_callback, &i2ctools_mutex);
  453. view_port_input_callback_set(i2ctools->view_port, i2ctools_input_callback, event_queue);
  454. // Register view port in GUI
  455. Gui* gui = furi_record_open(RECORD_GUI);
  456. gui_add_view_port(gui, i2ctools->view_port, GuiLayerFullscreen);
  457. InputEvent event;
  458. clearSnifferBuffers(i2ctools);
  459. i2ctools->sniffer.started = false;
  460. i2ctools->sniffer.menu_index = 0;
  461. i2ctools->scanner.menu_index = 0;
  462. i2ctools->scanner.scanned = false;
  463. i2ctools->sender.must_send = false;
  464. i2ctools->sender.sended = false;
  465. while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) {
  466. if(event.key == InputKeyBack && event.type == InputTypeRelease) {
  467. if(i2ctools->current_menu == MAIN_VIEW) {
  468. break;
  469. } else {
  470. if(i2ctools->current_menu == SNIFF_VIEW) {
  471. stop_interrupts();
  472. i2ctools->sniffer.started = false;
  473. i2ctools->sniffer.state = I2C_BUS_IDLE;
  474. }
  475. i2ctools->current_menu = MAIN_VIEW;
  476. }
  477. } else if(event.key == InputKeyUp && event.type == InputTypeRelease) {
  478. if(i2ctools->current_menu == MAIN_VIEW) {
  479. if(i2ctools->main_menu_index > 0) {
  480. i2ctools->main_menu_index--;
  481. }
  482. } else if(i2ctools->current_menu == SCAN_VIEW) {
  483. if(i2ctools->scanner.menu_index > 0) {
  484. i2ctools->scanner.menu_index--;
  485. }
  486. } else if(i2ctools->current_menu == SEND_VIEW) {
  487. if(i2ctools->sender.value < 0xFF) {
  488. i2ctools->sender.value++;
  489. i2ctools->sender.sended = false;
  490. }
  491. }
  492. } else if(
  493. event.key == InputKeyUp &&
  494. (event.type == InputTypeLong || event.type == InputTypeRepeat)) {
  495. if(i2ctools->current_menu == SEND_VIEW) {
  496. if(i2ctools->sender.value < 0xF9) {
  497. i2ctools->sender.value += 5;
  498. i2ctools->sender.sended = false;
  499. }
  500. }
  501. } else if(event.key == InputKeyDown && event.type == InputTypeRelease) {
  502. if(i2ctools->current_menu == MAIN_VIEW) {
  503. if(i2ctools->main_menu_index < 3) {
  504. i2ctools->main_menu_index++;
  505. }
  506. } else if(i2ctools->current_menu == SCAN_VIEW) {
  507. if(i2ctools->scanner.menu_index < ((int)i2ctools->scanner.found / 3)) {
  508. i2ctools->scanner.menu_index++;
  509. }
  510. } else if(i2ctools->current_menu == SEND_VIEW) {
  511. if(i2ctools->sender.value > 0x00) {
  512. i2ctools->sender.value--;
  513. i2ctools->sender.sended = false;
  514. }
  515. }
  516. } else if(event.key == InputKeyDown && event.type == InputTypeLong) {
  517. if(i2ctools->current_menu == SEND_VIEW) {
  518. if(i2ctools->sender.value > 0x05) {
  519. i2ctools->sender.value -= 5;
  520. i2ctools->sender.sended = false;
  521. }
  522. }
  523. } else if(event.key == InputKeyOk && event.type == InputTypeRelease) {
  524. if(i2ctools->current_menu == MAIN_VIEW) {
  525. if(i2ctools->main_menu_index == 0) {
  526. scan_i2c_bus(i2ctools);
  527. i2ctools->current_menu = SCAN_VIEW;
  528. } else if(i2ctools->main_menu_index == 1) {
  529. i2ctools->current_menu = SNIFF_VIEW;
  530. } else if(i2ctools->main_menu_index == 2) {
  531. i2ctools->current_menu = SEND_VIEW;
  532. } else if(i2ctools->main_menu_index == 3) {
  533. i2ctools->current_menu = PLAY_VIEW;
  534. }
  535. } else if(i2ctools->current_menu == SCAN_VIEW) {
  536. scan_i2c_bus(i2ctools);
  537. } else if(i2ctools->current_menu == SEND_VIEW) {
  538. i2ctools->sender.must_send = true;
  539. } else if(i2ctools->current_menu == SNIFF_VIEW) {
  540. if(i2ctools->sniffer.started) {
  541. stop_interrupts();
  542. i2ctools->sniffer.started = false;
  543. i2ctools->sniffer.state = I2C_BUS_IDLE;
  544. } else {
  545. start_interrupts(i2ctools);
  546. i2ctools->sniffer.started = true;
  547. i2ctools->sniffer.state = I2C_BUS_IDLE;
  548. }
  549. }
  550. } else if(event.key == InputKeyRight && event.type == InputTypeRelease) {
  551. if(i2ctools->current_menu == SEND_VIEW) {
  552. if(i2ctools->sender.address_idx < (i2ctools->scanner.found - 1)) {
  553. i2ctools->sender.address_idx++;
  554. i2ctools->sender.sended = false;
  555. }
  556. } else if(i2ctools->current_menu == SNIFF_VIEW) {
  557. if(i2ctools->sniffer.menu_index < i2ctools->sniffer.frame_index) {
  558. i2ctools->sniffer.menu_index++;
  559. }
  560. }
  561. } else if(event.key == InputKeyLeft && event.type == InputTypeRelease) {
  562. if(i2ctools->current_menu == SEND_VIEW) {
  563. if(i2ctools->sender.address_idx > 0) {
  564. i2ctools->sender.address_idx--;
  565. i2ctools->sender.sended = false;
  566. }
  567. } else if(i2ctools->current_menu == SNIFF_VIEW) {
  568. if(i2ctools->sniffer.menu_index > 0) {
  569. i2ctools->sniffer.menu_index--;
  570. }
  571. }
  572. }
  573. view_port_update(i2ctools->view_port);
  574. }
  575. gui_remove_view_port(gui, i2ctools->view_port);
  576. view_port_free(i2ctools->view_port);
  577. furi_message_queue_free(event_queue);
  578. free(i2ctools);
  579. furi_record_close(RECORD_GUI);
  580. return 0;
  581. }