trade.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. #include "../pokemon_app.h"
  2. #include "trade.hpp"
  3. #include "../pokemon_data.h"
  4. uint8_t out_data = 0;
  5. uint8_t in_data = 0;
  6. uint8_t shift = 0;
  7. uint32_t time = 0;
  8. volatile int counter = 0;
  9. volatile bool procesing = true;
  10. volatile connection_state_t connection_state = NOT_CONNECTED;
  11. volatile trade_centre_state_t trade_centre_state = INIT;
  12. void screen_gameboy_connect(Canvas* const canvas) {
  13. canvas_draw_frame(canvas, 0, 0, 128, 64);
  14. canvas_draw_icon(canvas, 1, 21, &I_Connect_me_62x31);
  15. canvas_draw_icon(canvas, 0, 53, &I_Background_128x11);
  16. canvas_draw_icon(canvas, 80, 0, &I_game_boy);
  17. canvas_draw_icon(canvas, 8, 2, &I_Space_65x18);
  18. canvas_draw_str(canvas, 18, 13, "Connect GB");
  19. }
  20. void screen_gameboy_connected(Canvas* const canvas) {
  21. canvas_draw_frame(canvas, 0, 0, 128, 64);
  22. canvas_draw_icon(canvas, 1, 21, &I_Connected_62x31);
  23. canvas_draw_icon(canvas, 0, 53, &I_Background_128x11);
  24. canvas_draw_icon(canvas, 80, 0, &I_game_boy);
  25. canvas_draw_icon(canvas, 8, 2, &I_Space_65x18);
  26. canvas_draw_str(canvas, 18, 13, "Connected!");
  27. }
  28. int time_in_seconds = 0;
  29. static void trade_draw_callback(Canvas* canvas, void* context) {
  30. canvas_clear(canvas);
  31. SelectPokemonModel* model = (SelectPokemonModel*)context;
  32. if(!model->trading) {
  33. if(!model->connected) {
  34. furi_hal_light_set(LightGreen, 0x00);
  35. furi_hal_light_set(LightBlue, 0x00);
  36. furi_hal_light_set(LightRed, 0xff);
  37. screen_gameboy_connect(canvas);
  38. } else if(model->connected) {
  39. furi_hal_light_set(LightGreen, 0xff);
  40. furi_hal_light_set(LightBlue, 0x00);
  41. furi_hal_light_set(LightRed, 0x00);
  42. screen_gameboy_connected(canvas);
  43. }
  44. } else {
  45. if(model->gameboy_status == GAMEBOY_TRADING) {
  46. furi_hal_light_set(LightGreen, 0x00);
  47. furi_hal_light_set(LightRed, 0x00);
  48. if(time_in_seconds % 2 == 1) {
  49. furi_hal_light_set(LightBlue, 0xff);
  50. canvas_draw_icon(canvas, 0, 0, &I_gb_step_1);
  51. } else {
  52. furi_hal_light_set(LightBlue, 0x00);
  53. canvas_draw_icon(canvas, 0, 0, &I_gb_step_2);
  54. }
  55. } else if(
  56. model->gameboy_status == GAMEBOY_READY || model->gameboy_status == GAMEBOY_WAITING ||
  57. model->gameboy_status == GAMEBOY_SEND) {
  58. canvas_draw_icon(canvas, 38, 11, pokemon_table[model->current_pokemon].icon);
  59. }
  60. canvas_draw_icon(canvas, 0, 53, &I_Background_128x11);
  61. canvas_draw_frame(canvas, 0, 0, 128, 64);
  62. canvas_draw_icon(canvas, 24, 0, &I_Space_80x18);
  63. const char* gameboy_status_text = "INITIAL";
  64. if(model->gameboy_status == GAMEBOY_READY) {
  65. gameboy_status_text = "READY";
  66. } else if(model->gameboy_status == GAMEBOY_WAITING) {
  67. gameboy_status_text = "WAITING";
  68. } else if(model->gameboy_status == GAMEBOY_TRADE_READY) {
  69. gameboy_status_text = "READY";
  70. } else if(model->gameboy_status == GAMEBOY_SEND) {
  71. gameboy_status_text = "DEAL...";
  72. } else if(model->gameboy_status == GAMEBOY_PENDING) {
  73. gameboy_status_text = "PENDING...";
  74. } else if(model->gameboy_status == GAMEBOY_TRADING) {
  75. gameboy_status_text = "TRADING...";
  76. }
  77. canvas_draw_str(canvas, 48, 12, gameboy_status_text);
  78. canvas_draw_icon(canvas, 27, 1, &I_red_16x15);
  79. time_in_seconds = (int)DWT->CYCCNT / (72000000.0f / 4); // 250ms
  80. }
  81. }
  82. static bool trade_input_callback(InputEvent* event, void* context) {
  83. furi_assert(context);
  84. Trade* trade = (Trade*)context;
  85. bool consumed = false;
  86. if(event->type == InputTypePress && event->key == InputKeyBack) {
  87. view_dispatcher_switch_to_view(trade->app->view_dispatcher, AppViewSelectPokemon);
  88. consumed = true;
  89. }
  90. return consumed;
  91. }
  92. uint32_t micros() {
  93. return DWT->CYCCNT / 64;
  94. }
  95. byte getConnectResponse(byte in) {
  96. if(in == PKMN_CONNECTED) {
  97. connection_state = CONNECTED;
  98. return PKMN_CONNECTED;
  99. }
  100. if(in == PKMN_MASTER) {
  101. return PKMN_SLAVE;
  102. }
  103. if(in == PKMN_BLANK) {
  104. return PKMN_BLANK;
  105. }
  106. connection_state = NOT_CONNECTED;
  107. return PKMN_BREAK_LINK;
  108. }
  109. byte getMenuResponse(byte in) {
  110. byte response = 0x00;
  111. if(in == PKMN_CONNECTED) {
  112. response = PKMN_CONNECTED;
  113. } else if(in == PKMN_TRADE_CENTRE) {
  114. connection_state = TRADE_CENTRE;
  115. } else if(in == PKMN_COLOSSEUM) {
  116. connection_state = COLOSSEUM;
  117. } else if(in == PKMN_BREAK_LINK || in == PKMN_MASTER) {
  118. connection_state = NOT_CONNECTED;
  119. response = PKMN_BREAK_LINK;
  120. } else {
  121. response = in;
  122. }
  123. return response;
  124. }
  125. byte getTradeCentreResponse(byte in, void* context) {
  126. UNUSED(context);
  127. Trade* trade = (Trade*)context;
  128. byte send = 0x00;
  129. if(trade_centre_state == INIT && in == 0x00) {
  130. if(counter++ == 5) {
  131. trade_centre_state = READY_TO_GO;
  132. // CLICK EN LA MESA
  133. with_view_model_cpp(
  134. trade->view,
  135. SelectPokemonModel*,
  136. model,
  137. { model->gameboy_status = GAMEBOY_READY; },
  138. false);
  139. }
  140. send = in;
  141. } else if(trade_centre_state == READY_TO_GO && (in & 0xF0) == 0xF0) {
  142. trade_centre_state = SEEN_FIRST_WAIT;
  143. send = in;
  144. } else if(trade_centre_state == SEEN_FIRST_WAIT && (in & 0xF0) != 0xF0) {
  145. send = in;
  146. counter = 0;
  147. trade_centre_state = SENDING_RANDOM_DATA;
  148. } else if(trade_centre_state == SENDING_RANDOM_DATA && (in & 0xF0) == 0xF0) {
  149. if(counter++ == 5) {
  150. trade_centre_state = WAITING_TO_SEND_DATA;
  151. with_view_model_cpp(
  152. trade->view,
  153. SelectPokemonModel*,
  154. model,
  155. { model->gameboy_status = GAMEBOY_WAITING; },
  156. false);
  157. }
  158. send = in;
  159. } else if(trade_centre_state == WAITING_TO_SEND_DATA && (in & 0xF0) != 0xF0) {
  160. counter = 0;
  161. INPUT_BLOCK[counter] = in;
  162. send = DATA_BLOCK[counter++];
  163. trade_centre_state = SENDING_DATA;
  164. } else if(trade_centre_state == SENDING_DATA) {
  165. INPUT_BLOCK[counter] = in;
  166. send = DATA_BLOCK[counter++];
  167. if(counter == 405) {
  168. trade_centre_state = SENDING_PATCH_DATA;
  169. }
  170. } else if(trade_centre_state == SENDING_PATCH_DATA && in == 0xFD) {
  171. counter = 0;
  172. send = 0xFD;
  173. } else if(trade_centre_state == SENDING_PATCH_DATA && in != 0xFD) {
  174. send = in;
  175. counter++;
  176. if(counter == 197) {
  177. trade_centre_state = TRADE_PENDING;
  178. }
  179. } else if(trade_centre_state == TRADE_PENDING && (in & 0x60) == 0x60) {
  180. if(in == 0x6f) {
  181. trade_centre_state = READY_TO_GO;
  182. send = 0x6f;
  183. with_view_model_cpp(
  184. trade->view,
  185. SelectPokemonModel*,
  186. model,
  187. { model->gameboy_status = GAMEBOY_TRADE_READY; },
  188. false);
  189. } else {
  190. send = 0x60; // first pokemon
  191. with_view_model_cpp(
  192. trade->view,
  193. SelectPokemonModel*,
  194. model,
  195. { model->gameboy_status = GAMEBOY_SEND; },
  196. false);
  197. }
  198. } else if(trade_centre_state == TRADE_PENDING && in == 0x00) {
  199. send = 0;
  200. trade_centre_state = TRADE_CONFIRMATION;
  201. } else if(trade_centre_state == TRADE_CONFIRMATION && (in & 0x60) == 0x60) {
  202. send = in;
  203. if(in == 0x61) {
  204. trade_centre_state = TRADE_PENDING;
  205. with_view_model_cpp(
  206. trade->view,
  207. SelectPokemonModel*,
  208. model,
  209. { model->gameboy_status = GAMEBOY_PENDING; },
  210. false);
  211. } else {
  212. trade_centre_state = DONE;
  213. }
  214. } else if(trade_centre_state == DONE && in == 0x00) {
  215. send = 0;
  216. trade_centre_state = INIT;
  217. with_view_model_cpp(
  218. trade->view,
  219. SelectPokemonModel*,
  220. model,
  221. { model->gameboy_status = GAMEBOY_TRADING; },
  222. false);
  223. } else {
  224. send = in;
  225. }
  226. return send;
  227. }
  228. void transferBit(void* context) {
  229. Trade* trade = (Trade*)context;
  230. byte raw_data = furi_hal_gpio_read(&GAME_BOY_SI);
  231. in_data |= raw_data << (7 - shift);
  232. if(++shift > 7) {
  233. shift = 0;
  234. if(connection_state == NOT_CONNECTED) {
  235. with_view_model_cpp(
  236. trade->view, SelectPokemonModel*, model, { model->connected = false; }, true);
  237. out_data = getConnectResponse(in_data);
  238. } else if(connection_state == CONNECTED) {
  239. with_view_model_cpp(
  240. trade->view, SelectPokemonModel*, model, { model->connected = true; }, true);
  241. out_data = getMenuResponse(in_data);
  242. } else if(connection_state == TRADE_CENTRE) {
  243. out_data = getTradeCentreResponse(in_data, trade);
  244. } else {
  245. out_data = in_data;
  246. }
  247. in_data = 0;
  248. }
  249. while(procesing && !furi_hal_gpio_read(&GAME_BOY_CLK))
  250. ;
  251. furi_hal_gpio_write(&GAME_BOY_SO, out_data & 0x80 ? true : false);
  252. furi_delay_us(
  253. DELAY_MICROSECONDS); // Wait 20-60us ... 120us max (in slave mode is not necessary)
  254. if(trade_centre_state == READY_TO_GO) {
  255. with_view_model_cpp(
  256. trade->view, SelectPokemonModel*, model, { model->trading = true; }, true);
  257. }
  258. out_data = out_data << 1;
  259. }
  260. void input_clk_gameboy(void* context) {
  261. furi_assert(context);
  262. if(time > 0) {
  263. // if there is no response from the master in 120 microseconds, the counters are reset
  264. if(micros() - time > 120) {
  265. // IDLE & Reset
  266. in_data = 0;
  267. shift = 0;
  268. }
  269. }
  270. transferBit(context);
  271. time = micros();
  272. }
  273. unsigned char convertCharToTagHex(char c) {
  274. switch(c) {
  275. case 'A':
  276. return A_;
  277. case 'B':
  278. return B_;
  279. case 'C':
  280. return C_;
  281. case 'D':
  282. return D_;
  283. case 'E':
  284. return E_;
  285. case 'F':
  286. return F_;
  287. case 'G':
  288. return G_;
  289. case 'H':
  290. return H_;
  291. case 'I':
  292. return I_;
  293. case 'J':
  294. return J_;
  295. case 'K':
  296. return K_;
  297. case 'L':
  298. return L_;
  299. case 'M':
  300. return M_;
  301. case 'N':
  302. return N_;
  303. case 'O':
  304. return O_;
  305. case 'P':
  306. return P_;
  307. case 'Q':
  308. return Q_;
  309. case 'R':
  310. return R_;
  311. case 'S':
  312. return S_;
  313. case 'T':
  314. return T_;
  315. case 'U':
  316. return U_;
  317. case 'V':
  318. return V_;
  319. case 'W':
  320. return W_;
  321. case 'X':
  322. return X_;
  323. case 'Y':
  324. return Y_;
  325. case 'Z':
  326. return Z_;
  327. case 'a':
  328. return A_;
  329. case 'b':
  330. return B_;
  331. case 'c':
  332. return C_;
  333. case 'd':
  334. return D_;
  335. case 'e':
  336. return E_;
  337. case 'f':
  338. return F_;
  339. case 'g':
  340. return G_;
  341. case 'h':
  342. return H_;
  343. case 'i':
  344. return I_;
  345. case 'j':
  346. return J_;
  347. case 'k':
  348. return K_;
  349. case 'l':
  350. return L_;
  351. case 'm':
  352. return M_;
  353. case 'n':
  354. return N_;
  355. case 'o':
  356. return O_;
  357. case 'p':
  358. return P_;
  359. case 'q':
  360. return Q_;
  361. case 'r':
  362. return R_;
  363. case 's':
  364. return S_;
  365. case 't':
  366. return T_;
  367. case 'u':
  368. return U_;
  369. case 'v':
  370. return V_;
  371. case 'w':
  372. return W_;
  373. case 'x':
  374. return X_;
  375. case 'y':
  376. return Y_;
  377. case 'z':
  378. return Z_;
  379. case ' ':
  380. return SPACE_;
  381. case '.':
  382. return PERIOD_;
  383. case '\'':
  384. return S_QUOTE_;
  385. case '!':
  386. return MALE_;
  387. case '@':
  388. return FEMALE_;
  389. default:
  390. return 0x00;
  391. }
  392. }
  393. void trade_enter_callback(void* context) {
  394. furi_assert(context);
  395. Trade* trade = (Trade*)context;
  396. with_view_model_cpp(
  397. trade->view,
  398. SelectPokemonModel*,
  399. model,
  400. {
  401. model->current_pokemon = trade->app->current_pokemon;
  402. model->pokemon_hex_code = trade->app->pokemon_hex_code;
  403. model->current_level = trade->app->current_level;
  404. model->current_stats = trade->app->current_stats;
  405. model->current_move = trade->app->current_move;
  406. model->move1_hex_code = trade->app->move1_hex_code;
  407. model->move2_hex_code = trade->app->move2_hex_code;
  408. model->move3_hex_code = trade->app->move3_hex_code;
  409. model->move4_hex_code = trade->app->move4_hex_code;
  410. model->trading = false;
  411. model->connected = false;
  412. model->gameboy_status = GAMEBOY_INITIAL;
  413. },
  414. true);
  415. FURI_LOG_D(TAG, "[Trade] Current Pokemon: %d", trade->app->current_pokemon);
  416. // Set the Pokemon name
  417. unsigned char nickname[11];
  418. for(size_t i = 0; i < 11; ++i) {
  419. nickname[i] = 0x50;
  420. }
  421. for(size_t i = 0; i < strlen(pokemon_table[trade->app->current_pokemon].name); ++i) {
  422. nickname[i] = convertCharToTagHex(pokemon_table[trade->app->current_pokemon].name[i]);
  423. }
  424. memcpy(DATA_BLOCK2.nickname[0].str, nickname, sizeof(nickname));
  425. FURI_LOG_D(TAG, "[Trade] Pokemon Name: %s", pokemon_table[trade->app->current_pokemon].name);
  426. // Set the Pokemon hex code
  427. DATA_BLOCK[12] = trade->app->pokemon_hex_code;
  428. FURI_LOG_D(TAG, "[Trade] Pokemon Hex Code: %x", trade->app->pokemon_hex_code);
  429. // Set the Pokemon level
  430. FURI_LOG_D(TAG, "[Trade] Current Level: %d", trade->app->current_level);
  431. uint8_t level = trade->app->current_level;
  432. DATA_BLOCK2.party[0].level = level & 0xFF;
  433. DATA_BLOCK2.party[0].level_again = level & 0xFF;
  434. FURI_LOG_D(TAG, "[Trade] Level Hex Code: %x", DATA_BLOCK2.party[0].level);
  435. // Set the Pokemon experience
  436. int32_t exp = 0;
  437. if(pokemon_table[trade->app->current_pokemon].xp_group == 0) {
  438. exp = 1.25 * level * level * level;
  439. } else if(pokemon_table[trade->app->current_pokemon].xp_group == 1) {
  440. exp = (1.2 * level * level * level) - (15 * level * level) + (100 * level) - 140;
  441. } else if(pokemon_table[trade->app->current_pokemon].xp_group == 2) {
  442. exp = level * level * level;
  443. } else if(pokemon_table[trade->app->current_pokemon].xp_group == 3) {
  444. exp = 0.8 * level * level * level;
  445. }
  446. DATA_BLOCK2.party[0].exp[0] = (exp >> 16) & 0xFF;
  447. DATA_BLOCK2.party[0].exp[1] = (exp >> 8) & 0xFF;
  448. DATA_BLOCK2.party[0].exp[2] = exp & 0xFF;
  449. FURI_LOG_D(TAG, "[Trade] XP 1: %x", DATA_BLOCK2.party[0].exp[0]);
  450. FURI_LOG_D(TAG, "[Trade] XP 2: %x", DATA_BLOCK2.party[0].exp[1]);
  451. FURI_LOG_D(TAG, "[Trade] XP 3: %x", DATA_BLOCK2.party[0].exp[2]);
  452. // Set the Pokemon stat experience
  453. uint16_t statexp = 0x0000;
  454. if(trade->app->current_stats == 1 || trade->app->current_stats == 4) {
  455. statexp = (65535 / 100) * level;
  456. } else if(trade->app->current_stats == 2 || trade->app->current_stats == 5) {
  457. statexp = 65535;
  458. }
  459. DATA_BLOCK2.party[0].hp_ev = ((statexp >> 8) & 0x00FF) | ((statexp << 8) & 0xFF00);
  460. DATA_BLOCK2.party[0].atk_ev = ((statexp >> 8) & 0x00FF) | ((statexp << 8) & 0xFF00);
  461. DATA_BLOCK2.party[0].def_ev = ((statexp >> 8) & 0x00FF) | ((statexp << 8) & 0xFF00);
  462. DATA_BLOCK2.party[0].spd_ev = ((statexp >> 8) & 0x00FF) | ((statexp << 8) & 0xFF00);
  463. DATA_BLOCK2.party[0].special_ev = ((statexp >> 8) & 0x00FF) | ((statexp << 8) & 0xFF00);
  464. FURI_LOG_D(TAG, "[Trade] Pokemon Stat EXP: %d", statexp);
  465. FURI_LOG_D(TAG, "[Trade] Pokemon HP EV: %x", DATA_BLOCK2.party[0].hp_ev);
  466. FURI_LOG_D(TAG, "[Trade] Pokemon Attack EV: %x", DATA_BLOCK2.party[0].atk_ev);
  467. FURI_LOG_D(TAG, "[Trade] Pokemon Defence EV: %x", DATA_BLOCK2.party[0].def_ev);
  468. FURI_LOG_D(TAG, "[Trade] Pokemon Speed EV: %x", DATA_BLOCK2.party[0].spd_ev);
  469. FURI_LOG_D(TAG, "[Trade] Pokemon Special EV: %x", DATA_BLOCK2.party[0].special_ev);
  470. // Set the Pokemon stats
  471. uint8_t atk_iv = 15;
  472. uint8_t def_iv = 15;
  473. uint8_t spd_iv = 15;
  474. uint8_t special_iv = 15;
  475. uint8_t hp_iv = 15;
  476. if(trade->app->current_stats <= 2) {
  477. atk_iv = rand() % 15;
  478. def_iv = rand() % 15;
  479. spd_iv = rand() % 15;
  480. special_iv = rand() % 15;
  481. DATA_BLOCK2.party[0].iv = ((atk_iv & 0b00001111) << 12) | ((def_iv & 0b00001111) << 8) |
  482. ((spd_iv & 0b00001111) << 4) | ((special_iv & 0b00001111));
  483. hp_iv = (DATA_BLOCK2.party[0].iv & 0xAA) >> 4;
  484. }
  485. FURI_LOG_D(TAG, "[Trade] Pokemon IV: %x", DATA_BLOCK2.party[0].iv);
  486. FURI_LOG_D(TAG, "[Trade] Pokemon HP IV: %x", hp_iv);
  487. FURI_LOG_D(TAG, "[Trade] Pokemon Attack IV: %x", atk_iv);
  488. FURI_LOG_D(TAG, "[Trade] Pokemon Defence IV: %x", def_iv);
  489. FURI_LOG_D(TAG, "[Trade] Pokemon Speed IV: %x", spd_iv);
  490. FURI_LOG_D(TAG, "[Trade] Pokemon Special IV: %x", special_iv);
  491. uint16_t max_hp = floor(
  492. (((2 * (pokemon_table[trade->app->current_pokemon].base_hp + hp_iv)) +
  493. floor(sqrt(statexp) / 4)) *
  494. level) /
  495. 100) +
  496. (level + 10);
  497. DATA_BLOCK2.party[0].max_hp = ((max_hp >> 8) & 0x00FF) | ((max_hp << 8) & 0xFF00);
  498. DATA_BLOCK2.party[0].hp = ((max_hp >> 8) & 0x00FF) | ((max_hp << 8) & 0xFF00);
  499. uint16_t attack = floor(
  500. (((2 * (pokemon_table[trade->app->current_pokemon].base_atk + atk_iv)) +
  501. floor(sqrt(statexp) / 4)) *
  502. level) /
  503. 100) +
  504. 5;
  505. DATA_BLOCK2.party[0].atk = ((attack >> 8) & 0x00FF) | ((attack << 8) & 0xFF00);
  506. uint16_t defence = floor(
  507. (((2 * (pokemon_table[trade->app->current_pokemon].base_def + def_iv)) +
  508. floor(sqrt(statexp) / 4)) *
  509. level) /
  510. 100) +
  511. 5;
  512. DATA_BLOCK2.party[0].def = ((defence >> 8) & 0x00FF) | ((defence << 8) & 0xFF00);
  513. uint16_t speed = floor(
  514. (((2 * (pokemon_table[trade->app->current_pokemon].base_spd + spd_iv)) +
  515. floor(sqrt(statexp) / 4)) *
  516. level) /
  517. 100) +
  518. 5;
  519. DATA_BLOCK2.party[0].spd = ((speed >> 8) & 0x00FF) | ((speed << 8) & 0xFF00);
  520. uint16_t special =
  521. floor(
  522. (((2 * (pokemon_table[trade->app->current_pokemon].base_special + special_iv)) +
  523. floor(sqrt(statexp) / 4)) *
  524. level) /
  525. 100) +
  526. 5;
  527. DATA_BLOCK2.party[0].special = ((special >> 8) & 0x00FF) | ((special << 8) & 0xFF00);
  528. FURI_LOG_D(TAG, "[Trade] Pokemon Max HP: %x", DATA_BLOCK2.party[0].max_hp);
  529. FURI_LOG_D(TAG, "[Trade] Pokemon Attack: %x", DATA_BLOCK2.party[0].atk);
  530. FURI_LOG_D(TAG, "[Trade] Pokemon Defence: %x", DATA_BLOCK2.party[0].def);
  531. FURI_LOG_D(TAG, "[Trade] Pokemon Speed: %x", DATA_BLOCK2.party[0].spd);
  532. FURI_LOG_D(TAG, "[Trade] Pokemon Special: %x", DATA_BLOCK2.party[0].special);
  533. // Set the Pokemon types
  534. DATA_BLOCK2.party[0].type[0] = pokemon_table[trade->app->current_pokemon].type1;
  535. if(pokemon_table[trade->app->current_pokemon].type2 == 0xFF) {
  536. DATA_BLOCK2.party[0].type[1] = pokemon_table[trade->app->current_pokemon].type1;
  537. } else {
  538. DATA_BLOCK2.party[0].type[1] = pokemon_table[trade->app->current_pokemon].type2;
  539. }
  540. FURI_LOG_D(TAG, "[Trade] Type 1: %x", DATA_BLOCK2.party[0].type[0]);
  541. FURI_LOG_D(TAG, "[Trade] Type 2: %x", DATA_BLOCK2.party[0].type[1]);
  542. // Set the Pokemon moves
  543. DATA_BLOCK2.party[0].move[0] = trade->app->move1_hex_code;
  544. DATA_BLOCK2.party[0].move[1] = trade->app->move2_hex_code;
  545. DATA_BLOCK2.party[0].move[2] = trade->app->move3_hex_code;
  546. DATA_BLOCK2.party[0].move[3] = trade->app->move4_hex_code;
  547. FURI_LOG_D(TAG, "[Trade] Move 1 Hex Code: %x", trade->app->move1_hex_code);
  548. FURI_LOG_D(TAG, "[Trade] Move 2 Hex Code: %x", trade->app->move2_hex_code);
  549. FURI_LOG_D(TAG, "[Trade] Move 3 Hex Code: %x", trade->app->move3_hex_code);
  550. FURI_LOG_D(TAG, "[Trade] Move 4 Hex Code: %x", trade->app->move4_hex_code);
  551. // B3 (Pin6) / SO (2)
  552. furi_hal_gpio_write(&GAME_BOY_SO, false);
  553. furi_hal_gpio_init(&GAME_BOY_SO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  554. // B2 (Pin5) / SI (3)
  555. furi_hal_gpio_write(&GAME_BOY_SI, false);
  556. furi_hal_gpio_init(&GAME_BOY_SI, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
  557. // // C3 (Pin7) / CLK (5)
  558. furi_hal_gpio_init(
  559. &GAME_BOY_CLK,
  560. GpioModeInterruptRise,
  561. GpioPullNo,
  562. GpioSpeedVeryHigh); // <-- This line causes the "OK" to stop functioning when exiting the application, so a reboot of the Flipper Zero is required.
  563. furi_hal_gpio_remove_int_callback(&GAME_BOY_CLK);
  564. furi_hal_gpio_add_int_callback(&GAME_BOY_CLK, input_clk_gameboy, trade);
  565. // furi_hal_gpio_disable_int_callback(&GAME_BOY_CLK);
  566. // furi_hal_gpio_remove_int_callback(&GAME_BOY_CLK);
  567. // Reset GPIO pins to default state
  568. // furi_hal_gpio_init(&GAME_BOY_CLK, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
  569. }
  570. bool trade_custom_callback(uint32_t event, void* context) {
  571. UNUSED(event);
  572. furi_assert(context);
  573. Trade* trade = (Trade*)context;
  574. view_dispatcher_send_custom_event(trade->app->view_dispatcher, 0);
  575. return true;
  576. }
  577. void disconnect_pin(const GpioPin* pin) {
  578. furi_hal_gpio_init(pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
  579. furi_hal_gpio_write(pin, true);
  580. }
  581. void trade_exit_callback(void* context) {
  582. furi_assert(context);
  583. procesing = false;
  584. furi_hal_light_set(LightGreen, 0x00);
  585. furi_hal_light_set(LightBlue, 0x00);
  586. furi_hal_light_set(LightRed, 0x00);
  587. }
  588. Trade* trade_alloc(App* app) {
  589. Trade* trade = (Trade*)malloc(sizeof(Trade));
  590. trade->app = app;
  591. trade->view = view_alloc();
  592. procesing = true;
  593. view_set_context(trade->view, trade);
  594. view_allocate_model(trade->view, ViewModelTypeLockFree, sizeof(SelectPokemonModel));
  595. view_set_draw_callback(trade->view, trade_draw_callback);
  596. view_set_input_callback(trade->view, trade_input_callback);
  597. view_set_enter_callback(trade->view, trade_enter_callback);
  598. view_set_custom_callback(trade->view, trade_custom_callback);
  599. view_set_exit_callback(trade->view, trade_exit_callback);
  600. return trade;
  601. }
  602. void trade_free(App* app) {
  603. furi_assert(app);
  604. // Free resources
  605. procesing = false;
  606. furi_hal_gpio_remove_int_callback(&GAME_BOY_CLK);
  607. disconnect_pin(&GAME_BOY_CLK);
  608. view_free(app->trade->view);
  609. free(app->trade);
  610. }
  611. View* trade_get_view(App* app) {
  612. furi_assert(app);
  613. return app->trade->view;
  614. }