Poke_Transporter_GB/include/link_handler.h
2026-05-24 17:42:04 -04:00

230 lines
5.9 KiB
C++

// Loosely based on code created by StevenChaulk
// Source: https://github.com/stevenchaulk/arduino-poke-gen2
#ifndef LINK_HANDLER_H_
#define LINK_HANDLER_H_
#include <tonc.h>
#include "libraries/gba-link-connection/LinkSPI.hpp"
#include "pokemon_party.h"
#define DATA_PER_PACKET 8
#define PACKET_DATA_START 2
#define PACKET_DATA_AT(i) (PACKET_DATA_START + (i * 2))
#define PACKET_FLAG_AT(i) (PACKET_DATA_START + (i * 2) + 1)
#define PACKET_CHECKSUM (PACKET_DATA_START + (2 * DATA_PER_PACKET))
#define PACKET_LOCATION_UPPER (PACKET_CHECKSUM + 1)
#define PACKET_LOCATION_LOWER (PACKET_CHECKSUM + 2)
// 0xFD, 0x00, data bytes per packet, flag bytes per packet, the checksum, and two location bytes
#define PACKET_SIZE (1 + 1 + (2 * DATA_PER_PACKET) + 1 + 2) // Originally 13
#define TIMEOUT 2
#define TIMEOUT_ONE_LENGTH 1000000 // Maybe keep a 10:1 ratio between ONE and TWO?
#define TIMEOUT_TWO_LENGTH 100000
#define SPI_TEXT_OUT_ARRAY_ELEMENT_SIZE 64
enum GameBoyROM
{
RED_JP_v0,
RED_JP_v1,
RED_EN,
RED_FR,
RED_IT,
RED_DE,
RED_SP,
GREEN_JP_v0,
GREEN_JP_v1,
BLUE_JP,
BLUE_EN,
BLUE_FR,
BLUE_IT,
BLUE_DE,
BLUE_SP,
YELLOW_JP_v0,
YELLOW_JP_v1,
YELLOW_JP_v2,
YELLOW_JP_v3,
YELLOW_EN,
YELLOW_FR,
YELLOW_IT,
YELLOW_DE,
YELLOW_SP,
GOLD_JP_v0,
GOLD_JP_v1,
GOLD_EN,
GOLD_FR,
GOLD_IT,
GOLD_DE,
GOLD_SP,
GOLD_KOR,
SILVER_JP_v0,
SILVER_JP_v1,
SILVER_EN,
SILVER_FR,
SILVER_IT,
SILVER_DE,
SILVER_SP,
SILVER_KOR,
CRYSTAL_JP,
CRYSTAL_EN,
CRYSTAL_FR,
CRYSTAL_IT,
CRYSTAL_DE,
CRYSTAL_SP,
NO_GB_ROM,
GB_ROM_ERROR,
};
// This table has the 3 checksums, followed by the enum value
const u16 GameBoyROMChecksumTable[][4]{
{0x32, 0xA2, 0xC1, RED_JP_v0},
{0x31, 0xB8, 0x66, RED_JP_v1},
{0x20, 0x91, 0xE6, RED_EN},
{0x18, 0x7A, 0xFC, RED_FR},
{0x18, 0x89, 0xD2, RED_IT},
{0x18, 0x5C, 0xDC, RED_DE},
{0x18, 0x38, 0x4A, RED_SP},
{0x9C, 0xDD, 0xD5, GREEN_JP_v0},
{0x9B, 0xF5, 0x47, GREEN_JP_v1},
{0xE5, 0xDC, 0x36, BLUE_JP},
{0xD3, 0x9D, 0x0A, BLUE_EN},
{0xCB, 0x56, 0xA4, BLUE_FR},
{0xCB, 0x5E, 0x9C, BLUE_IT},
{0xCB, 0x2E, 0xBC, BLUE_DE},
{0xCB, 0x14, 0xD7, BLUE_SP},
{0x20, 0x9C, 0x29, YELLOW_JP_v0},
{0x1F, 0x88, 0x58, YELLOW_JP_v1},
{0x1E, 0xED, 0xD9, YELLOW_JP_v2},
{0x1D, 0xD9, 0x84, YELLOW_JP_v3},
{0x97, 0x04, 0x7C, YELLOW_EN},
{0x61, 0x66, 0xFB, YELLOW_FR},
{0x5C, 0x4E, 0x8F, YELLOW_IT},
{0x5F, 0xB7, 0xC1, YELLOW_DE},
{0x52, 0x56, 0x37, YELLOW_SP},
{0x48, 0x8A, 0x70, GOLD_JP_v0},
{0x47, 0x84, 0x60, GOLD_JP_v1},
{0x4B, 0x68, 0x2D, GOLD_EN},
{0x4A, 0x6F, 0xC6, GOLD_FR},
{0x47, 0xCE, 0x0C, GOLD_IT},
{0x4C, 0xDC, 0x97, GOLD_DE},
{0x3D, 0x93, 0x53, GOLD_SP},
{0x08, 0x77, 0x8A, GOLD_KOR},
{0x27, 0x76, 0x91, SILVER_JP_v0},
{0x26, 0x1D, 0x34, SILVER_JP_v1},
{0x2A, 0x0D, 0xAE, SILVER_EN},
{0x29, 0xFB, 0x8C, SILVER_FR},
{0x26, 0x73, 0x50, SILVER_IT},
{0x2B, 0xCD, 0x6E, SILVER_DE},
{0x1C, 0x06, 0x4B, SILVER_SP},
{0xE7, 0x98, 0x5B, SILVER_KOR},
{0x22, 0x9A, 0x40, CRYSTAL_JP},
{0x26, 0x18, 0xD2, CRYSTAL_EN},
{0x26, 0xF2, 0xE2, CRYSTAL_FR},
{0x23, 0xDB, 0xBA, CRYSTAL_IT},
{0x28, 0x49, 0x82, CRYSTAL_DE},
{0x19, 0x42, 0xF4, CRYSTAL_SP},
};
enum CompositeState
{
NO_COMPOSITE_STATE,
INITIAL_CONNECTION
};
enum SubstateState
{
NO_SUBSTATE,
// INITIAL_CONNECTION
CLOCK,
SAVE_SUCCESS,
MENU_OPEN,
MENU_SUCCESS,
WAIT_FOR_TRADE,
TRADE_PREAMBLE,
TRADE,
MAIL,
WAIT_FOR_PAYLOAD,
GET_CHECKSUM,
END,
};
enum LinkConnectionError
{
NO_ERROR,
};
class LinkConnection
{
public:
LinkConnection *globalPtr;
CompositeState compState = NO_COMPOSITE_STATE;
SubstateState subState = NO_SUBSTATE;
CompositeState prevCompState = NO_COMPOSITE_STATE;
SubstateState prevSubState = NO_SUBSTATE;
LinkConnectionError lastError = NO_ERROR;
uint8_t inData;
uint8_t outData;
int compStateCounter = 0; // the counter for the total number of bytes sent compstate
int subStateCounter = 0; // The counter for the total number of bytes sent in this substate
int gen = 0; // The generation we are trading with
GameBoyROM currROM = NO_GB_ROM; // The GameBoy ROM we're communicating with
int FF_count = 0; // The number of 0xFF bytes that have been in a row
int zero_count = 0; // The number of 0x00 bytes that have been in a row
int mosi_delay = 4; // inital delay, speeds up once sending
int received_offset = 0; // The offset contained in the last packet
int next_offset = 0; // The offset we are sending in the next packet
int packet_index = 0; // The index of the current packet
bool failed_packet = false; // Flags if a packet failed
bool init_packet = true; // Flags if a packet is the inital one
bool end_of_data = false; // Flags if we are at the end of the data
bool test_packet_fail = false; // ???
byte data_packet[PACKET_SIZE];
byte curr_payload[0x2A0];
int curr_payload_size = 0;
byte dataOutBuffer[0xFF];
int dataOutBufferCurrIndex = 0;
bool paused = false; // Used for pausing and sending one byte at a time
void setup(const u16 *debug_charset);
void startConnection(CompositeState startState);
bool earlyExit();
void exchangeBytes();
void printData();
void writeData();
void handleStateLogic();
private:
void load_universal_payload();
void LoadCurrGameFromChecksum();
void logicState_initConnection();
// Used for debug features
#define LINE_WIDTH 24
#define NUM_LINES 8
char stuff[NUM_LINES][LINE_WIDTH];
char line[LINE_WIDTH] = "OUT";
int link_cable_array_index = 0;
int link_cable_memory_section_index = 0;
const u16 *debug_charset;
};
extern LinkConnection globalLinkCable;
void linkCableIRQ();
#endif /* LINK_HANDLER_H_ */