wii_ec.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #include <stdint.h>
  2. #include <furi.h> // Core API
  3. #include "wii_anal.h"
  4. #include "wii_i2c.h"
  5. #include "wii_ec.h"
  6. #include "bc_logging.h"
  7. #include "gfx/images.h" // Images
  8. #include "wii_anal_lcd.h" // Drawing functions
  9. #include "wii_anal_keys.h" // key mappings
  10. //----------------------------------------------------------------------------- ----------------------------------------
  11. // List of known perhipherals
  12. //
  13. // More perhipheral ID codes here: https://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way
  14. //
  15. const ecId_t ecId[PID_CNT] = {
  16. [PID_UNKNOWN ] = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, "Unknown Perhipheral", SCENE_DUMP,
  17. NULL, NULL, NULL, NULL, ec_show, ec_key},
  18. // If you're wise, ONLY edit this bit
  19. [PID_NUNCHUCK ] = { {0x00, 0x00, 0xA4, 0x20, 0x00, 0x00}, "Nunchuck", SCENE_NUNCHUCK,
  20. NULL, nunchuck_decode, nunchuck_msg, nunchuck_calib, nunchuck_show, nunchuck_key },
  21. [PID_CLASSIC ] = { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x01}, "Classic Controller", SCENE_CLASSIC,
  22. NULL, classic_decode, classic_msg, classic_calib, classic_show, classic_key },
  23. [PID_BALANCE ] = { {0x00, 0x00, 0xA4, 0x20, 0x04, 0x02}, "Balance Board", SCENE_DUMP,
  24. NULL, NULL, NULL, NULL, NULL, NULL },
  25. [PID_GH_GUITAR ] = { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x03}, "Guitar Hero Guitar", SCENE_DUMP,
  26. NULL, NULL, NULL, NULL, NULL, NULL },
  27. [PID_GH_DRUMS ] = { {0x01, 0x00, 0xA4, 0x20, 0x01, 0x03}, "Guitar Hero World Tour Drums", SCENE_DUMP,
  28. NULL, NULL, NULL, NULL, NULL, NULL },
  29. [PID_TURNTABLE ] = { {0x03, 0x00, 0xA4, 0x20, 0x01, 0x03}, "DJ Hero Turntable", SCENE_DUMP,
  30. NULL, NULL, NULL, NULL, NULL, NULL },
  31. [PID_TAIKO_DRUMS] = { {0x00, 0x00, 0xA4, 0x20, 0x01, 0x11}, "Taiko Drum Controller)", SCENE_DUMP,
  32. NULL, NULL, NULL, NULL, NULL, NULL }, // Taiko no Tatsujin TaTaCon (Drum controller)
  33. [PID_UDRAW ] = { {0xFF, 0x00, 0xA4, 0x20, 0x00, 0x13}, "uDraw Tablet", SCENE_DUMP,
  34. udraw_init, NULL, NULL, NULL, NULL, NULL }, //! same as drawsome?
  35. // -----
  36. [PID_ERROR ] = { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, "Read Error", SCENE_NONE,
  37. NULL, NULL, NULL, NULL, NULL, NULL },
  38. [PID_NULL ] = { {0}, NULL, SCENE_NONE, NULL, NULL, NULL, NULL, NULL, NULL } // last entry
  39. };
  40. //+============================================================================ ========================================
  41. void ecDecode (wiiEC_t* pec)
  42. {
  43. if (ecId[pec->pidx].decode) ecId[pec->pidx].decode(pec) ;
  44. }
  45. //+============================================================================ ========================================
  46. void ecCalibrate (wiiEC_t* const pec, ecCalib_t c)
  47. {
  48. if (ecId[pec->pidx].calib) ecId[pec->pidx].calib(pec, c) ;
  49. }
  50. //+============================================================================ ========================================
  51. void ecPoll (wiiEC_t* const pec, FuriMessageQueue* const queue)
  52. {
  53. ENTER;
  54. furi_assert(queue);
  55. if (!pec->init) {
  56. // Attempt to initialise
  57. if (ecInit(pec, NULL)) { //! need a way to auto-start with encryption enabled
  58. eventMsg_t msg = {
  59. .id = EVID_WIIEC,
  60. .wiiEc = {
  61. .type = WIIEC_CONN,
  62. .in = '<',
  63. .val = pec->pidx
  64. }
  65. };
  66. furi_message_queue_put(queue, &msg, 0);
  67. }
  68. } else {
  69. // Attempt to read
  70. switch (ecRead(pec)) {
  71. case 2: { // device gone
  72. eventMsg_t msg = {
  73. .id = EVID_WIIEC,
  74. .wiiEc = {
  75. .type = WIIEC_DISCONN,
  76. .in = '>',
  77. .val = pec->pidx
  78. }
  79. };
  80. furi_message_queue_put(queue, &msg, 0);
  81. break;
  82. }
  83. case 0: { // read OK
  84. void (*fn)(wiiEC_t*, FuriMessageQueue*) = ecId[pec->pidx].check;
  85. if (fn) fn(pec, queue);
  86. break;
  87. }
  88. case 3: // read fail
  89. // this is probably temporary just ignore it
  90. break;
  91. default: // bug: unknown
  92. case 1: // bug: not initialised - should never happen
  93. ERROR("%s : read bug", __func__);
  94. break;
  95. }
  96. }
  97. LEAVE;
  98. return;
  99. }
  100. //+============================================================================ ========================================
  101. // This is the screen drawn for an unknown controller
  102. // It is also available by pressing LEFT (at least once) on a "known controller" screen
  103. //
  104. void ec_show (Canvas* const canvas, state_t* const state)
  105. {
  106. wiiEC_t* pec = &state->ec;
  107. int h = 11; // line height
  108. int x = 1; // (initial) offset for bits
  109. int y = -h; // previous y value
  110. int yb = 0; // y for bit patterns
  111. int c2 = 17; // column 2
  112. // Headings
  113. canvas_set_font(canvas, FontSecondary);
  114. canvas_set_color(canvas, ColorBlack);
  115. canvas_draw_str_aligned(canvas, 0 ,0, AlignLeft, AlignTop, "SID:");
  116. canvas_draw_str_aligned(canvas, c2,0, AlignLeft, AlignTop, pec->sid);
  117. canvas_draw_str_aligned(canvas, 0 ,11, AlignLeft, AlignTop, "PID:");
  118. canvas_draw_str_aligned(canvas, 0 ,22, AlignLeft, AlignTop, "Cal:");
  119. // PID
  120. x = c2;
  121. for (int i = 0; i < 6; i++) {
  122. show(canvas, x,11, img_5x7[pec->pid[i]>>4], SHOW_SET_BLK);
  123. x += 5+1;
  124. show(canvas, x,11, img_5x7[pec->pid[i]&0xF], SHOW_SET_BLK);
  125. x += 5+1+2;
  126. }
  127. // Calibrations data
  128. y = 11;
  129. for (int j = 0; j <= 8; j += 8) {
  130. x = c2;
  131. y += 11;
  132. for (int i = 0; i < 8; i++) {
  133. show(canvas, x,y, img_5x7[pec->calF[i+j]>>4], SHOW_SET_BLK);
  134. x += 5+1;
  135. show(canvas, x,y, img_5x7[pec->calF[i+j]&0xF], SHOW_SET_BLK);
  136. x += 5+1+2;
  137. }
  138. }
  139. // Reading
  140. x = 1;
  141. y++;
  142. yb = (y+=h) +h +2;
  143. canvas_draw_line(canvas, x,y-1, x,yb+4);
  144. x += 2;
  145. for (int i = 0; i < JOY_LEN; i++) {
  146. show(canvas, x+ 1,y, img_6x8[pec->joy[i]>>4], SHOW_SET_BLK);
  147. show(canvas, x+11,y, img_6x8[pec->joy[i]&0xF], SHOW_SET_BLK);
  148. // bits
  149. for (int m = 0x80; m; m >>= 1) {
  150. x += 2 * !!(m & 0x08) ; // nybble step
  151. canvas_draw_box(canvas, x,yb +(2*!(pec->joy[i] & m)), 2,2) ;
  152. x += 2; // bit step
  153. }
  154. // byte step
  155. x += 1;
  156. canvas_draw_line(canvas, x,y-1, x,yb+4);
  157. x += 2;
  158. }
  159. // Scene navigation
  160. if (state->scenePrev != SCENE_WAIT)
  161. show(canvas, 120,0, &img_key_R, SHOW_SET_BLK);
  162. }
  163. //+============================================================================ ========================================
  164. // The DUMP screen is
  165. //
  166. bool ec_key (const eventMsg_t* const msg, state_t* const state)
  167. {
  168. int used = false; // assume key is NOT-handled
  169. if (state->scenePrev != SCENE_WAIT) {
  170. //# <L [ SHORT-RIGHT ]
  171. if ((msg->input.type == InputTypeShort) && (msg->input.key == InputKeyRight)) {
  172. sceneSet(state, state->scenePrev);
  173. used = true;
  174. }
  175. }
  176. return used;
  177. }