flip_rob.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /*
  2. flip_rob - Flipper app to control a Nintendo R.O.B./Family Computer Robot.
  3. John Riney 2023
  4. */
  5. #include <furi.h>
  6. #include <gui/gui.h>
  7. #include <flip_rob_icons.h>
  8. /* Pin definitions for the IR LEDs and buttons */
  9. const GpioPin* const IR_PIN = &gpio_infrared_tx;
  10. const GpioPin* const BACK_PIN = &gpio_button_back;
  11. const GpioPin* const UP_PIN = &gpio_button_up;
  12. const GpioPin* const DOWN_PIN = &gpio_button_down;
  13. const GpioPin* const LEFT_PIN = &gpio_button_left;
  14. const GpioPin* const RIGHT_PIN = &gpio_button_right;
  15. const GpioPin* const OK_PIN = &gpio_button_ok;
  16. /*
  17. Timings and signals for IR pulses - derived from
  18. https://learn.adafruit.com/controlling-a-classic-nintendo-r-o-b-robot-using-circuit-playground-express/overview
  19. */
  20. const int32_t ON_US = 1500;
  21. const int32_t OFF_US = 15167;
  22. const int8_t COMMAND_LEN = 13;
  23. const int8_t BLINK_COMMAND[] = {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1};
  24. const int8_t LEFT_COMMAND[] = {0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0};
  25. const int8_t RIGHT_COMMAND[] = {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0};
  26. const int8_t UP_COMMAND[] = {0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1};
  27. const int8_t DOWN_COMMAND[] = {0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1};
  28. const int8_t CLOSE_COMMAND[] = {0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0};
  29. const int8_t OPEN_COMMAND[] = {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0};
  30. /* Draw a really minimal UI with instructions. */
  31. static void my_draw_callback(Canvas* canvas, void* context) {
  32. UNUSED(context);
  33. canvas_set_font(canvas, FontPrimary);
  34. canvas_draw_str(canvas, 60, 10, "Move R.O.B.");
  35. canvas_draw_str(canvas, 60, 20, "with arrows.");
  36. canvas_draw_str(canvas, 60, 30, "Toggle hands");
  37. canvas_draw_str(canvas, 60, 40, "with OK.");
  38. canvas_draw_str(canvas, 20, 64, "Hold Back to exit.");
  39. canvas_draw_icon(canvas, 0, 0, &I_rob_mono);
  40. canvas_set_font(canvas, FontSecondary);
  41. canvas_draw_str(canvas, 8, 36, "by riney");
  42. }
  43. /* Blink */
  44. void send_bit(int8_t b) {
  45. if(b == 0) {
  46. furi_hal_gpio_write(IR_PIN, false);
  47. }
  48. else {
  49. furi_hal_gpio_write(IR_PIN, true);
  50. }
  51. furi_delay_us(ON_US);
  52. furi_hal_gpio_write(IR_PIN, false);
  53. furi_delay_us(OFF_US);
  54. }
  55. /* Blinkblinkblinkblink */
  56. void send_command(const int8_t cmd[]) {
  57. for(int32_t i = 0; i < COMMAND_LEN; i++) {
  58. send_bit(cmd[i]);
  59. }
  60. }
  61. /* Entry point */
  62. int flip_rob_app(void* p) {
  63. UNUSED(p);
  64. /* Show directions to user. */
  65. Gui* gui = furi_record_open(RECORD_GUI);
  66. ViewPort* view_port = view_port_alloc();
  67. view_port_draw_callback_set(view_port, my_draw_callback, NULL);
  68. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  69. /* Initialize the LED pin as 3.3V output. */
  70. furi_hal_gpio_init_simple(IR_PIN, GpioModeOutputPushPull);
  71. int8_t hands_closed = 0;
  72. /* Main loop to read keys and send commands */
  73. do {
  74. if(!furi_hal_gpio_read(LEFT_PIN)) {
  75. /* L/R mirrored for ease of use */
  76. send_command(RIGHT_COMMAND);
  77. }
  78. else if(!furi_hal_gpio_read(RIGHT_PIN)) {
  79. send_command(LEFT_COMMAND);
  80. }
  81. else if(!furi_hal_gpio_read(UP_PIN)) {
  82. send_command(UP_COMMAND);
  83. }
  84. else if(!furi_hal_gpio_read(DOWN_PIN)) {
  85. send_command(DOWN_COMMAND);
  86. }
  87. else if(furi_hal_gpio_read(OK_PIN)) {
  88. /* OK isn't inverted for some reason? */
  89. if(hands_closed == 1) {
  90. hands_closed = 0;
  91. send_command(OPEN_COMMAND);
  92. }
  93. else {
  94. hands_closed = 1;
  95. send_command(CLOSE_COMMAND);
  96. }
  97. }
  98. furi_delay_ms(250);
  99. }
  100. while(furi_hal_gpio_read(BACK_PIN));
  101. /* Reset IR pin */
  102. furi_hal_gpio_init_simple(IR_PIN, GpioModeAnalog);
  103. /* Clean up GUI and bail */
  104. gui_remove_view_port(gui, view_port);
  105. return 0;
  106. }