wii_ec.c 8.0 KB

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