diff --git a/include/link_handler.h b/include/link_handler.h index 07e7268..fe4eb07 100644 --- a/include/link_handler.h +++ b/include/link_handler.h @@ -63,52 +63,102 @@ enum GameBoyROM const GB_PayloadsFiles GameBoyROMPayloads[] = { - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_R, // RED_JP_v0 - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_R11, // RED_JP_v1 - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_EN_R, // RED_EN - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_FR_R, // RED_FR - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_IT_R, // RED_IT - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_DE_R, // RED_DE - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_SP_R, // RED_SP + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_R, // RED_JP_v0 + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_R11, // RED_JP_v1 + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_EN_R, // RED_EN + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_FR_R, // RED_FR + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_IT_R, // RED_IT + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_DE_R, // RED_DE + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_SP_R, // RED_SP GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_GR, // GREEN_JP_v0 GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_GR11, // GREEN_JP_v1 - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_B, // BLUE_JP - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_EN_B, // BLUE_EN - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_FR_B, // BLUE_FR - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_IT_B, // BLUE_IT - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_DE_B, // BLUE_DE - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_SP_B, // BLUE_SP - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_Y, // YELLOW_JP_v0 - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_Y11, // YELLOW_JP_v1 - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_Y12, // YELLOW_JP_v2 - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_Y13, // YELLOW_JP_v3 - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_EN_Y, // YELLOW_EN - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_FR_Y, // YELLOW_FR - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_IT_Y, // YELLOW_IT - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_DE_Y, // YELLOW_DE - GB_PayloadsFiles::SPECIFICPAYLOADGEN1_SP_Y, // 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 + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_B, // BLUE_JP + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_EN_B, // BLUE_EN + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_FR_B, // BLUE_FR + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_IT_B, // BLUE_IT + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_DE_B, // BLUE_DE + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_SP_B, // BLUE_SP + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_Y, // YELLOW_JP_v0 + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_Y11, // YELLOW_JP_v1 + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_Y12, // YELLOW_JP_v2 + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_JP_Y13, // YELLOW_JP_v3 + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_EN_Y, // YELLOW_EN + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_FR_Y, // YELLOW_FR + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_IT_Y, // YELLOW_IT + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_DE_Y, // YELLOW_DE + GB_PayloadsFiles::SPECIFICPAYLOADGEN1_SP_Y, // 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 +}; + +const Language GameBoyROMLanguages[] = + { + JAPANESE, // RED_JP_v0 + JAPANESE, // RED_JP_v1 + ENGLISH, // RED_EN + FRENCH, // RED_FR + ITALIAN, // RED_IT + GERMAN, // RED_DE + SPANISH, // RED_SP + JAPANESE, // GREEN_JP_v0 + JAPANESE, // GREEN_JP_v1 + JAPANESE, // BLUE_JP + ENGLISH, // BLUE_EN + FRENCH, // BLUE_FR + ITALIAN, // BLUE_IT + GERMAN, // BLUE_DE + SPANISH, // BLUE_SP + JAPANESE, // YELLOW_JP_v0 + JAPANESE, // YELLOW_JP_v1 + JAPANESE, // YELLOW_JP_v2 + JAPANESE, // YELLOW_JP_v3 + ENGLISH, // YELLOW_EN + FRENCH, // YELLOW_FR + ITALIAN, // YELLOW_IT + GERMAN, // YELLOW_DE + SPANISH, // YELLOW_SP + JAPANESE, // GOLD_JP_v0 + JAPANESE, // GOLD_JP_v1 + ENGLISH, // GOLD_EN + FRENCH, // GOLD_FR + ITALIAN, // GOLD_IT + GERMAN, // GOLD_DE + SPANISH, // GOLD_SP + KOREAN, // GOLD_KOR + JAPANESE, // SILVER_JP_v0 + JAPANESE, // SILVER_JP_v1 + ENGLISH, // SILVER_EN + FRENCH, // SILVER_FR + ITALIAN, // SILVER_IT + GERMAN, // SILVER_DE + SPANISH, // SILVER_SP + KOREAN, // SILVER_KOR + JAPANESE, // CRYSTAL_JP + ENGLISH, // CRYSTAL_EN + FRENCH, // CRYSTAL_FR + ITALIAN, // CRYSTAL_IT + GERMAN, // CRYSTAL_DE + SPANISH, // CRYSTAL_SP }; // This table has the 3 checksums, followed by the enum value @@ -190,6 +240,9 @@ enum LinkConnectionError NO_ERROR, PACKET_TIMED_OUT, CHECKSUM_MISMATCH, + + PACKET_SUCCESS, + PACKET_READ, }; enum PayloadCommand @@ -247,8 +300,9 @@ public: int globalStateCounter = 0; // The counter for the total number of bytes sent 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 gen = 0; // The generation we are trading with + Language lang = LANGUAGE_UNKNOWN; // The language 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 @@ -258,10 +312,14 @@ public: byte dataOutBuffer[16]; int dataOutBufferCurrIndex = 0; - LinkPacket *currLinkPacketArr; - int currLinkPacketArrTotalCount = 0; - int currLinkPacketArrFilledCount = 0; - int currLinkPacketArrIndex = 0; + // This MUST be a power of 2! +#define LINK_PACKET_ARRAY_SIZE 4 + LinkPacket linkPacketArr[LINK_PACKET_ARRAY_SIZE]; + int linkPacketArrIndex = 0; + u16 linkPacketDataAddr = 0; + u16 linkPacketDataStart = 0; + int linkPacketDataSize = 0; + byte *outDataArrayPtr; 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 @@ -276,6 +334,8 @@ public: void writeData(); void handleStateLogic(); void prepareForNextCycle(); + bool readMemorySection(u16 dataPointer, byte outArray[], int outArraySize); + // Some operations are too long to be done within the IRQ. // So we need to handle them in the main loop instead to avoid data corruption. void handleCartIO(); @@ -284,7 +344,9 @@ private: void loadPayload(GB_PayloadsFiles payload); void loadPayloadByROM(GameBoyROM rom); void loadCurrGameFromChecksum(); + bool allPacketsProcessed(); bool processPacket(); + void loadNextPacket(); // Used for debug features #define LINE_WIDTH 24 diff --git a/source/link_handler.cpp b/source/link_handler.cpp index bda64c7..c305527 100644 --- a/source/link_handler.cpp +++ b/source/link_handler.cpp @@ -98,7 +98,7 @@ void LinkConnection::setup(const u16 *debug_charset) ++cur; } } - else if(g_debug_options.write_cable_data_to_save == WRITE_CABLE_DATA_MODE_CART) + else if (g_debug_options.write_cable_data_to_save == WRITE_CABLE_DATA_MODE_CART) { // before each write, we need to erase the sector. // so, let's do that for the first one before we start writing anything. @@ -111,10 +111,10 @@ void LinkConnection::loadPayload(GB_PayloadsFiles payload) u32 fileSize; u8 decompressionBuffer[0x1000]; const u8 *chunkList[] = { - (const u8 *)GB_Payloads_chunk0_lz10_bin, - (const u8 *)GB_Payloads_chunk1_lz10_bin, - (const u8 *)GB_Payloads_chunk2_lz10_bin, - (const u8 *)GB_Payloads_chunk3_lz10_bin, + (const u8 *)GB_Payloads_chunk0_lz10_bin, + (const u8 *)GB_Payloads_chunk1_lz10_bin, + (const u8 *)GB_Payloads_chunk2_lz10_bin, + (const u8 *)GB_Payloads_chunk3_lz10_bin, }; FileContainerReader reader(chunkList, 4); const u32 fileIndex = (u32)payload; @@ -130,6 +130,7 @@ void LinkConnection::loadPayload(GB_PayloadsFiles payload) void LinkConnection::loadPayloadByROM(GameBoyROM rom) { loadPayload(GameBoyROMPayloads[rom]); + lang = GameBoyROMLanguages[rom]; } void LinkConnection::loadCurrGameFromChecksum() @@ -190,19 +191,19 @@ void LinkConnection::exchangeBytes() // skip the first 6 bytes, which are for human consumption link_cable_array_index += 6; - inData = read_byte_save((0x1000 * link_cable_memory_section_index) + link_cable_array_index); - ++link_cable_array_index; - outData = read_byte_save((0x1000 * link_cable_memory_section_index) + link_cable_array_index); - ++link_cable_array_index; + inData = read_byte_save((0x1000 * link_cable_memory_section_index) + link_cable_array_index); + ++link_cable_array_index; + outData = read_byte_save((0x1000 * link_cable_memory_section_index) + link_cable_array_index); + ++link_cable_array_index; - if(link_cable_array_index >= 0x1000) - { - // if we reached the end of the section, we need to load the next section (if there is one) - ++link_cable_memory_section_index; - link_cable_array_index = 0; - } - break; + if (link_cable_array_index >= 0x1000) + { + // if we reached the end of the section, we need to load the next section (if there is one) + ++link_cable_memory_section_index; + link_cable_array_index = 0; } + break; + } } } @@ -275,7 +276,7 @@ void LinkConnection::printData() { byte tempBuffer[16]; int packetIndex = dataOutBuffer[INP_COUNTER_INDEX]; - LinkPacket &currLinkPacket = currLinkPacketArr[packetIndex]; + LinkPacket &currLinkPacket = linkPacketArr[packetIndex]; tempBuffer[0] = packetIndex; tempBuffer[1] = currLinkPacket.command; @@ -320,9 +321,9 @@ void LinkConnection::writeData() // WARNING: If you want to add or remove fields here, // make sure to keep the number of bytes a clean divider of 4096 (global_memory_buffer_size) - // the next 6 bytes are for human consumption when viewed in a hex editor. - // they can be useful to correlate the current LinkConnection state with the data that was sent over the cable. - // but they're not needed for reconstructing the conversation with load_cable_data_from_save + // the next 6 bytes are for human consumption when viewed in a hex editor. + // they can be useful to correlate the current LinkConnection state with the data that was sent over the cable. + // but they're not needed for reconstructing the conversation with load_cable_data_from_save global_memory_buffer[writeBufferOffset + 0] = (u8)(globalStateCounter >> 8) & 0xFF; global_memory_buffer[writeBufferOffset + 1] = (u8)(globalStateCounter >> 0) & 0xFF; global_memory_buffer[writeBufferOffset + 2] = (u8)enterState; @@ -330,14 +331,14 @@ void LinkConnection::writeData() global_memory_buffer[writeBufferOffset + 4] = (u8)(subStateCounter >> 0) & 0xFF; global_memory_buffer[writeBufferOffset + 5] = (u8)exitState; - // actual data bytes start here. - global_memory_buffer[writeBufferOffset + 6] = inData; - global_memory_buffer[writeBufferOffset + 7] = outData; + // actual data bytes start here. + global_memory_buffer[writeBufferOffset + 6] = inData; + global_memory_buffer[writeBufferOffset + 7] = outData; - writeBufferOffset += 8; + writeBufferOffset += 8; - break; - } + break; + } } } @@ -513,57 +514,39 @@ void LinkConnection::handleStateLogic() nextOutData = 0xFD; break; case 1: - nextOutData = currLinkPacketArrIndex; + nextOutData = linkPacketArrIndex; break; case 2: - nextOutData = currLinkPacketArr[currLinkPacketArrIndex].command; + nextOutData = linkPacketArr[linkPacketArrIndex].command; break; case 3: - nextOutData = currLinkPacketArr[currLinkPacketArrIndex].argument[0]; + nextOutData = linkPacketArr[linkPacketArrIndex].argument[0]; break; case 4: - nextOutData = currLinkPacketArr[currLinkPacketArrIndex].argument[1]; + nextOutData = linkPacketArr[linkPacketArrIndex].argument[1]; break; case 5: - nextOutData = currLinkPacketArr[currLinkPacketArrIndex].pointer >> 0; + nextOutData = linkPacketArr[linkPacketArrIndex].pointer >> 0; break; case 6: - nextOutData = currLinkPacketArr[currLinkPacketArrIndex].pointer >> 8; + nextOutData = linkPacketArr[linkPacketArrIndex].pointer >> 8; break; case TOTAL_PACKET_LENGTH - 1: - currLinkPacketArrIndex++; + linkPacketArrIndex = (linkPacketArrIndex + 1) % LINK_PACKET_ARRAY_SIZE; default: nextOutData = 0xFF; break; } - if (currLinkPacketArrIndex >= currLinkPacketArrFilledCount + 2) + if (allPacketsProcessed()) { exitState = PRINT_LAST_PACKET; } - else if (currLinkPacketArrIndex >= currLinkPacketArrFilledCount) - { - // We don't want to send another packet, we just want the data back - nextOutData = 0xFF; - } - if ((subStateCounter % TOTAL_PACKET_LENGTH == 0) && (currLinkPacketArrIndex > 1)) + if (subStateCounter % TOTAL_PACKET_LENGTH == 0) { newPacket = true; - - if (processPacket() == false) - { - // Packet failed, we need to put it back in the queue - if (currLinkPacketArrFilledCount < currLinkPacketArrTotalCount) - { - currLinkPacketArr[currLinkPacketArrFilledCount] = currLinkPacketArr[currLinkPacketArrIndex]; - currLinkPacketArrFilledCount++; - } - else - { - // We have filled the packet array. Set - } - } + processPacket(); } else { @@ -573,7 +556,7 @@ void LinkConnection::handleStateLogic() dataOutBuffer[subStateCounter % TOTAL_PACKET_LENGTH] = inData; } break; - + case PRINT_LAST_PACKET: nextOutData = 0xFF; exitState = END; @@ -602,10 +585,14 @@ void LinkConnection::prepareForNextCycle() subStateChanged = false; } + if (newPacket) + { + loadNextPacket(); + } + globalStateCounter++; enterState = exitState; outData = nextOutData; - } /* @@ -634,9 +621,9 @@ void LinkConnection::handleCartIO() memmove(global_memory_buffer, global_memory_buffer + curBufDepth, writeBufferOffset); u8 *curWriteBuf = writeBuffer; - const u8 * const endWriteBuf = writeBuffer + curBufDepth; + const u8 *const endWriteBuf = writeBuffer + curBufDepth; - while(curWriteBuf < endWriteBuf) + while (curWriteBuf < endWriteBuf) { // make sure not to write beyond the current flash sector's boundaries. We'll need an erase_sector() call before // we write to the next sector. @@ -648,7 +635,7 @@ void LinkConnection::handleCartIO() curBufDepth -= bytesToWrite; link_cable_array_index += bytesToWrite; - if(link_cable_array_index >= 0x1000) + if (link_cable_array_index >= 0x1000) { // we have reached the end of our current sector. Let's erase the next one. link_cable_array_index = 0; @@ -711,9 +698,9 @@ bool LinkConnection::earlyExit() bool LinkConnection::processPacket() { int checksum = 0; - LinkPacket &currPacket = currLinkPacketArr[dataOutBuffer[INP_COUNTER_INDEX]]; + LinkPacket &currPacket = linkPacketArr[dataOutBuffer[INP_COUNTER_INDEX] & (LINK_PACKET_ARRAY_SIZE - 1)]; - for (int i = INP_DELAY_FROM_OUTP; i < INP_LENGTH; i++) + for (int i = INP_COUNTER_INDEX; i < INP_LENGTH; i++) { if (i != INP_CHECKSUM_INDEX) { @@ -738,5 +725,65 @@ bool LinkConnection::processPacket() currPacket.latestError = CHECKSUM_MISMATCH; return false; } + currPacket.latestError = PACKET_SUCCESS; + return true; +} + +void LinkConnection::loadNextPacket() +{ + /* + ---------------- + For this part, the LinkConnection has an array of 4 packets that it will send. + The current packet will be sent and a response will be recieved at the same time. If the recieved packet is + successful, the data will be moved to the outArray and the packet will be replaced by a packet asking for the next data section. + If the packet was not successful it will stay in the list and be ran again down the line. If packets have been sent for all the + data sections, a completed packet will be replaced with an empty packet. Once the array is full of empty packets, the data + has all been read and we are finished. + ---------------- +*/ + LinkPacket &currPacket = linkPacketArr[dataOutBuffer[INP_COUNTER_INDEX] & (LINK_PACKET_ARRAY_SIZE - 1)]; + if (currPacket.latestError == PACKET_SUCCESS) + { + // Packet was successful, Find which packet sent it and mark it. + // If this was data, then save the data and replace it with the next one in line + + currPacket.latestError = PACKET_READ; + if (((currPacket.pointer - linkPacketDataStart) < linkPacketDataSize)) + { + memcpy(&outDataArrayPtr[currPacket.pointer - linkPacketDataStart], &currPacket.recievedData[0], 8); + currPacket = {CMD_ReadDataRequest, 0x00, 0x00, linkPacketDataAddr}; + linkPacketDataAddr += 8; + } + } + else + { + // Packet failed, don't remove it. + } +} + +bool LinkConnection::allPacketsProcessed() +{ + for (int i = 0; i < LINK_PACKET_ARRAY_SIZE; i++) + { + if (linkPacketArr[i].latestError != PACKET_READ) + { + return false; + } + } + return true; +} + +bool LinkConnection::readMemorySection(u16 dataPointer, byte outArray[], int outArraySize) +{ + linkPacketDataStart = dataPointer; + linkPacketDataSize = outArraySize; + linkPacketDataAddr = dataPointer; + outDataArrayPtr = outArray; + + for (int i = 0; i < LINK_PACKET_ARRAY_SIZE; i++) + { + linkPacketArr[i] = {CMD_ReadDataRequest, 0x00, 0x00, linkPacketDataAddr}; + linkPacketDataAddr += 8; + } return true; } \ No newline at end of file diff --git a/source/script_array.cpp b/source/script_array.cpp index 8cc330c..30ead82 100644 --- a/source/script_array.cpp +++ b/source/script_array.cpp @@ -797,34 +797,25 @@ bool run_conditional(int index) obj_unhide(flag, 0); obj_set_pos(flag, 1.5 * 8, 14 * 8); - 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}, - }; - - globalLinkCable.skipPrint = false; - globalLinkCable.pauseOnPacket = true; - while (true) + if (g_debug_options.print_link_packets) { - globalLinkCable.currLinkPacketArr = packets; - globalLinkCable.currLinkPacketArrFilledCount = 6; - globalLinkCable.currLinkPacketArrIndex = 0; - - globalLinkCable.startConnection(PACKET_EXCHANGE); - while (globalLinkCable.enterState != END) - { - globalLinkCable.handleCartIO(); - VBlankIntrWait(); - } + globalLinkCable.skipPrint = false; + globalLinkCable.pauseOnPacket = true; } + + globalLinkCable.readMemorySection(0xDA80, party_data.box_data_array, 1122); + globalLinkCable.startConnection(PACKET_EXCHANGE); + while (globalLinkCable.enterState != END) + { + globalLinkCable.handleCartIO(); + VBlankIntrWait(); + } + party_data.box.loadData(globalLinkCable.gen, globalLinkCable.lang, party_data.box_data_array); } reload_textbox_background(); load_flex_background(FLEXBG_FENNEL, 2); link_animation_state(0); + return true; case CMD_IMPORT_POKEMON: