trade.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. /*
  2. * This setup always forces the flipper to the follower/slave role in the link.
  3. * This just makes our logic consistent and since we're going to be gobs faster
  4. * than a real Game Boy, we can be guaranteed to always be ready to respond.
  5. *
  6. * As documented here: http://www.adanscotney.com/2014/01/spoofing-pokemon-trades-with-stellaris.html
  7. * The general gist of the communication is as follows:
  8. * 1) Each Game Boy tries to listen for an external clock coming in on the link cable.
  9. * After some unknown timeout, this Game Boy decides its going to take the leader/master role.
  10. * In this state, it generates a clock and repeatedly sends out PKMN_MASTER(0x01)
  11. * 2) The other side, sensing a clock from the leader/master, then responds with PKMN_SLAVE(0x02)
  12. * 3) Once both sides understand their roles, they both respond with PKMN_BLANK(0x00) for a bit.
  13. * 4) Next, the leader/master sends CONNECTED(0x60) bytes that the follower/slave repeats
  14. * back. Then a bunch of BLANK bytes.
  15. * 5) At this point, each Game Boy repeatedly sends the menu item it has highlighted,
  16. * prepended by a BLANK, in groups of 3 bytes. These are ITEM_*_HIGHLIGHTED.
  17. * 6) Then, once both sides send ITEM_*_SELECTED, the next step occurs.
  18. * This application, from steps 3 through 6, just repeats bytes back and lets the Game Boy
  19. * dictate the steps. We stay here until we start seeing PREAMBLE(0xFD) bytes,
  20. * as those dictate the start of the next sections.
  21. *
  22. * The Flipper is now in the "READY" state.
  23. *
  24. * 7) Once the player on the Game Boy side uses the trade table, a block of data is
  25. * transmitted. This starts with 10x PREAMBLE(0xFD) bytes, 10x random bytes (to
  26. * sync the RNG between two devices, unused at this time), and then the 415 trade_block,
  27. * struct gets transferred. At the end of this is 3 ending bytes, DF FE 15. And, weirdly,
  28. * 3 PREAMBLE(0xFD) bytes.
  29. * 8) The patch list starts with 3x more PREAMBLE(0xFD) bytes for a total of 6x PREAMBLE,
  30. * followed by 7x BLANK bytes. Then remaining 189 bytes of patch list data. The patch
  31. * list is used to compensate for byte values of NO_DATA_BYE(0xFE) being transmitted.
  32. * The patch list is specifically for the party data of the trade_block. To patch
  33. * outgoing data, if a byte is 0xFE, it is changed to 0xFF, and the index+1 is
  34. * added to the patch list. There are two parts to the patch list as the data it
  35. * covers is longer than 0xFC. After each part is complete, 0xFF is added to the
  36. * patch list. The first part of the patch list can patch 0x00:0xFB of the party,
  37. * the second part can patch 0xFC:0x107 of the party. If there are no bytes to
  38. * patch in a part, 0xFF is just appended. After both terminators, it is expected
  39. * all remaining bytes are 0x00.
  40. *
  41. * The Flipper is now in the "WAITING" state.
  42. *
  43. * 9) At this point, both sides have full copies of each other's current party. The sides
  44. * simply indicate which Pokemon they are sending. This is done with a BLANK byte to
  45. * start, and then each side indicates which Pokemon it wants to trade with SEL_NUM_MASK(0x60)
  46. * + party index. We always transmit the first Pokemon. Once in a agreement, both
  47. * sides transmit a handful of BLANK bytes.
  48. *
  49. * The Flipper is now in the "DEAL?" state.
  50. *
  51. * A) Starting with another BLANK byte, both sides need to agree to the trade by
  52. * sending TRADE_ACCEPT(0x62) repeatedly, and then a handful of BLANK bytes.
  53. * To disagree with a trade, either side would send TRADE_REJECT(0x61), the
  54. * Flipper will never send this on its own. If the Game Boy does, both it and
  55. * the flipper got back to step 9 again.
  56. *
  57. * The Flipper is now in the "TRADING" state.
  58. *
  59. * B) The Flipper actually goes back to step 7, but keeps the drawing mode as
  60. * TRADING. After the trade is complete on the Game Boy, it re-sends the
  61. * trade_block data. This re-syncs the states between the Flipper and
  62. * Game Boy and another trade can occur.
  63. *
  64. * *) A point of note is that the Flipper can go back to the main menu from
  65. * any state. Though, doing so in the TRADING state might actually cause
  66. * the Game Boy to have issues. When in READY or WAITING state, the Flipper
  67. * can go back and modify the Pokemon that the Game Boy sent to it. If the
  68. * Flipper then goes back to Trade from the main menu, it will be in the
  69. * READY state. If the Game Boy is still on the trade menu, and it tries
  70. * to trade, the trade will be rejected. The Game Boy needs to exit the
  71. * trade menu, and then re-enter it by selecting the table in the trade
  72. * center. This will then push the Flipper to the WAITING state, and the
  73. * trade_blocks will re-sync between them with the new data. If the Game Boy
  74. * leave the trade menu while the Flipper is in the WAITING state, the
  75. * Flipper will go back to the READY state.
  76. *
  77. * TODO: Set up requiring a long back press to go back to the main menu
  78. * from the TRADING state or from the main menu to exit the application.
  79. */
  80. #include <furi.h>
  81. #include <furi_hal.h>
  82. #include <gui/view.h>
  83. #include <pokemon_icons.h>
  84. #include <gblink.h>
  85. #include "../pokemon_app.h"
  86. #include "trade_patch_list.h"
  87. #define DELAY_MICROSECONDS 15
  88. #define PKMN_BLANK 0x00
  89. #define ITEM_1_HIGHLIGHTED 0xD0
  90. #define ITEM_2_HIGHLIGHTED 0xD1
  91. #define ITEM_3_HIGHLIGHTED 0xD2
  92. #define ITEM_1_SELECTED 0xD4
  93. #define ITEM_2_SELECTED 0xD5
  94. #define ITEM_3_SELECTED 0xD6
  95. #define SERIAL_PREAMBLE_BYTE 0xFD
  96. #define SERIAL_PREAMBLE_LENGTH 6
  97. #define SERIAL_RN_PREAMBLE_LENGTH 7
  98. #define SERIAL_TRADE_PREAMBLE_LENGTH 9
  99. #define SERIAL_RNS_LENGTH 10
  100. #define SERIAL_PATCH_LIST_PART_TERMINATOR 0xFF
  101. #define SERIAL_NO_DATA_BYTE 0xFE
  102. #define PKMN_MASTER 0x01
  103. #define PKMN_SLAVE 0x02
  104. #define PKMN_CONNECTED 0x60
  105. #define PKMN_TRADE_ACCEPT 0x62
  106. #define PKMN_TRADE_REJECT 0x61
  107. #define PKMN_TABLE_LEAVE 0x6f
  108. #define PKMN_SEL_NUM_MASK 0x60
  109. #define PKMN_SEL_NUM_ONE 0x60
  110. #define PKMN_ACTION 0x60
  111. #define PKMN_TRADE_CENTRE ITEM_1_SELECTED
  112. #define PKMN_COLOSSEUM ITEM_2_SELECTED
  113. #define PKMN_BREAK_LINK ITEM_3_SELECTED
  114. /* States specific to the trade process. */
  115. typedef enum {
  116. TRADE_RESET,
  117. TRADE_INIT,
  118. TRADE_RANDOM,
  119. TRADE_DATA,
  120. TRADE_PATCH_HEADER,
  121. TRADE_PATCH_DATA,
  122. TRADE_SELECT,
  123. TRADE_PENDING,
  124. TRADE_CONFIRMATION,
  125. TRADE_DONE
  126. } trade_centre_state_t;
  127. /* Global states for the trade logic. These are used to dictate what gets drawn
  128. * to the screen but also handle a few sync states. The CONN states are to denote
  129. * if a link has been established or note. READY through TRADING are all specific
  130. * screens to draw in the trade center. COLOSSEUM causes a data loopback so the
  131. * player can fight themselves.
  132. */
  133. typedef enum {
  134. GAMEBOY_CONN_FALSE,
  135. GAMEBOY_CONN_TRUE,
  136. GAMEBOY_READY,
  137. GAMEBOY_WAITING,
  138. GAMEBOY_TRADE_PENDING,
  139. GAMEBOY_TRADING,
  140. GAMEBOY_COLOSSEUM
  141. } render_gameboy_state_t;
  142. /* Anonymous struct */
  143. struct trade_ctx {
  144. trade_centre_state_t trade_centre_state;
  145. FuriTimer* draw_timer;
  146. View* view;
  147. uint8_t in_data;
  148. uint8_t out_data;
  149. uint8_t shift;
  150. TradeBlock* trade_block;
  151. TradeBlock* input_block;
  152. const PokemonTable* pokemon_table;
  153. struct patch_list* patch_list;
  154. void* gblink_handle;
  155. struct gblink_pins* gblink_pins;
  156. };
  157. /* These are the needed variables for the draw callback */
  158. struct trade_model {
  159. render_gameboy_state_t gameboy_status;
  160. bool ledon; // Controls the blue LED during trade
  161. uint8_t curr_pokemon;
  162. const PokemonTable* pokemon_table;
  163. };
  164. /* A callback function that must be called outside of an interrupt context,
  165. * This will completely destroy the current patch list, and then rebuild it from
  166. * the current trade_block state. This is used mostly after a trade to rebuild
  167. * the list with the new data we just copied in.
  168. */
  169. static void pokemon_plist_recreate_callback(void* context, uint32_t arg) {
  170. furi_assert(context);
  171. UNUSED(arg);
  172. struct trade_ctx* trade = context;
  173. plist_create(&(trade->patch_list), trade->trade_block);
  174. }
  175. /* Draws a whole screen image with Flipper mascot, Game Boy, etc. */
  176. static void trade_draw_connect(Canvas* const canvas) {
  177. furi_assert(canvas);
  178. canvas_draw_frame(canvas, 0, 0, 128, 64);
  179. canvas_draw_icon(canvas, 1, 21, &I_Connect_me_62x31);
  180. canvas_draw_icon(canvas, 0, 53, &I_Background_128x11);
  181. canvas_draw_icon(canvas, 80, 0, &I_game_boy);
  182. canvas_draw_icon(canvas, 8, 2, &I_Space_65x18);
  183. canvas_draw_str(canvas, 18, 13, "Connect GB");
  184. }
  185. /* Draws a whole screen image with Flipper mascot, Game Boy, etc. */
  186. static void trade_draw_connected(Canvas* const canvas) {
  187. furi_assert(canvas);
  188. canvas_draw_frame(canvas, 0, 0, 128, 64);
  189. canvas_draw_icon(canvas, 1, 21, &I_Connected_62x31);
  190. canvas_draw_icon(canvas, 0, 53, &I_Background_128x11);
  191. canvas_draw_icon(canvas, 80, 0, &I_game_boy);
  192. canvas_draw_icon(canvas, 8, 2, &I_Space_65x18);
  193. canvas_draw_str(canvas, 18, 13, "Connected!");
  194. }
  195. /* Draws a frame around the screen, with a box at the top for a text string,
  196. * and an icon of the player.
  197. */
  198. static void trade_draw_frame(Canvas* canvas, const char* str) {
  199. furi_assert(canvas);
  200. canvas_draw_icon(canvas, 0, 53, &I_Background_128x11);
  201. canvas_draw_frame(canvas, 0, 0, 128, 64);
  202. canvas_draw_icon(canvas, 24, 0, &I_Space_80x18);
  203. canvas_draw_str(canvas, 48, 12, str);
  204. canvas_draw_icon(canvas, 27, 1, &I_red_16x15);
  205. }
  206. /* Draws the Pokemon's image in the middle of the screen */
  207. static void trade_draw_pkmn_avatar(Canvas* canvas, const Icon* icon) {
  208. furi_assert(canvas);
  209. furi_assert(icon);
  210. canvas_draw_icon(canvas, 38, 11, icon);
  211. furi_hal_light_set(LightBlue, 0x00);
  212. furi_hal_light_set(LightGreen, 0x00);
  213. }
  214. /* Called every 250 ms on a timer. This controls the blue LED when in TRADING
  215. * state. This is necessary as Flipper OS does not make any guarantees on when
  216. * draw updates may or may not be called. There are situations where a draw
  217. * update is called much faster. Therefore, we need to control the update rate
  218. * via the ledon view_model variable.
  219. */
  220. static void trade_draw_timer_callback(void* context) {
  221. furi_assert(context);
  222. struct trade_ctx* trade = (struct trade_ctx*)context;
  223. with_view_model(
  224. trade->view, struct trade_model * model, { model->ledon ^= 1; }, true);
  225. }
  226. static void trade_draw_callback(Canvas* canvas, void* view_model) {
  227. furi_assert(view_model);
  228. struct trade_model* model = view_model;
  229. const Icon* icon = model->pokemon_table[model->curr_pokemon].icon;
  230. canvas_clear(canvas);
  231. switch(model->gameboy_status) {
  232. case GAMEBOY_CONN_FALSE:
  233. furi_hal_light_set(LightGreen, 0x00);
  234. furi_hal_light_set(LightRed, 0xff);
  235. trade_draw_connect(canvas);
  236. break;
  237. case GAMEBOY_CONN_TRUE:
  238. furi_hal_light_set(LightGreen, 0xff);
  239. furi_hal_light_set(LightRed, 0x00);
  240. trade_draw_connected(canvas);
  241. break;
  242. case GAMEBOY_READY:
  243. trade_draw_pkmn_avatar(canvas, icon);
  244. trade_draw_frame(canvas, "READY");
  245. break;
  246. case GAMEBOY_WAITING:
  247. trade_draw_pkmn_avatar(canvas, icon);
  248. trade_draw_frame(canvas, "WAITING");
  249. break;
  250. case GAMEBOY_TRADE_PENDING:
  251. trade_draw_pkmn_avatar(canvas, icon);
  252. trade_draw_frame(canvas, "DEAL?");
  253. break;
  254. case GAMEBOY_TRADING:
  255. furi_hal_light_set(LightGreen, 0x00);
  256. if(model->ledon) {
  257. furi_hal_light_set(LightBlue, 0xff);
  258. canvas_draw_icon(canvas, 0, 0, &I_gb_step_1);
  259. } else {
  260. furi_hal_light_set(LightBlue, 0x00);
  261. canvas_draw_icon(canvas, 0, 0, &I_gb_step_2);
  262. }
  263. trade_draw_frame(canvas, "TRADING");
  264. break;
  265. case GAMEBOY_COLOSSEUM:
  266. trade_draw_frame(canvas, "FIGHT!");
  267. break;
  268. default:
  269. trade_draw_frame(canvas, "INITIAL");
  270. break;
  271. }
  272. }
  273. /* Get the response byte from the link partner, updating the connection
  274. * state if needed.
  275. */
  276. static uint8_t getConnectResponse(struct trade_ctx* trade) {
  277. furi_assert(trade);
  278. uint8_t ret;
  279. switch(trade->in_data) {
  280. case PKMN_CONNECTED:
  281. with_view_model(
  282. trade->view,
  283. struct trade_model * model,
  284. { model->gameboy_status = GAMEBOY_CONN_TRUE; },
  285. false);
  286. ret = PKMN_CONNECTED;
  287. break;
  288. case PKMN_MASTER:
  289. ret = PKMN_SLAVE;
  290. break;
  291. case PKMN_BLANK:
  292. ret = PKMN_BLANK;
  293. break;
  294. default:
  295. with_view_model(
  296. trade->view,
  297. struct trade_model * model,
  298. { model->gameboy_status = GAMEBOY_CONN_FALSE; },
  299. false);
  300. ret = PKMN_BREAK_LINK;
  301. break;
  302. }
  303. return ret;
  304. }
  305. /* Receive what the Pokemon game is requesting and move to that mode.
  306. *
  307. * This reads bytes sent by the Game Boy and responds. The only things
  308. * we care about are when menu items are actually selected. The protocol
  309. * seems to send data both when one of the link menu items is highlighted
  310. * and when one of them is selected.
  311. *
  312. * If somehow we get a leader/master byte received, then go back to the
  313. * NOT_CONNECTED state. For the leader/master byte likely means that
  314. * the linked Game Boy is still trying to negotiate roles and we need to
  315. * respond with a follower/slave byte.
  316. *
  317. * Note that, we can probably eventually drop colosseum/battle connections,
  318. * though it may be an interesting exercise in better understanding how the
  319. * "random" seeding is done between the units. As noted here:
  320. * http://www.adanscotney.com/2014/01/spoofing-pokemon-trades-with-stellaris.html
  321. * it is presumed these bytes are to sync the RNG seed between the units to
  322. * not need arbitration on various die rolls.
  323. */
  324. static uint8_t getMenuResponse(struct trade_ctx* trade) {
  325. furi_assert(trade);
  326. uint8_t response = PKMN_BLANK;
  327. switch(trade->in_data) {
  328. case PKMN_CONNECTED:
  329. response = PKMN_CONNECTED;
  330. break;
  331. case PKMN_TRADE_CENTRE:
  332. with_view_model(
  333. trade->view,
  334. struct trade_model * model,
  335. { model->gameboy_status = GAMEBOY_READY; },
  336. false);
  337. break;
  338. case PKMN_COLOSSEUM:
  339. with_view_model(
  340. trade->view,
  341. struct trade_model * model,
  342. { model->gameboy_status = GAMEBOY_COLOSSEUM; },
  343. false);
  344. break;
  345. case PKMN_BREAK_LINK:
  346. case PKMN_MASTER:
  347. with_view_model(
  348. trade->view,
  349. struct trade_model * model,
  350. { model->gameboy_status = GAMEBOY_CONN_FALSE; },
  351. false);
  352. response = PKMN_BREAK_LINK;
  353. break;
  354. default:
  355. response = trade->in_data;
  356. break;
  357. }
  358. return response;
  359. }
  360. static uint8_t getTradeCentreResponse(struct trade_ctx* trade) {
  361. furi_assert(trade);
  362. uint8_t* trade_block_flat = (uint8_t*)trade->trade_block;
  363. uint8_t* input_block_flat = (uint8_t*)trade->input_block;
  364. uint8_t* input_party_flat = (uint8_t*)trade->input_block->party;
  365. struct trade_model* model = NULL;
  366. uint8_t in = trade->in_data;
  367. uint8_t send = in;
  368. static bool patch_pt_2;
  369. static int counter;
  370. static uint8_t in_pkmn_idx;
  371. /* TODO: Figure out how we should respond to a no_data_byte and/or how to
  372. * send one and what response to expect.
  373. *
  374. * This isn't a high priority since it should be unlikely that we would
  375. * actually ever receive a NO_DATA_BYE as the Game Boy is the leader/master
  376. * and therefore would only transmit when it has data ready.
  377. */
  378. /* Since this is a fairly long function, it doesn't call any other functions,
  379. * the view model isn't locked, and we're in an interrupt context, lets just
  380. * map the view model to a local var and commit it back when we're done.
  381. */
  382. model = view_get_model(trade->view);
  383. /* There is a handful of communications that happen once the Game Boy
  384. * clicks on the table. For all of them, the Flipper can just mirror back
  385. * the byte the Game Boy sends. We can spin in this forever until we see 10x
  386. * SERIAL_PREAMBLE_BYTEs. Once we receive those, the counters are synced,
  387. * and every byte after that can be easily counted for the actual transfer
  388. * of Pokemon data.
  389. */
  390. switch(trade->trade_centre_state) {
  391. case TRADE_RESET:
  392. /* Reset counters and other static variables */
  393. counter = 0;
  394. patch_pt_2 = false;
  395. trade->trade_centre_state = TRADE_INIT;
  396. break;
  397. /* This state runs through the end of the random preamble */
  398. case TRADE_INIT:
  399. if(in == SERIAL_PREAMBLE_BYTE) {
  400. counter++;
  401. model->gameboy_status = GAMEBOY_WAITING;
  402. } else if((in & PKMN_SEL_NUM_MASK) == PKMN_SEL_NUM_MASK) {
  403. send = PKMN_TABLE_LEAVE;
  404. }
  405. if(counter == SERIAL_RNS_LENGTH) {
  406. trade->trade_centre_state = TRADE_RANDOM;
  407. counter = 0;
  408. }
  409. break;
  410. /* Once we start getting PKMN_BLANKs, we mirror them until we get 10x
  411. * SERIAL_PREAMBLE_BYTE, and then 10 random numbers. The 10 random
  412. * numbers are for synchronizing the PRNG between the two systems,
  413. * we do not use these numbers at this time.
  414. *
  415. * This waits through the end of the trade block preamble, a total of 20
  416. * bytes.
  417. */
  418. case TRADE_RANDOM:
  419. counter++;
  420. if(counter == (SERIAL_RNS_LENGTH + SERIAL_TRADE_PREAMBLE_LENGTH)) {
  421. trade->trade_centre_state = TRADE_DATA;
  422. counter = 0;
  423. }
  424. break;
  425. /* This is where we exchange trade_block data with the Game Boy */
  426. case TRADE_DATA:
  427. input_block_flat[counter] = in;
  428. send = trade_block_flat[counter];
  429. counter++;
  430. if(counter == sizeof(TradeBlock)) {
  431. trade->trade_centre_state = TRADE_PATCH_HEADER;
  432. counter = 0;
  433. }
  434. break;
  435. /* This absorbs the 3 byte ending sequence (DF FE 15) after the trade data is
  436. * swapped, then the 3x SERIAL_PREAMBLE_BYTEs that end the trade data, and
  437. * another 3x of them that start the patch data. By the time we're done with
  438. * this state, the patch list BLANK bytes are ready to be transmitted.
  439. * We only care about the 6x total preamble bytes.
  440. */
  441. case TRADE_PATCH_HEADER:
  442. if(in == SERIAL_PREAMBLE_BYTE) {
  443. counter++;
  444. }
  445. if(counter == 6) {
  446. counter = 0;
  447. trade->trade_centre_state = TRADE_PATCH_DATA;
  448. } else {
  449. break;
  450. }
  451. [[fallthrough]];
  452. case TRADE_PATCH_DATA:
  453. counter++;
  454. /* This magic number is basically the header length, 10, minus
  455. * the 3x 0xFD that we should be transmitting as part of the patch
  456. * list header.
  457. */
  458. if(counter > 7) {
  459. send = plist_index_get(trade->patch_list, (counter - 8));
  460. }
  461. /* Patch received data */
  462. /* This relies on the data sent only ever sending 0x00 after
  463. * part 2 of the patch list has been terminated. This is the
  464. * case in official Gen I code at this time.
  465. */
  466. switch(in) {
  467. case PKMN_BLANK:
  468. break;
  469. case SERIAL_PATCH_LIST_PART_TERMINATOR:
  470. patch_pt_2 = true;
  471. break;
  472. default: // Any nonzero value will cause a patch
  473. if(!patch_pt_2) {
  474. /* Pt 1 is 0x00 - 0xFB */
  475. input_party_flat[in - 1] = SERIAL_NO_DATA_BYTE;
  476. } else {
  477. /* Pt 2 is 0xFC - 0x107
  478. * 0xFC + in - 1
  479. */
  480. input_party_flat[0xFB + in] = SERIAL_NO_DATA_BYTE;
  481. }
  482. break;
  483. }
  484. /* What is interesting about the following check, is the Pokemon code
  485. * seems to allocate 203 bytes, 3x for the preamble, and then 200 bytes
  486. * of patch list. But in practice, the Game Boy seems to transmit 3x
  487. * preamble bytes, 7x 0x00, then 189 bytes for the patch list. A
  488. * total of 199 bytes transmitted.
  489. */
  490. if(counter == 196) trade->trade_centre_state = TRADE_SELECT;
  491. break;
  492. /* Resets the incoming Pokemon index, and once a BLANK byte is received,
  493. * moves to the pending state.
  494. */
  495. case TRADE_SELECT:
  496. in_pkmn_idx = 0;
  497. if(in == PKMN_BLANK) {
  498. trade->trade_centre_state = TRADE_PENDING;
  499. } else {
  500. break;
  501. }
  502. [[fallthrough]];
  503. /* Handle the Game Boy selecting a Pokemon to trade, or leaving the table */
  504. case TRADE_PENDING:
  505. /* If the player leaves the trade menu and returns to the room */
  506. if(in == PKMN_TABLE_LEAVE) {
  507. trade->trade_centre_state = TRADE_RESET;
  508. send = PKMN_TABLE_LEAVE;
  509. model->gameboy_status = GAMEBOY_READY;
  510. /* If the player selected a Pokemon to send from the Game Boy */
  511. } else if((in & PKMN_SEL_NUM_MASK) == PKMN_SEL_NUM_MASK) {
  512. in_pkmn_idx = in;
  513. send = PKMN_SEL_NUM_ONE; // We always send the first Pokemon
  514. model->gameboy_status = GAMEBOY_TRADE_PENDING;
  515. /* BLANKs are sent in a few places, we want to do nothing about them
  516. * unless the Game Boy already sent us an index they want to trade.
  517. */
  518. } else if(in == PKMN_BLANK) {
  519. if(in_pkmn_idx != 0) {
  520. send = 0;
  521. trade->trade_centre_state = TRADE_CONFIRMATION;
  522. in_pkmn_idx &= 0x0F;
  523. }
  524. }
  525. break;
  526. /* Handle the Game Boy accepting or rejecting a trade deal */
  527. case TRADE_CONFIRMATION:
  528. if(in == PKMN_TRADE_REJECT) {
  529. trade->trade_centre_state = TRADE_SELECT;
  530. model->gameboy_status = GAMEBOY_WAITING;
  531. } else if(in == PKMN_TRADE_ACCEPT) {
  532. trade->trade_centre_state = TRADE_DONE;
  533. }
  534. break;
  535. /* Start the actual trade. Waits in reset until the Game Boy is done with
  536. * its animation and re-exchanges updated party data.
  537. */
  538. case TRADE_DONE:
  539. if(in == PKMN_BLANK) {
  540. trade->trade_centre_state = TRADE_RESET;
  541. model->gameboy_status = GAMEBOY_TRADING;
  542. /* Copy the traded-in Pokemon's main data to our struct */
  543. trade->trade_block->party_members[0] = trade->input_block->party_members[in_pkmn_idx];
  544. memcpy(
  545. &(trade->trade_block->party[0]),
  546. &(trade->input_block->party[in_pkmn_idx]),
  547. sizeof(struct pokemon_structure));
  548. memcpy(
  549. &(trade->trade_block->nickname[0]),
  550. &(trade->input_block->nickname[in_pkmn_idx]),
  551. sizeof(struct name));
  552. memcpy(
  553. &(trade->trade_block->ot_name[0]),
  554. &(trade->input_block->ot_name[in_pkmn_idx]),
  555. sizeof(struct name));
  556. model->curr_pokemon = pokemon_table_get_num_from_index(
  557. trade->pokemon_table, trade->trade_block->party_members[0]);
  558. /* Schedule a callback outside of ISR context to rebuild the patch
  559. * list with the new Pokemon that we just accepted.
  560. */
  561. furi_timer_pending_callback(pokemon_plist_recreate_callback, trade, 0);
  562. }
  563. break;
  564. default:
  565. // Do Nothing
  566. break;
  567. }
  568. view_commit_model(trade->view, false);
  569. return send;
  570. }
  571. static void transferBit(void* context, uint8_t in_byte) {
  572. furi_assert(context);
  573. struct trade_ctx* trade = (struct trade_ctx*)context;
  574. render_gameboy_state_t status;
  575. with_view_model(
  576. trade->view, struct trade_model * model, { status = model->gameboy_status; }, false);
  577. trade->in_data = in_byte;
  578. /* Once a byte of data has been shifted in, process it */
  579. switch(status) {
  580. case GAMEBOY_CONN_FALSE:
  581. gblink_transfer(trade->gblink_handle, getConnectResponse(trade));
  582. break;
  583. case GAMEBOY_CONN_TRUE:
  584. gblink_transfer(trade->gblink_handle, getMenuResponse(trade));
  585. break;
  586. case GAMEBOY_COLOSSEUM:
  587. gblink_transfer(trade->gblink_handle, in_byte);
  588. break;
  589. /* Every other state is trade related */
  590. default:
  591. gblink_transfer(trade->gblink_handle, getTradeCentreResponse(trade));
  592. break;
  593. }
  594. }
  595. void trade_enter_callback(void* context) {
  596. furi_assert(context);
  597. struct trade_ctx* trade = (struct trade_ctx*)context;
  598. struct trade_model* model;
  599. struct gblink_def gblink_def = {0};
  600. model = view_get_model(trade->view);
  601. if(model->gameboy_status == GAMEBOY_COLOSSEUM) {
  602. model->gameboy_status = GAMEBOY_CONN_FALSE;
  603. } else if(model->gameboy_status > GAMEBOY_READY) {
  604. model->gameboy_status = GAMEBOY_READY;
  605. }
  606. trade->trade_centre_state = TRADE_RESET;
  607. model->pokemon_table = trade->pokemon_table;
  608. model->curr_pokemon = pokemon_table_get_num_from_index(
  609. trade->pokemon_table, trade->trade_block->party_members[0]);
  610. model->ledon = false;
  611. view_commit_model(trade->view, true);
  612. /* TODO: This should be moved further back to struct pokemon_fap for whole
  613. * app flexibility since it would probably be written to by a different scene
  614. */
  615. gblink_def.pins = trade->gblink_pins;
  616. gblink_def.callback = transferBit;
  617. gblink_def.cb_context = trade;
  618. trade->gblink_handle = gblink_alloc(&gblink_def);
  619. gblink_nobyte_set(trade->gblink_handle, SERIAL_NO_DATA_BYTE);
  620. /* Every 250 ms, trigger a draw update. 250 ms was chosen so that during
  621. * the trade process, each update can flip the LED and screen to make the
  622. * trade animation.
  623. */
  624. trade->draw_timer = furi_timer_alloc(trade_draw_timer_callback, FuriTimerTypePeriodic, trade);
  625. furi_timer_start(trade->draw_timer, furi_ms_to_ticks(250));
  626. /* Create a trade patch list from the current trade block */
  627. plist_create(&(trade->patch_list), trade->trade_block);
  628. }
  629. void disconnect_pin(const GpioPin* pin) {
  630. /* Existing projects seem to set the pin back to analog mode upon exit */
  631. furi_hal_gpio_init_simple(pin, GpioModeAnalog);
  632. }
  633. void trade_exit_callback(void* context) {
  634. furi_assert(context);
  635. struct trade_ctx* trade = (struct trade_ctx*)context;
  636. furi_hal_light_set(LightGreen, 0x00);
  637. furi_hal_light_set(LightBlue, 0x00);
  638. furi_hal_light_set(LightRed, 0x00);
  639. /* Stop the timer, and deallocate it as the enter callback allocates it on entry */
  640. furi_timer_free(trade->draw_timer);
  641. trade->draw_timer = NULL;
  642. /* Unset the pin settings */
  643. gblink_free(trade->gblink_handle);
  644. /* Destroy the patch list, it is allocated on the enter callback */
  645. plist_free(trade->patch_list);
  646. trade->patch_list = NULL;
  647. }
  648. void* trade_alloc(
  649. TradeBlock* trade_block,
  650. const PokemonTable* table,
  651. struct gblink_pins* gblink_pins,
  652. ViewDispatcher* view_dispatcher,
  653. uint32_t view_id) {
  654. furi_assert(trade_block);
  655. struct trade_ctx* trade = malloc(sizeof(struct trade_ctx));
  656. memset(trade, '\0', sizeof(struct trade_ctx));
  657. trade->view = view_alloc();
  658. trade->trade_block = trade_block;
  659. trade->input_block = malloc(sizeof(TradeBlock));
  660. trade->pokemon_table = table;
  661. trade->patch_list = NULL;
  662. trade->gblink_pins = gblink_pins;
  663. view_set_context(trade->view, trade);
  664. view_allocate_model(trade->view, ViewModelTypeLockFree, sizeof(struct trade_model));
  665. view_set_draw_callback(trade->view, trade_draw_callback);
  666. view_set_enter_callback(trade->view, trade_enter_callback);
  667. view_set_exit_callback(trade->view, trade_exit_callback);
  668. view_dispatcher_add_view(view_dispatcher, view_id, trade->view);
  669. return trade;
  670. }
  671. void trade_free(ViewDispatcher* view_dispatcher, uint32_t view_id, void* trade_ctx) {
  672. furi_assert(trade_ctx);
  673. struct trade_ctx* trade = (struct trade_ctx*)trade_ctx;
  674. view_dispatcher_remove_view(view_dispatcher, view_id);
  675. view_free(trade->view);
  676. free(trade->input_block);
  677. free(trade);
  678. }