Poke_Transporter_GB/source/gameboy_colour.cpp
2024-08-19 14:47:29 -04:00

409 lines
8.4 KiB
C++

// Loosely based on code created by StevenChaulk
// Source: https://github.com/stevenchaulk/arduino-poke-gen2
#include <tonc.h>
#include <string>
#include "gameboy_colour.h"
#include "pokemon_trade.h"
#include "script_array.h"
#include "debug_mode.h"
#include "interrupt.h"
#include "text_engine.h"
#include "global_frame_controller.h"
#include "gb_rom_values/eng_gb_rom_values.h"
#include "background_engine.h"
#include "sprite_data.h"
#define TIMEOUT 2
#define TIMEOUT_ONE_LENGTH 1000000 // Maybe keep a 10:1 ratio between ONE and TWO?
#define TIMEOUT_TWO_LENGTH 100000
#define hs 0
#define ack 1
#define menu 2
#define pretrade 3
#define trade 4
#define party_preamble 5
#define colosseum 6
#define cancel 7
#define trade_data 8
#define box_preamble 9
#define box_data 10
#define end1 11
#define reboot 12
#define remove_array_preamble 13
#define send_remove_array 14
#define end2 15
#define wait_to_resend 16
#define resend_payload 17
const int MODE = 1; // mode=0 will transfer pokemon data from pokemon.h
// mode=1 will copy pokemon party data being received
LinkSPI *linkSPI = new LinkSPI();
uint8_t in_data;
uint8_t out_data;
uint frame;
connection_state_t connection_state;
int counter;
int data_counter = 0;
int gen_1_room_counter = 0;
int gen;
int trade_pokemon;
int FF_count;
int zero_count;
int state;
int mosi_delay = 4; // inital delay, speeds up once sending PKMN
std::string spi_text_out_array[10];
void print(std::string str)
{
for (int i = 10; i > 0; i--)
{
spi_text_out_array[i] = spi_text_out_array[i - 1];
}
spi_text_out_array[0] = str + "\n";
tte_erase_rect(LEFT, TOP, RIGHT, BOTTOM);
tte_set_pos(LEFT, 0);
for (int j = 0; j < 10; j++)
{
tte_write("#{cx:0xE000}");
tte_write(spi_text_out_array[j].c_str());
}
}
void setup()
{
interrupt_init();
interrupt_set_handler(INTR_SERIAL, LINK_SPI_ISR_SERIAL);
interrupt_enable(INTR_SERIAL);
linkSPI->activate(LinkSPI::Mode::MASTER_256KBPS);
linkSPI->setWaitModeActive(false);
state = hs;
in_data = 0;
out_data = 0;
frame = 0;
connection_state = NOT_CONNECTED;
counter = 0;
gen = 0;
trade_pokemon = -1;
FF_count = 0;
zero_count = 0;
if (DEBUG_MODE)
{
tte_erase_rect(LEFT, TOP, RIGHT, BOTTOM);
tte_set_pos(0, 0);
tte_write("FEED ME POKEMON, I HUNGER!\n");
}
set_textbox_large();
tte_erase_screen();
tte_set_pos(40, 24);
tte_write("\n\n\n Connecting to\n GameBoy");
}
byte handleIncomingByte(byte in, byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, Simplified_Pokemon *curr_simple_array, bool cancel_connection)
{
// TODO: Change to a switch statement
if (state == hs)
{
mosi_delay = 4;
if (curr_gb_rom->generation == 2)
{
state = ack;
return 0x00;
}
if (in == 0x00)
{
state = ack;
return 0x01;
}
}
else if (state == ack)
{
if (curr_gb_rom->generation == 2)
{
if (in == 0x61)
{
state = menu;
return 0x61;
}
return 0x01;
}
else
{
if (in == 0x00)
{
state = menu;
return 0x00;
}
else if (in == 0x02)
{
state = hs;
return 0x02;
}
}
}
else if (state == menu)
{
if (in == 0x60 || in == 0x61)
{
tte_erase_screen();
tte_set_pos(40, 24);
tte_write("\n\n\nLink was successful!\n\n Waiting for trade");
link_animation_state(STATE_NO_ANIM);
state = pretrade;
data_counter = 0;
return in;
}
else if (in == 0x02)
{
state = hs;
return 0x02;
}
else
{
return in;
}
}
else if (state == pretrade)
{
if (data_counter == 16)
{
data_counter = 0;
state = trade;
}
data_counter++;
return (curr_gb_rom->generation == 1 ? 0xD4 : 0x61);
}
else if (state == trade)
{
if (in == 0xfd)
{
tte_erase_screen();
tte_set_pos(40, 24);
tte_write("\n\n\nTransferring data...\n please wait!");
link_animation_state(STATE_TRANSFER);
mosi_delay = 1;
state = party_preamble;
}
return in;
}
else if (state == party_preamble)
{
if (in != 0xfd)
{
state = trade_data;
return exchange_parties(in, curr_payload);
}
return in;
}
else if (state == trade_data)
{
if (data_counter >= curr_gb_rom->payload_size)
{
if (in == 0xFD)
{
state = box_preamble;
}
else if ((curr_gb_rom->method == METHOD_MEW) && (in == 0xFE))
{
tte_erase_screen();
tte_set_pos(40, 24);
tte_write("\n\nPlease press A or B\n twice on the other\n GameBoy system");
link_animation_state(STATE_NO_ANIM);
mosi_delay = 3;
state = wait_to_resend;
}
else
{
return 0x00;
}
}
return exchange_parties(in, curr_payload);
}
else if (state == box_preamble)
{
if (in != 0xFD)
{
state = box_data;
data_counter = 0;
return exchange_boxes(in, box_data_storage);
}
return in;
}
else if (state == box_data)
{
if (data_counter >= curr_gb_rom->box_data_size)
{
state = end1;
}
return exchange_boxes(in, box_data_storage);
}
else if (state == wait_to_resend)
{
if (in != 0xFE)
{
tte_erase_screen();
tte_set_pos(40, 24);
tte_write("\n\n\nTransferring data...\n please wait!");
link_animation_state(STATE_TRANSFER);
state = resend_payload;
data_counter = 0x1B4;
}
return 0x00;
}
else if (state == resend_payload)
{
if (data_counter >= (0x1B4 + 0xC2 + 0x07)) // Offset + size + preamble
{
state = box_preamble;
data_counter = curr_gb_rom->payload_size;
mosi_delay = 1;
}
return exchange_parties(in, curr_payload);
}
else if (state == reboot)
{
data_counter = 0;
state = remove_array_preamble;
return 0xFD;
}
else if (state == remove_array_preamble)
{
if (in != 0xFD)
{
state = send_remove_array;
return exchange_remove_array(in, curr_simple_array, cancel_connection);
}
return in;
}
else if (state == send_remove_array)
{
if (data_counter >= 29) // This assumes the preamble does not count towards the number of bytes sent over the cable
{
state = end2;
}
data_counter++;
return exchange_remove_array(in, curr_simple_array, cancel_connection);
}
return in;
}
int loop(byte *box_data_storage, byte *curr_payload, GB_ROM *curr_gb_rom, Simplified_Pokemon *curr_simple_array, bool cancel_connection)
{
int counter = 0;
while (true)
{
// TODO: Restore Errors
in_data = linkSPI->transfer(out_data);
if (DEBUG_MODE)
{
tte_set_margins(0, 0, H_MAX, V_MAX);
print(
std::to_string(counter) + ": [" +
std::to_string(data_counter) + "][" +
std::to_string(state) + "][" +
std::to_string(in_data) + "][" +
std::to_string(out_data) + "]\n");
}
out_data = handleIncomingByte(in_data, box_data_storage, curr_payload, curr_gb_rom, curr_simple_array, cancel_connection);
if (FF_count > (15 * 60))
{
return COND_ERROR_DISCONNECT;
}
if (zero_count > (5 * 60))
{
// return COND_ERROR_COM_ENDED;
}
if (connection_state == COLOSSEUM)
{
return COND_ERROR_COLOSSEUM;
}
if (state == end1)
{
state = reboot;
return 0;
}
if (state == end2)
{
return 0;
}
if (DEBUG_MODE && key_hit(KEY_SELECT))
{
return COND_ERROR_DISCONNECT;
}
if (state != box_data)
{
FF_count = (in_data == 0xFF ? FF_count + mosi_delay : 0);
zero_count = (in_data == 0x00 ? zero_count + mosi_delay : 0);
}
counter++;
for (int i = 0; i < mosi_delay; i++)
{
global_next_frame();
}
}
};
byte exchange_parties(byte curr_in, byte *curr_payload)
{
int ret = curr_payload[data_counter];
data_counter += 1;
return ret;
};
byte exchange_boxes(byte curr_in, byte *box_data_storage)
{
box_data_storage[data_counter] = curr_in;
data_counter += 1;
return curr_in;
};
byte exchange_remove_array(byte curr_in, Simplified_Pokemon *curr_simple_array, bool cancel_connection)
{
for (int i = 29; i >= 0; i--)
{
if (curr_simple_array[i].is_valid && !curr_simple_array[i].is_transferred && !cancel_connection)
{
curr_simple_array[i].is_transferred = true;
return i;
}
}
return 0xFF;
}