wii_ec.c 7.0 KB

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