diff --git a/include/debug.h b/include/debug.h index ea70b6b..3f4a99e 100644 --- a/include/debug.h +++ b/include/debug.h @@ -1,6 +1,9 @@ #ifndef DEBUG_H #define DEBUG_H +#include +#include + #define testVar 1000 char intToHex(unsigned int num); void printValueAt(vu32 testAdd); diff --git a/include/gameboy_colour.h b/include/gameboy_colour.h new file mode 100644 index 0000000..60f21d8 --- /dev/null +++ b/include/gameboy_colour.h @@ -0,0 +1,30 @@ +//Created by StevenChaulk? https://github.com/stevenchaulk/arduino-poke-gen2 + +#ifndef GAMEBOY_COLOUR_H_ +#define GAMEBOY_COLOUR_H_ + +#include + +#define LINK_SPI_NO_DATA 0xffffffff +#define LINK_SPI_SIOCNT_NORMAL 0 +#define LINK_SPI_BIT_CLOCK 0 +#define LINK_SPI_BIT_CLOCK_SPEED 1 +#define LINK_SPI_BIT_SI 2 +#define LINK_SPI_BIT_SO 3 +#define LINK_SPI_BIT_START 7 +#define LINK_SPI_BIT_LENGTH 12 +#define LINK_SPI_BIT_IRQ 14 +#define LINK_SPI_BIT_GENERAL_PURPOSE_LOW 14 +#define LINK_SPI_BIT_GENERAL_PURPOSE_HIGH 15 +#define LINK_SPI_SET_HIGH(REG, BIT) REG |= 1 << BIT +#define LINK_SPI_SET_LOW(REG, BIT) REG &= ~(1 << BIT) + +#define LINK_SPI_SET(REG, BIT, VALUE) VALUE ? LINK_SPI_SET_HIGH(REG, BIT) : LINK_SPI_SET_LOW(REG, BIT) + + +void setup(); +byte handleIncomingByte(byte in); +void transferBit(void); +void loop(); + +#endif /* GAMEBOY_COLOUR_H_ */ diff --git a/include/output.h b/include/output.h new file mode 100644 index 0000000..36d5fbe --- /dev/null +++ b/include/output.h @@ -0,0 +1,66 @@ +//Created by StevenChaulk? https://github.com/stevenchaulk/arduino-poke-gen2 + +#include + +#define PLAYER_LENGTH 418 //11+8+(44*6)+(11*6)+(11*6)+3 +#define PLAYER_LENGTH_GEN_II 444 //11+8+2+(48*6)+(11*6)+(11*6)+3 + +uint8_t INPUT_BLOCK[PLAYER_LENGTH]; +uint8_t INPUT_BLOCK_GEN_II[PLAYER_LENGTH_GEN_II]; + +/* const uint8_t DATA_BLOCK[PLAYER_LENGTH] PROGMEM = { +0x80, 0x91, 0x83, 0x94, 0x88, 0x8D, 0x8E, 0x50, 0x00, 0x00, 0x00, // name +0x1, 0x24, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // number of pokemon in party (0x00), pokemon ID (0x01 - 0x06), stop byte (0x07) +// 6 pokemon +//spc curr HP lvl sts typ1 typ2 cr mv1 mv2 mv3 mv4 OT experience HP EV att EV def EV speed EV Speci EV IV mvPP mvPP mvPP mvPP Lvl max HP attack defense speed special +0x24, 0x0, 0xD, 0x2, 0x0, 0x0, 0x2, 0xFF, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46, 0x21, 0x23, 0x0, 0x0, 0x0, 0x2, 0x0, 0xD, 0x0, 0x6, 0x0, 0x6, 0x0, 0x7, 0x0, 0x6, +0x85, 0x0, 0x1, 0x5, 0x1, 0x15, 0x15, 0xFF, 0x96, 0x0, 0x0, 0x0, 0x8, 0x87, 0x0, 0x0, 0x9C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2D, 0x24, 0x28, 0x0, 0x0, 0x0, 0x5, 0x0, 0x11, 0x0, 0x6, 0x0, 0xB, 0x0, 0xD, 0x0, 0x7, +0x85, 0x0, 0x1, 0x5, 0x1, 0x15, 0x15, 0xFF, 0x96, 0x0, 0x0, 0x0, 0x8, 0x87, 0x0, 0x0, 0x9C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2D, 0x24, 0x28, 0x0, 0x0, 0x0, 0x5, 0x0, 0x11, 0x0, 0x6, 0x0, 0xB, 0x0, 0xD, 0x0, 0x7, +0x85, 0x0, 0x1, 0x5, 0x1, 0x15, 0x15, 0xFF, 0x96, 0x0, 0x0, 0x0, 0x8, 0x87, 0x0, 0x0, 0x9C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2D, 0x24, 0x28, 0x0, 0x0, 0x0, 0x5, 0x0, 0x11, 0x0, 0x6, 0x0, 0xB, 0x0, 0xD, 0x0, 0x7, +0x85, 0x0, 0x1, 0x5, 0x1, 0x15, 0x15, 0xFF, 0x96, 0x0, 0x0, 0x0, 0x8, 0x87, 0x0, 0x0, 0x9C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2D, 0x24, 0x28, 0x0, 0x0, 0x0, 0x5, 0x0, 0x11, 0x0, 0x6, 0x0, 0xB, 0x0, 0xD, 0x0, 0x7, +0x85, 0x0, 0x1, 0x5, 0x1, 0x15, 0x15, 0xFF, 0x96, 0x0, 0x0, 0x0, 0x8, 0x87, 0x0, 0x0, 0x9C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2D, 0x24, 0x28, 0x0, 0x0, 0x0, 0x5, 0x0, 0x11, 0x0, 0x6, 0x0, 0xB, 0x0, 0xD, 0x0, 0x7, +// 6 trainer names +0x87, 0x80, 0x82, 0x8A, 0x84, 0x91, 0x50, 0x00, 0x00, 0x00, 0x00, +0xFF, 0x84, 0x83, 0x50, 0x80, 0x92, 0x87, 0x50, 0x89, 0x80, 0x82, +0xFF, 0x84, 0x83, 0x50, 0x80, 0x92, 0x87, 0x50, 0x89, 0x80, 0x82, +0xFF, 0x84, 0x83, 0x50, 0x80, 0x92, 0x87, 0x50, 0x89, 0x80, 0x82, +0xFF, 0x84, 0x83, 0x50, 0x80, 0x92, 0x87, 0x50, 0x89, 0x80, 0x82, +0xFF, 0x84, 0x83, 0x50, 0x80, 0x92, 0x87, 0x50, 0x89, 0x80, 0x82, +// 6 nicknames +0x8F, 0x88, 0x83, 0x86, 0x84, 0x98, 0x50, 0x50, 0x50, 0x50, 0x50, +0x8C, 0x80, 0x86, 0x88, 0x8A, 0x80, 0x91, 0x8F, 0x50, 0x50, 0x50, +0x8C, 0x80, 0x86, 0x88, 0x8A, 0x80, 0x91, 0x8F, 0x50, 0x50, 0x50, +0x8C, 0x80, 0x86, 0x88, 0x8A, 0x80, 0x91, 0x8F, 0x50, 0x50, 0x50, +0x8C, 0x80, 0x86, 0x88, 0x8A, 0x80, 0x91, 0x8F, 0x50, 0x50, 0x50, +0x8C, 0x80, 0x86, 0x88, 0x8A, 0x80, 0x91, 0x8F, 0x50, 0x50, 0x50, +// 2 useless bytes?? +0x00, 0x00, 0x00}; */ + +const uint8_t DATA_BLOCK_GEN_II[PLAYER_LENGTH_GEN_II] = { +0x80, 0x91, 0x83, 0x94, 0x88, 0x8D, 0x8E, 0x50, 0x00, 0x00, 0x00, // name +0x1, 0x5C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // number of pokemon in party (0x00), pokemon ID (0x01 - 0x06), stop byte (0x07) +0xA9, 0xC8, //trainer ID +// 6 pokemon +//spc Held mv1 mv2 mv3 mv4 OT ID exp. HP_EV Attack_EV Def_EV Speed_EV Special_EV IV_Data m1pp m2pp m3pp m4pp frnd virus cght_data lvl sat. N/A curr_HP max_HP attack defence speed spcl_att spcl_def +0x5C, 0x00 ,0x5F, 0x7A, 0xAE, 0xD4, 0x8E, 0x47, 0x00 ,0x16, 0xDA, 0x07 ,0xB4, 0x08, 0x5F, 0x07, 0x8F, 0x09, 0xDF, 0x08, 0x6A, 0x88, 0x51, 0x14 ,0x1E, 0xA , 0x05, 0x9F, 0x00, 0xC3, 0x87, 0x14, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x2D, 0x00, 0x18, 0x00, 0x16, 0x00, 0x29, 0x00, 0x2F, 0x00, 0x15, +0x46, 0x1A, 0x21, 0x00, 0x00, 0x00, 0xA9, 0xC8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0x1E, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xC5, 0x81, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, +0x46, 0x1A, 0x21, 0x00, 0x00, 0x00, 0xA9, 0xC8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0x1E, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xC5, 0x81, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, +0x46, 0x1A, 0x21, 0x00, 0x00, 0x00, 0xA9, 0xC8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0x1E, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xC5, 0x81, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, +0x46, 0x1A, 0x21, 0x00, 0x00, 0x00, 0xA9, 0xC8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0x1E, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xC5, 0x81, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, +0x46, 0x1A, 0x21, 0x00, 0x00, 0x00, 0xA9, 0xC8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0x1E, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xC5, 0x81, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, 0x00, 0x15, +// 6 trainer names +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x50, 0x00, 0x00, 0x00, +0xFF, 0x84, 0x83, 0x50, 0x80, 0x92, 0x87, 0x50, 0x89, 0x80, 0x82, +0xFF, 0x84, 0x83, 0x50, 0x80, 0x92, 0x87, 0x50, 0x89, 0x80, 0x82, +0xFF, 0x84, 0x83, 0x50, 0x80, 0x92, 0x87, 0x50, 0x89, 0x80, 0x82, +0xFF, 0x84, 0x83, 0x50, 0x80, 0x92, 0x87, 0x50, 0x89, 0x80, 0x82, +0xFF, 0x84, 0x83, 0x50, 0x80, 0x92, 0x87, 0x50, 0x89, 0x80, 0x82, +// 6 nicknames +0x8F, 0x88, 0x83, 0x86, 0x84, 0x98, 0x50, 0x50, 0x50, 0x50, 0x50, +0x8C, 0x80, 0x86, 0x88, 0x8A, 0x80, 0x91, 0x8F, 0x50, 0x50, 0x50, +0x8C, 0x80, 0x86, 0x88, 0x8A, 0x80, 0x91, 0x8F, 0x50, 0x50, 0x50, +0x8C, 0x80, 0x86, 0x88, 0x8A, 0x80, 0x91, 0x8F, 0x50, 0x50, 0x50, +0x8C, 0x80, 0x86, 0x88, 0x8A, 0x80, 0x91, 0x8F, 0x50, 0x50, 0x50, +0x8C, 0x80, 0x86, 0x88, 0x8A, 0x80, 0x91, 0x8F, 0x50, 0x50, 0x50, +// 2 useless bytes?? +0x00, 0x00, 0x00}; diff --git a/include/pokemon.h b/include/pokemon.h new file mode 100644 index 0000000..d7025fd --- /dev/null +++ b/include/pokemon.h @@ -0,0 +1,72 @@ +//Created by StevenChaulk? https://github.com/stevenchaulk/arduino-poke-gen2 + +#ifndef POKEMON_H_ +#define POKEMON_H_ + +typedef enum { + NOT_CONNECTED, + CONNECTED, + TRADE_CENTRE, + COLOSSEUM +} connection_state_t; + +/* typedef enum { + INIT, + READY_TO_GO, + SEEN_FIRST_WAIT, + SENDING_RANDOM_DATA, + WAITING_TO_SEND_DATA, + START_SENDING_DATA, + SENDING_DATA, + SENDING_PATCH_DATA, + TRADE_PENDING, + TRADE_CONFIRMATION, + DONE +} trade_centre_state_t; */ + +typedef enum { + INIT, + READY_TO_GO, + SEEN_FIRST_WAIT, + SENDING_RANDOM_DATA, + WAITING_TO_SEND_DATA, + SENDING_DATA, + SENDING_PATCH_DATA, + MIMIC, + TRADE_PENDING, + TRADE_CONFIRMATION, + DONE +} trade_centre_state_gen_II_t; + +typedef unsigned char byte; + +#define PKMN_BLANK 0x00 + +#define ITEM_1_HIGHLIGHTED 0xD0 +#define ITEM_2_HIGHLIGHTED 0xD1 +#define ITEM_3_HIGHLIGHTED 0xD2 +#define ITEM_1_SELECTED 0xD4 +#define ITEM_2_SELECTED 0xD5 +#define ITEM_2_SELECTED 0xD5 +#define ITEM_3_SELECTED 0xD6 + +#define GEN_II_CABLE_TRADE_CENTER 0xD1 +#define GEN_II_CABLE_CLUB_COLOSSEUM 0xD2 + +#define PKMN_MASTER 0x01 +#define PKMN_SLAVE 0x02 +#define PKMN_MASTER_GEN_III 0x8FFF //?? +#define PKMN_SLAVE_GEN_III 0xB9A0 //?? +#define PKMN_CONNECTED_I 0x60 +#define PKMN_CONNECTED_II 0x61 +#define PKMN_WAIT 0x7F + +#define PKMN_ACTION 0x60 + +#define PKMN_TRADE_CENTRE ITEM_1_SELECTED +#define PKMN_COLOSSEUM ITEM_2_SELECTED +#define PKMN_BREAK_LINK ITEM_3_SELECTED + +#define TRADE_CENTRE_WAIT 0xFD + +#endif /* POKEMON_H_ */ diff --git a/source/gameboy_colour.cpp b/source/gameboy_colour.cpp new file mode 100644 index 0000000..952b619 --- /dev/null +++ b/source/gameboy_colour.cpp @@ -0,0 +1,264 @@ +#include +#include +#include "gameboy_colour.h" +#include "pokemon.h" +#include "output.h" + +// Reads the given bit at the given register +INLINE bool LINK_SPI_READ(vu16 REG, u32 BIT) +{ + return REG & (1 << BIT); +} + +const int MODE = 0; // mode=0 will transfer pokemon data from pokemon.h + // mode=1 will copy pokemon party data being received + +uint8_t shift = 0; +uint8_t in_data = 0; +uint8_t out_data = 0; +uint frame = 0; + +connection_state_t connection_state = NOT_CONNECTED; +trade_centre_state_gen_II_t trade_centre_state_gen_II = INIT; +int counter = 0; + +int trade_pokemon = -1; + +unsigned long last_bit; + +void setup() +{ + + // pinMode(SCLK_, INPUT); + // pinMode(MISO_, INPUT); + // pinMode(MOSI_, OUTPUT); + LINK_SPI_SET_LOW(REG_RCNT, 4); + LINK_SPI_SET_LOW(REG_RCNT, 6); + LINK_SPI_SET_HIGH(REG_RCNT, 7); + + LINK_SPI_SET_LOW(REG_RCNT, LINK_SPI_BIT_GENERAL_PURPOSE_LOW); + LINK_SPI_SET_HIGH(REG_RCNT, LINK_SPI_BIT_GENERAL_PURPOSE_HIGH); + + + tte_erase_screen(); + tte_set_pos(0, 0); + tte_write("FEED ME POKEMON, I HUNGER!\n"); + + // digitalWrite(MOSI_, LOW); + LINK_SPI_SET_LOW(REG_RCNT, LINK_SPI_BIT_SI); + + out_data <<= 1; +} + +byte handleIncomingByte(byte in) +{ + byte send = 0x00; + + switch (connection_state) + { + case NOT_CONNECTED: + if (in == PKMN_MASTER) + send = PKMN_SLAVE; + else if (in == PKMN_BLANK) + send = PKMN_BLANK; + else if (in == PKMN_CONNECTED_II) + { + send = PKMN_CONNECTED_II; + connection_state = CONNECTED; + } + break; + + case CONNECTED: + if (in == PKMN_CONNECTED_II) // acknowledge connection + send = PKMN_CONNECTED_II; + else if (in == GEN_II_CABLE_TRADE_CENTER) + { // acknowledge trade center selection + connection_state = TRADE_CENTRE; + send = GEN_II_CABLE_TRADE_CENTER; + } + else if (in == GEN_II_CABLE_CLUB_COLOSSEUM) + { // acknowledge colosseum selection + connection_state = COLOSSEUM; + send = GEN_II_CABLE_CLUB_COLOSSEUM; + } + else + { + send = in; + } + break; + + case TRADE_CENTRE: + if (trade_centre_state_gen_II == INIT && in == 0x00) + { + trade_centre_state_gen_II = READY_TO_GO; + send = 0x00; + } + else if (trade_centre_state_gen_II == READY_TO_GO && in == 0xFD) + { + trade_centre_state_gen_II = SEEN_FIRST_WAIT; + send = 0xFD; + } + else if (trade_centre_state_gen_II == SEEN_FIRST_WAIT && in != 0xFD) + { + // random data of slave is ignored. + send = in; + trade_centre_state_gen_II = SENDING_RANDOM_DATA; + } + else if (trade_centre_state_gen_II == SENDING_RANDOM_DATA && in == 0xFD) + { + trade_centre_state_gen_II = WAITING_TO_SEND_DATA; + send = 0xFD; + } + else if (trade_centre_state_gen_II == WAITING_TO_SEND_DATA && in != 0xFD) + { + counter = 0; + // send first byte + switch (MODE) + { + case 0: + send = DATA_BLOCK_GEN_II[counter]; + INPUT_BLOCK_GEN_II[counter] = in; + break; + case 1: + send = in; + break; + default: + send = in; + break; + } + counter++; + trade_centre_state_gen_II = SENDING_DATA; + } + else if (trade_centre_state_gen_II == SENDING_DATA) + { + switch (MODE) + { + case 0: + send = DATA_BLOCK_GEN_II[counter]; + INPUT_BLOCK_GEN_II[counter] = in; + break; + case 1: + send = in; + break; + default: + send = in; + break; + } + counter++; + if (counter == PLAYER_LENGTH_GEN_II) + { + trade_centre_state_gen_II = SENDING_PATCH_DATA; + } + } + else if (trade_centre_state_gen_II == SENDING_PATCH_DATA && in == 0xFD) + { + counter = 0; + send = 0xFD; + } + else if (trade_centre_state_gen_II == SENDING_PATCH_DATA && in != 0xFD) + { + send = in; + trade_centre_state_gen_II = MIMIC; + } + else if (trade_centre_state_gen_II == MIMIC) + { + send = in; + } + else if (trade_centre_state_gen_II == TRADE_PENDING && (in & 0x60) == 0x60) + { + if (in == 0x6f) + { + trade_centre_state_gen_II = READY_TO_GO; + send = 0x6f; + } + else + { + send = 0x60; // first pokemon + trade_pokemon = in - 0x60; + } + } + else if (trade_centre_state_gen_II == TRADE_PENDING && in == 0x00) + { + send = 0; + trade_centre_state_gen_II = TRADE_CONFIRMATION; + } + else if (trade_centre_state_gen_II == TRADE_CONFIRMATION && (in & 0x60) == 0x60) + { + send = in; + if (in == 0x61) + { + trade_pokemon = -1; + trade_centre_state_gen_II = TRADE_PENDING; + } + else + { + trade_centre_state_gen_II = DONE; + } + } + else if (trade_centre_state_gen_II == DONE && in == 0x00) + { + send = 0; + trade_centre_state_gen_II = INIT; + } + else + { + send = in; + } + break; + + default: + send = in; + break; + } + + return send; +} + +void transferBit(void) +{ + in_data |= LINK_SPI_READ(REG_RCNT, LINK_SPI_BIT_SO) /*digitalRead(MISO_)*/ << (7 - shift); + if (++shift > 7) + { + shift = 0; + out_data = handleIncomingByte(in_data); + tte_set_pos(0, 0); + tte_erase_screen(); + tte_write(trade_centre_state_gen_II); + tte_write(" "); + tte_write(connection_state); + tte_write(" "); + tte_write(in_data, HEX); + tte_write(" "); + tte_write(out_data, HEX); + tte_write("\n"); + in_data = 0; + } + + while (/*!digitalRead(SCLK_)*/!LINK_SPI_READ(REG_RCNT, LINK_SPI_BIT_CLOCK)) // no activity when clock is low + + //digitalWrite(MOSI_, out_data & 0x80 ? HIGH : LOW); + LINK_SPI_SET(REG_RCNT, LINK_SPI_BIT_SI, out_data & 0x80); + out_data <<= 1; +} + +void loop() +{ + while (true) + { + last_bit = frame; + while (LINK_SPI_READ(REG_RCNT, LINK_SPI_BIT_CLOCK) /*digitalRead(SCLK_)*/) + { + if (frame - last_bit > 1000000) + { // show when the clock is inactive + tte_write("idle\n"); + last_bit = frame; + shift = 0; + in_data = 0; + } + frame++; + } + frame++; + transferBit(); + //tte_erase_screen(); + } +} \ No newline at end of file diff --git a/source/gb_link.cpp b/source/gb_link.cpp deleted file mode 100644 index 9fccf57..0000000 --- a/source/gb_link.cpp +++ /dev/null @@ -1,264 +0,0 @@ -#include -#include - -#include "gb_link.h" -#include "LinkSPI.h" -#include "debug.h" - -// (1) Create a LinkSPI instance -LinkSPI *linkSPI = new LinkSPI(); - -vu32 trainerData[111] = {0x8A918892, 0x50505050, 0x50505006, 0x9B9B9B9B, 0x9B9BFF25, 0xDA9B0021, 0x2B000025, 0xDA000087, 0x00000000, 0x00000000, 0x00007221, 0x231E0000, 0x46008581, 0x05000000, 0x13001300, 0x0A000900, 0x0B000B00, 0x0A9B0021, 0x2B000025, 0xDA000087, 0x00000000, 0x00000000, 0x00007221, 0x231E0000, 0x46008581, 0x05000000, 0x13001300, 0x0A000900, 0x0B000B00, 0x0A9B0021, 0x2B000025, 0xDA000087, 0x00000000, 0x00000000, 0x00007221, 0x231E0000, 0x46008581, 0x05000000, 0x13001300, 0x0A000900, 0x0B000B00, 0x0A9B0021, 0x2B000025, 0xDA000087, 0x00000000, 0x00000000, 0x00007221, 0x231E0000, 0x46008581, 0x05000000, 0x13001300, 0x0A000900, 0x0B000B00, 0x0A9B0021, 0x2B000025, 0xDA000087, 0x00000000, 0x00000000, 0x00007221, 0x231E0000, 0x46008581, 0x05000000, 0x13001300, 0x0A000900, 0x0B000B00, 0x0A9B0021, 0x2B000025, 0xDA000087, 0x00000000, 0x00000000, 0x00007221, 0x231E0000, 0x46008581, 0x05000000, 0x13001300, 0x0A000900, 0x0B000B00, 0x0A8A9188, 0x92505050, 0x50505050, 0x8A918892, 0x50505050, 0x5050508A, 0x91889250, 0x50505050, 0x50508A91, 0x88925050, 0x50505050, 0x508A9188, 0x92505050, 0x50505050, 0x8A918892, 0x50505050, 0x50505082, 0x988D8380, 0x9094888B, 0x50508298, 0x8D838090, 0x94888B50, 0x5082988D, 0x83809094, 0x888B5050, 0x82988D83, 0x80909488, 0x8B505082, 0x988D8380, 0x9094888B, 0x50508298, 0x8D838090, 0x94888B50, 0x50000000}; - -void init() -{ - REG_DISPCNT = DCNT_MODE0 | DCNT_BG0; - tte_init_se_default(0, BG_CBB(0) | BG_SBB(31)); - - // (2) Add the interrupt service routines -} - -std::string convertToString(char *a, int size) -{ - int i; - std::string s = ""; - for (i = 0; i < size; i++) - { - s = s + a[i]; - } - return s; -} - -int start_link() -{ - init(); - - u8 SPIout = 0x00; // What the GBA is sending out to the GBC - u8 SPIin = 0x00; // What the GBA is receiving from the GBC - std::string outputArr[16] = {}; - u32 mode = 0; // Trick game into entering trading room - bool firstTransfer = false; - u32 index = 0; - std::string bigOut = ""; - // connection_state linkCable = POST_SAVE; - - connection_state_t connection_state = NOT_CONNECTED; - trade_centre_state_gen_II_t trade_centre_state_gen_II = INIT; - int counter = 0; - byte in; - byte send = 0x16; - const int MODE = 1; // mode=0 will transfer pokemon data from pokemon.h -int trade_pokemon = -1; - - while (true) - { - std::string output = ""; - - u16 keys = ~REG_KEYS & KEY_ANY; - - if (!linkSPI->isActive()) - { - firstTransfer = true; - linkSPI->activate(LinkSPI::Mode::SLAVE); - } - else - { - // Title - auto modeName = - linkSPI->getMode() == LinkSPI::Mode::SLAVE ? "[slave]" : "[master]"; - output += std::string(modeName) + "\n"; - if (firstTransfer) - { - log(output + "Waiting for link cable...\nPress L and R to cancel"); - firstTransfer = false; - } - - // (4)/(5) Exchange 32-bit data with the other end - SPIin = linkSPI->transfer(SPIout, []() - { - bool exit = false; - u16 keys = ~REG_KEYS & KEY_ANY; - if ((keys & KEY_L) && (keys & KEY_R)){ - exit = true; - } - return exit; }); - - in = SPIin; - - byte send = 0x00; - - switch(connection_state) { - case NOT_CONNECTED: - if(in == PKMN_MASTER) - send = PKMN_SLAVE; - else if(in == PKMN_BLANK) - send = PKMN_BLANK; - else if(in == PKMN_CONNECTED_II) { - send = PKMN_CONNECTED_II; - connection_state = CONNECTED; - } - break; - - case CONNECTED: - if(in == PKMN_CONNECTED_II) //acknowledge connection - send = PKMN_CONNECTED_II; - else if(in == GEN_II_CABLE_TRADE_CENTER){ //acknowledge trade center selection - connection_state = TRADE_CENTRE; - send = GEN_II_CABLE_TRADE_CENTER; - } - else if(in == GEN_II_CABLE_CLUB_COLOSSEUM){ //acknowledge colosseum selection - connection_state = COLOSSEUM; - send = GEN_II_CABLE_CLUB_COLOSSEUM; - } - else { - send = in; - } - break; - - case TRADE_CENTRE: - if(trade_centre_state_gen_II == INIT && in == 0x00) { - trade_centre_state_gen_II = READY_TO_GO; - send = 0x00; - } else if(trade_centre_state_gen_II == READY_TO_GO && in == 0xFD) { - trade_centre_state_gen_II = SEEN_FIRST_WAIT; - send = 0xFD; - } else if(trade_centre_state_gen_II == SEEN_FIRST_WAIT && in != 0x70) { - // random data of slave is ignored. - send = in; - trade_centre_state_gen_II = SENDING_RANDOM_DATA; - } else if(trade_centre_state_gen_II == SENDING_RANDOM_DATA && in == 0xFD) { - trade_centre_state_gen_II = WAITING_TO_SEND_DATA; - send = 0xFD; - } else if(trade_centre_state_gen_II == WAITING_TO_SEND_DATA && in != 0xFD) { - counter = 0; - // send first byte - switch(MODE){ - case 0: - //send = pgm_read_byte(&(DATA_BLOCK_GEN_II[counter])); - //INPUT_BLOCK_GEN_II[counter] = in; - break; - case 1: - send = in; - break; - default: - send = in; - break; - } - counter++; - trade_centre_state_gen_II = SENDING_DATA; - } else if(trade_centre_state_gen_II == SENDING_DATA) { - switch(MODE){ - case 0: - //send = pgm_read_byte(&(DATA_BLOCK_GEN_II[counter])); - //INPUT_BLOCK_GEN_II[counter] = in; - break; - case 1: - send = in; - break; - default: - send = in; - break; - } - counter++; - if(counter == PLAYER_LENGTH_GEN_II) { - trade_centre_state_gen_II = SENDING_PATCH_DATA; - } - } else if(trade_centre_state_gen_II == SENDING_PATCH_DATA && in == 0xFD) { - counter = 0; - send = 0xFD; - } else if(trade_centre_state_gen_II == SENDING_PATCH_DATA && in != 0xFD) { - send = in; - trade_centre_state_gen_II = MIMIC; - } else if(trade_centre_state_gen_II == MIMIC){ - send = in; - - - - - - } else if(trade_centre_state_gen_II == TRADE_PENDING && (in & 0x60) == 0x60) { - if (in == 0x6f) { - trade_centre_state_gen_II = READY_TO_GO; - send = 0x6f; - } else { - send = 0x60; // first pokemon - trade_pokemon = in - 0x60; - } - } else if(trade_centre_state_gen_II == TRADE_PENDING && in == 0x00) { - send = 0; - trade_centre_state_gen_II = TRADE_CONFIRMATION; - } else if(trade_centre_state_gen_II == TRADE_CONFIRMATION && (in & 0x60) == 0x60) { - send = in; - if (in == 0x61) { - trade_pokemon = -1; - trade_centre_state_gen_II = TRADE_PENDING; - } else { - trade_centre_state_gen_II = DONE; - } - } else if(trade_centre_state_gen_II == DONE && in == 0x00) { - send = 0; - trade_centre_state_gen_II = INIT; - } else { - send = in; - } - break; - - default: - send = in; - break; - } - - SPIout = send; - - for (int i = 7; i > 0; i--) - { - outputArr[i] = outputArr[i - 1]; - } - outputArr[0] = "TS: " + std::to_string((int)trade_centre_state_gen_II) + " CS: " + std::to_string((int)connection_state) + - " OUT: " + u8ToHexStr(SPIout) + " IN: " + u8ToHexStr(SPIin); - - - // Cancel - if ((keys & KEY_L) && (keys & KEY_R)) - { - linkSPI->deactivate(); - return 0; - } - } - - // Print - VBlankIntrWait(); - output = ""; - - for (int i = 0; i < 8; i++) - { - output += (outputArr[i] + "\n"); - } - - log(output); - } - - return 0; -} - -void log(std::string text) -{ - tte_erase_screen(); - tte_write("#{P:0,0}"); - tte_write(text.c_str()); -} - -void wait(u32 verticalLines) -{ - u32 count = 0; - u32 vCount = REG_VCOUNT; - - while (count < verticalLines) - { - if (REG_VCOUNT != vCount) - { - count++; - vCount = REG_VCOUNT; - } - }; -} \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp index e7008f4..b970c4f 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -7,6 +7,7 @@ #include "interrupt.h" #include "LinkSPI.h" #include "gb_link.h" +#include "gameboy_colour.h" // This file is autogenerated from the file in the graphics folder #include "metr.h" @@ -115,7 +116,8 @@ int main(void) } if (key_released(KEY_START)){ - start_link(); + setup(); + loop(); }