From e268ccccf5129f792ca6a3f70746eadc3911b261 Mon Sep 17 00:00:00 2001 From: GearsProgress Date: Thu, 4 Jun 2026 23:12:09 -0400 Subject: [PATCH] Basic link packet implementation --- container/GB_Payloads.containerdef | 6 +- include/dbg/debug_mode.h | 4 +- include/link_handler.h | 29 +++- source/dbg/debug_menu_entries.cpp | 1 + source/dbg/debug_mode.cpp | 1 + source/link_handler.cpp | 246 +++++++++++++++++++---------- source/script_array.cpp | 19 ++- 7 files changed, 203 insertions(+), 103 deletions(-) diff --git a/container/GB_Payloads.containerdef b/container/GB_Payloads.containerdef index c7297a0..7fee1a3 100644 --- a/container/GB_Payloads.containerdef +++ b/container/GB_Payloads.containerdef @@ -1,3 +1,3 @@ -tools/gb-payload-generator/build/specificPayloadGen1_RB_EN.bin -tools/gb-payload-generator/build/universalPayloadGen1.bin -tools/gb-payload-generator/build/universalPayloadGen2.bin +tools/gb-payload-generator/build/specificPayloadGen1/specificPayloadGen1_en_r.bin +tools/gb-payload-generator/build/universalPayloadGen1/universalPayloadGen1.bin +tools/gb-payload-generator/build/universalPayloadGen2/universalPayloadGen2.bin diff --git a/include/dbg/debug_mode.h b/include/dbg/debug_mode.h index b7eb639..2c64234 100644 --- a/include/dbg/debug_mode.h +++ b/include/dbg/debug_mode.h @@ -22,6 +22,9 @@ typedef struct debug_options /** This option will print the link cable data. Pause the transfer with L, resume with R. Skip printing with DOWN. */ bool print_link_data; + /** This option will print the link cable packets. Pause the transfer with L, resume with R. Skip printing with DOWN. */ + bool print_link_packets; + /** * @brief If this option has been set, we won't animate the text, but show the full text immediately. */ @@ -96,7 +99,6 @@ typedef struct debug_options extern debug_options g_debug_options; - // Options that affect and require payload_builder // (and therefore can't be put in the debug menu) #define SHOW_DATA_PACKETS (false && DEBUG_MODE) diff --git a/include/link_handler.h b/include/link_handler.h index cffc44f..bf4cc62 100644 --- a/include/link_handler.h +++ b/include/link_handler.h @@ -163,6 +163,7 @@ enum LinkConnectionError { NO_ERROR, PACKET_TIMED_OUT, + CHECKSUM_MISMATCH, }; enum PayloadCommand @@ -176,8 +177,22 @@ enum PayloadCommand CMD_ReadDataRequest, // a request to read data starting from the address defined by the 16-bit pointer. }; -#define OUT_PACKET_LENGTH 16 -#define IN_PACKET_LENGTH 16 +#define OUTP_PREAMBLE_INDEX 0 +#define OUTP_COUNTER_INDEX 1 +#define OUTP_COMMAND_INDEX 2 +#define OUTP_ARGS_INDEX 3 +#define OUTP_POINTER_INDEX 5 +#define OUTP_FILLER_INDEX 7 +#define OUTP_LENGTH 13 + +#define INP_COUNTER_INDEX (0 + INP_DELAY_FROM_OUTP) +#define INP_LSB_INDEX (1 + INP_DELAY_FROM_OUTP) +#define INP_CHECKSUM_INDEX (3 + INP_DELAY_FROM_OUTP) +#define INP_DATA_INDEX (4 + INP_DELAY_FROM_OUTP) +#define INP_LENGTH (12 + INP_DELAY_FROM_OUTP) + +#define INP_DELAY_FROM_OUTP 3 +#define TOTAL_PACKET_LENGTH (OUTP_LENGTH + INP_DELAY_FROM_OUTP) struct LinkPacket { @@ -187,8 +202,8 @@ struct LinkPacket u16 pointer; // Incoming data - byte recievedData[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; LinkConnectionError latestError = NO_ERROR; + byte recievedData[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; }; class LinkConnection @@ -238,7 +253,10 @@ public: int currLinkPacketArrNum = 0; int currLinkPacketArrIndex = 0; - bool paused = false; // Used for pausing and sending one byte at a time + bool pauseOnByte = false; // Used for pausing and sending one byte at a time + bool pauseOnPacket = false; // Used for pausing and sending one packet at a time + bool skipPrint = false; // Skips printing to the screen + bool newPacket = false; void setup(const u16 *debug_charset); void startConnection(CompositeState startState); @@ -250,7 +268,8 @@ public: private: void load_payload(GB_PayloadsFiles payload); - void LoadCurrGameFromChecksum(); + void loadCurrGameFromChecksum(); + bool processPacket(); void logicState_initConnection(); void logicState_packetExchange(); diff --git a/source/dbg/debug_menu_entries.cpp b/source/dbg/debug_menu_entries.cpp index d44de61..fb20c96 100644 --- a/source/dbg/debug_menu_entries.cpp +++ b/source/dbg/debug_menu_entries.cpp @@ -109,6 +109,7 @@ void fill_debug_menu_with_entries(vertical_menu &menu, u16 *charset) #endif define_song_row(charset, "Song"), define_toggle_row(charset, "Print Link", dbg_set_boolean_flag, g_debug_options.print_link_data, &g_debug_options.print_link_data), + define_toggle_row(charset, "Print Packets", dbg_set_boolean_flag, g_debug_options.print_link_packets, &g_debug_options.print_link_packets), define_toggle_row(charset, "Instant Text", dbg_set_boolean_flag, g_debug_options.instant_text_speed, &g_debug_options.instant_text_speed), define_toggle_row(charset, "Ign Cart", dbg_set_boolean_flag, g_debug_options.ignore_game_pak, &g_debug_options.ignore_game_pak), define_toggle_row(charset, "Ign Sprites", dbg_set_boolean_flag, g_debug_options.ignore_game_pak_sprites, &g_debug_options.ignore_game_pak_sprites), diff --git a/source/dbg/debug_mode.cpp b/source/dbg/debug_mode.cpp index e4826c0..31fb233 100644 --- a/source/dbg/debug_mode.cpp +++ b/source/dbg/debug_mode.cpp @@ -3,6 +3,7 @@ debug_options g_debug_options = { .print_link_data = (true && DEBUG_MODE), + .print_link_packets = (true && DEBUG_MODE), .instant_text_speed = (true && DEBUG_MODE), .ignore_game_pak = (true && DEBUG_MODE), .ignore_game_pak_sprites = (false && DEBUG_MODE), diff --git a/source/link_handler.cpp b/source/link_handler.cpp index 48261ff..bafa424 100644 --- a/source/link_handler.cpp +++ b/source/link_handler.cpp @@ -38,7 +38,7 @@ void linkCableIRQ() globalLinkCable.exchangeBytes(); - if (g_debug_options.print_link_data) + if (g_debug_options.print_link_data || g_debug_options.print_link_packets) { globalLinkCable.printData(); } @@ -78,7 +78,7 @@ void LinkConnection::startConnection(CompositeState startState) case PACKET_EXCHANGE: subState = BYTE_EXCHANGE; REG_TM3D = -0x0040; - //REG_TM3D = -0x4000 / 2; + // REG_TM3D = -0x4000 / 2; REG_TM3CNT = TM_FREQ_1024 | TM_ENABLE; break; default: @@ -107,22 +107,74 @@ void LinkConnection::exchangeBytes() void LinkConnection::printData() { - n2hexstr(&line[0], compState & 0xFF, 2); - line[2] = ':'; - n2hexstr(&line[3], compStateCounter & 0xFFFF, 4); - line[7] = '|'; - n2hexstr(&line[8], subState & 0xFF, 2); - line[10] = ':'; - n2hexstr(&line[11], subStateCounter & 0xFFFF, 4); - line[15] = '|'; - line[16] = 'i'; - n2hexstr(&line[17], inData & 0xFF, 2); - line[19] = '|'; - line[20] = 'o'; - n2hexstr(&line[21], outData & 0xFF, 2); - line[23] = '\0'; - scroll_text(true, tte_get_context(), false, 8, 8, 138, 135); - ptgb_write_debug(this->debug_charset, line, true); + if (globalLinkCable.skipPrint) + { + tte_erase_rect(0, 0, H_MAX, V_MAX); + } + else + { + if (g_debug_options.print_link_data) + { + n2hexstr(&line[0], compState & 0xFF, 2); + line[2] = ':'; + n2hexstr(&line[3], compStateCounter & 0xFFFF, 4); + line[7] = '|'; + n2hexstr(&line[8], subState & 0xFF, 2); + line[10] = ':'; + n2hexstr(&line[11], subStateCounter & 0xFFFF, 4); + line[15] = '|'; + line[16] = 'i'; + n2hexstr(&line[17], inData & 0xFF, 2); + line[19] = '|'; + line[20] = 'o'; + n2hexstr(&line[21], outData & 0xFF, 2); + line[23] = '\0'; + scroll_text(true, tte_get_context(), false, 8, 8, 138, 135); + ptgb_write_debug(this->debug_charset, line, true); + } + + // TODO: This is pretty rough, but it's the best we can do until the text engine rewrite. + if (g_debug_options.print_link_packets) + { + tte_erase_rect(160, 16, H_MAX, V_MAX); + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + { + n2hexstr(&line[3 * j], dataOutBuffer[(4 * i) + j], 2); + line[(3 * j) + 2] = ' '; + } + line[12] = '\0'; + tte_set_pos(160, 16 * i); + ptgb_write_debug(this->debug_charset, line, true); + } + + for (int i = 0; i < 4; i++) + { + byte tempBuffer[16]; + int packetIndex = dataOutBuffer[INP_COUNTER_INDEX]; + LinkPacket &currLinkPacket = currLinkPacketArr[packetIndex]; + + tempBuffer[0] = packetIndex; + tempBuffer[1] = currLinkPacket.command; + tempBuffer[2] = currLinkPacket.pointer >> 0; + tempBuffer[3] = currLinkPacket.pointer >> 8; + memcpy(&tempBuffer[4], currLinkPacket.argument, 2); + tempBuffer[6] = currLinkPacket.latestError; + tempBuffer[7] = 0x00; + memcpy(&tempBuffer[8], currLinkPacket.recievedData, 8); + + for (int j = 0; j < 4; j++) + { + n2hexstr(&line[3 * j], tempBuffer[(4 * i) + j], 2); + line[(3 * j) + 2] = ' '; + } + line[12] = '\0'; + tte_set_pos(160, (16 * 5) + (16 * i)); + ptgb_write_debug(this->debug_charset, line, true); + } + } + } } void LinkConnection::writeData() @@ -187,23 +239,52 @@ void LinkConnection::handleStateLogic() bool LinkConnection::earlyExit() { - if (g_debug_options.print_link_data && key_hit(KEY_LEFT)) + if (g_debug_options.print_link_data && !skipPrint && key_held(KEY_LEFT)) { - globalLinkCable.paused = true; + pauseOnByte = true; + pauseOnPacket = false; } - else if (g_debug_options.print_link_data && key_hit(KEY_RIGHT)) + else if (g_debug_options.print_link_packets && !skipPrint && key_held(KEY_RIGHT)) { - globalLinkCable.paused = false; + pauseOnPacket = true; + pauseOnByte = false; + } + else if (g_debug_options.print_link_data && !skipPrint && key_held(KEY_SELECT)) + { + pauseOnByte = false; + } + else if (g_debug_options.print_link_packets && !skipPrint && key_held(KEY_START)) + { + pauseOnPacket = false; + } + else if ((g_debug_options.print_link_data || g_debug_options.print_link_packets) && key_held(KEY_UP)) + { + skipPrint = true; + pauseOnPacket = false; + pauseOnByte = false; + } + else if ((g_debug_options.print_link_data || g_debug_options.print_link_packets) && key_held(KEY_DOWN)) + { + skipPrint = false; } - if (globalLinkCable.paused && g_debug_options.print_link_data) + if (pauseOnByte && g_debug_options.print_link_data) + { + if (key_hit(KEY_B)) + { + return false; // Even if paused, run once + } + } + + if (pauseOnPacket && newPacket && g_debug_options.print_link_packets) { if (key_hit(KEY_A)) { return false; // Even if paused, run once } } - return globalLinkCable.paused; + + return pauseOnByte || (pauseOnPacket && newPacket); } void LinkConnection::logicState_initConnection() @@ -322,7 +403,6 @@ void LinkConnection::logicState_initConnection() break; case GET_CHECKSUM: - if (inData != 0xFD) { dataOutBuffer[dataOutBufferCurrIndex] = inData; @@ -331,8 +411,8 @@ void LinkConnection::logicState_initConnection() } else if (inData == 0xFD && dataOutBufferCurrIndex > 0) { - LoadCurrGameFromChecksum(); - load_payload(GB_PayloadsFiles::SPECIFICPAYLOADGEN1_RB_EN); + loadCurrGameFromChecksum(); + load_payload(GB_PayloadsFiles::SPECIFICPAYLOADGEN1_EN_R); nextSubState = SEND_SPECIFIC_PAYLOAD; } else @@ -350,7 +430,7 @@ void LinkConnection::logicState_initConnection() break; case SEND_SPECIFIC_PAYLOAD: - if (subStateCounter > 200) // The 200 comes from the Universal Payload + if (subStateCounter > 255) // The 255 comes from the Universal Payload { nextSubState = END; } @@ -378,83 +458,39 @@ void LinkConnection::logicState_packetExchange() { switch (subState) { - - /* - case SEND_PACKET: - - // Output the payload followed by 0xFF while waiting - if (subStateCounter > 12) - { - nextSubState = RECIEVE_PACKET; - } - outData = payloadBuffer[subStateCounter]; - break; - - case WAIT_FOR_RESPONSE: - if (inData != 0xFD) - { - nextSubState = RECIEVE_PACKET; - } - else if (subStateCounter >= 256) - { - lastError = PACKET_TIMED_OUT; - nextSubState = END; - } - outData = 0xFF; - break; - - case RECIEVE_PACKET: - // See if we've already begun recieving the response - if (dataOutBufferCurrIndex > 0) - { - // Are we at the end of the response? - if (dataOutBufferCurrIndex >= 13) - { - nextSubState = END; - } - else - { - dataOutBuffer[dataOutBufferCurrIndex] = inData; - dataOutBufferCurrIndex++; - } - } - // We haven't... see if this is the first byte in the response - - // Let's also make sure that we haven't been sitting here for a long time - - break; -*/ - case BYTE_EXCHANGE: - if (subStateCounter < OUT_PACKET_LENGTH) + if (subStateCounter < TOTAL_PACKET_LENGTH) { // Start with OUT_PACKET_LENGTH of bytes of prep to make sure things are set to go outData = 0xFF; } else { - switch (subStateCounter % OUT_PACKET_LENGTH) + switch (subStateCounter % TOTAL_PACKET_LENGTH) { case 0: outData = 0xFD; break; case 1: - outData = currLinkPacketArr[currLinkPacketArrIndex].command; + outData = currLinkPacketArrIndex; break; case 2: - outData = currLinkPacketArr[currLinkPacketArrIndex].argument[0]; + outData = currLinkPacketArr[currLinkPacketArrIndex].command; break; case 3: - outData = currLinkPacketArr[currLinkPacketArrIndex].argument[1]; + outData = currLinkPacketArr[currLinkPacketArrIndex].argument[0]; break; case 4: - outData = currLinkPacketArr[currLinkPacketArrIndex].pointer >> 8; + outData = currLinkPacketArr[currLinkPacketArrIndex].argument[1]; break; case 5: outData = currLinkPacketArr[currLinkPacketArrIndex].pointer >> 0; break; - case OUT_PACKET_LENGTH - 1: + case 6: + outData = currLinkPacketArr[currLinkPacketArrIndex].pointer >> 8; + break; + case TOTAL_PACKET_LENGTH - 1: currLinkPacketArrIndex++; default: outData = 0xFF; @@ -465,11 +501,17 @@ void LinkConnection::logicState_packetExchange() nextSubState = END; } - if (subStateCounter % OUT_PACKET_LENGTH + 2 == 0) + if (subStateCounter % TOTAL_PACKET_LENGTH == 0) { - // Process packet + newPacket = true; + processPacket(); } - dataOutBuffer[subStateCounter % OUT_PACKET_LENGTH + 2] = inData; + else + { + newPacket = false; + } + + dataOutBuffer[subStateCounter % TOTAL_PACKET_LENGTH] = inData; } break; @@ -499,7 +541,7 @@ void LinkConnection::load_payload(GB_PayloadsFiles payload) this->curr_payload_size = fileSize; } -void LinkConnection::LoadCurrGameFromChecksum() +void LinkConnection::loadCurrGameFromChecksum() { if (((dataOutBuffer[0] + dataOutBuffer[1]) & 0x7F) != dataOutBuffer[3]) { @@ -530,4 +572,36 @@ void LinkConnection::LoadCurrGameFromChecksum() } currROM = GB_ROM_ERROR; return; +} + +bool LinkConnection::processPacket() +{ + int checksum = 0; + LinkPacket &currPacket = currLinkPacketArr[dataOutBuffer[INP_COUNTER_INDEX]]; + for (int i = INP_DELAY_FROM_OUTP; i < INP_LENGTH; i++) + { + if (i != INP_CHECKSUM_INDEX) + { + checksum += dataOutBuffer[i]; + } + } + // Add the read pointer + checksum += ((currPacket.pointer + 8) >> 0) & 0xFF; + checksum += ((currPacket.pointer + 8) >> 8) & 0xFF; + + checksum &= 0x7F; + + byte lsbByte = dataOutBuffer[INP_LSB_INDEX] | dataOutBuffer[INP_LSB_INDEX + 1]; + for (int i = 0; i < 8; i++) + { + currPacket.recievedData[i] = + (dataOutBuffer[INP_DATA_INDEX + i] << 1) | ((lsbByte >> (7 - i)) & 0b1); + } + + if (checksum != dataOutBuffer[INP_CHECKSUM_INDEX]) + { + currPacket.latestError = CHECKSUM_MISMATCH; + return false; + } + return true; } \ No newline at end of file diff --git a/source/script_array.cpp b/source/script_array.cpp index c686e09..aebb6b8 100644 --- a/source/script_array.cpp +++ b/source/script_array.cpp @@ -794,16 +794,19 @@ bool run_conditional(int index) obj_unhide(flag, 0); obj_set_pos(flag, 1.5 * 8, 14 * 8); - LinkPacket packets[6] = { - {CMD_ReadDataRequest, 0x00, 0x00, 0xDCC5}, - {CMD_ReadDataRequest, 0x00, 0x00, 0xDCC5}, - {CMD_ReadDataRequest, 0x00, 0x00, 0xDCC5}, - {CMD_ReadDataRequest, 0x00, 0x00, 0xDCC5}, - {CMD_ReadDataRequest, 0x00, 0x00, 0xDCC5}, - {CMD_ReadDataRequest, 0x00, 0x00, 0xDCC5}, + LinkPacket packets[] = { + {CMD_ReadDataRequest, 0x00, 0x00, 0xDA80}, + {CMD_ReadDataRequest, 0x00, 0x00, 0xDA88}, + {CMD_ReadDataRequest, 0x00, 0x00, 0xDA90}, + {CMD_ReadDataRequest, 0x00, 0x00, 0xDA98}, + {CMD_ReadDataRequest, 0x00, 0x00, 0xDAA0}, + {CMD_ReadDataRequest, 0x00, 0x00, 0xDAA8}, + {CMD_ReadDataRequest, 0x00, 0x00, 0xC5DC} }; - globalLinkCable.paused = true; + + globalLinkCable.skipPrint = false; + globalLinkCable.pauseOnPacket = true; while (true) { globalLinkCable.currLinkPacketArr = packets;