diff --git a/include/link_handler.h b/include/link_handler.h index 7eb3532..95dd532 100644 --- a/include/link_handler.h +++ b/include/link_handler.h @@ -285,7 +285,7 @@ struct LinkPacket PayloadCommand command = CMD_NONE; byte argument[2] = {0x00, 0x00}; u16 pointer = 0xC6DC; - byte packetID = 0; + byte packetID = 0x7F; // Incoming data LinkConnectionError latestError = NO_ERROR; @@ -299,7 +299,7 @@ struct LinkPacket LinkPacket() {}; LinkPacket(PayloadCommand cmd, byte arg1, byte arg2, u16 addr); - LinkPacket(byte *payload, int payloadSize); + void loadSecondaryPayload(byte *payload, int payloadSize); }; class LinkConnection @@ -332,9 +332,14 @@ public: // This MUST be a power of 2! #define LINK_PACKET_ARRAY_SIZE 4 + +// This is lower than the max 0x7F so we can save that value for dummy packets +#define LINK_PACKET_INDEX_MASK 0x3F + LinkPacket linkPacketArr[LINK_PACKET_ARRAY_SIZE]; LinkPacket *currOutgoingPacket; LinkPacket *currIncomingPacket; + LinkPacket dummyPacket = LinkPacket(); byte linkPacketArrIndex = 0; u16 linkPacketDataAddr = 0; u16 linkPacketDataStart = 0; @@ -358,10 +363,10 @@ public: // These are all the Link Commands bool LinkCommand_InitalizeConnection(bool waitForCompletion = true); bool LinkCommand_ReloadCurrentBox(bool waitForCompletion = true); - bool LinkCommand_TransferPokemon(bool waitForCompletion = true); + bool LinkCommand_TransferPokemon(byte payload[], int payloadLength, bool waitForCompletion = true); bool LinkCommand_SoftReset(bool waitForCompletion = true); bool LinkCommand_ModifySRAMAccess(bool enableSRAM, byte SRAMbank, bool waitForCompletion = true); - bool LinkCommand_RunSecondaryPayload(bool waitForCompletion = true); + bool LinkCommand_RunSecondaryPayload(byte payload[], int payloadLength, bool waitForCompletion = true); bool LinkCommand_ReadMemorySection(u16 dataPointer, byte outArray[], int outArraySize, bool waitForCompletion = true); // Some operations are too long to be done within the IRQ. @@ -374,7 +379,8 @@ private: void loadCurrGameFromChecksum(); bool allPacketsProcessed(); bool processPacket(); - void loadNextPacket(); + void consumePacket(); + bool prepareNextPacket(); void waitForEnd(); // Used for debug features diff --git a/source/link_handler.cpp b/source/link_handler.cpp index 9763713..a7215f2 100644 --- a/source/link_handler.cpp +++ b/source/link_handler.cpp @@ -78,9 +78,8 @@ LinkPacket::LinkPacket(PayloadCommand cmd, byte arg1, byte arg2, u16 addr) inUse = true; }; -LinkPacket::LinkPacket(byte *payload, int payloadSize) +void LinkPacket::loadSecondaryPayload(byte *payload, int payloadSize) { - command = CMD_SecondaryPayload; secondaryPayloadData = payload; secondaryPayloadDataSize = payloadSize; for (int i = 0; i < payloadSize; i++) @@ -278,7 +277,7 @@ void LinkConnection::printData() } // 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) + if (g_debug_options.print_link_packets && currIncomingPacket != nullptr) { tte_erase_rect(160, 16, H_MAX, V_MAX); for (int i = 0; i < 4; i++) @@ -448,7 +447,7 @@ void LinkConnection::handleStateLogic() break; case TRADE: - if (subStateCounter > curr_payload_size) + if (subStateCounter >= curr_payload_size) { if (this->gen == 2) { @@ -463,7 +462,7 @@ void LinkConnection::handleStateLogic() break; case MAIL: - if (subStateCounter > 0x186) + if (subStateCounter >= 0x186) { exitState = WAIT_FOR_CHECKSUM_PAYLOAD; } @@ -506,7 +505,7 @@ void LinkConnection::handleStateLogic() break; case SEND_SPECIFIC_PAYLOAD: - if (subStateCounter > 255) // The 255 comes from the Universal Payload + if (subStateCounter >= 255) // The 255 comes from the Universal Payload { exitState = SEND_FIRST_PACKET; } @@ -521,31 +520,15 @@ void LinkConnection::handleStateLogic() break; case SEND_FIRST_PACKET: - // In order to make sure everything is set to go, we need to "send and recieve" one packet - if (subStateCounter % TOTAL_PACKET_LENGTH == 0) - { - nextOutData = 0xFD; - } - else - { - nextOutData = 0x00; - } - if (subStateCounter >= TOTAL_PACKET_LENGTH * 2) - { - exitState = END; - } + // In order to make sure everything is set to go, we need to send a dummy packet. + currOutgoingPacket = &dummyPacket; + nextOutData = 0xFF; + exitState = STANDARD_PACKET_EXCHANGE; break; case PACKET_EXCHANGE: nextOutData = 0xFF; - if (currOutgoingPacket->command == CMD_SecondaryPayload) - { - exitState = SECONDARY_PACKET_EXCHANGE; - } - else - { - exitState = STANDARD_PACKET_EXCHANGE; - } + exitState = STANDARD_PACKET_EXCHANGE; break; case STANDARD_PACKET_EXCHANGE: @@ -580,7 +563,15 @@ void LinkConnection::handleStateLogic() nextOutData = currOutgoingPacket->pointer >> 8; break; case TOTAL_PACKET_LENGTH: - exitState = PROCESS_PACKET; + if (currOutgoingPacket->secondaryPayloadData != nullptr) + { + // We get our response after the GB gets the secondary payload, send that first. + exitState = SECONDARY_PACKET_EXCHANGE; + } + else + { + exitState = PROCESS_PACKET; + } default: nextOutData = 0xFF; break; @@ -602,10 +593,10 @@ void LinkConnection::handleStateLogic() break; case 2: // The command ID matches the saftey byte (0xFF) - nextOutData = currOutgoingPacket->command; + nextOutData = 0xFF; break; case 3: - nextOutData = currOutgoingPacket->secondaryPayloadDataSize; + nextOutData = currOutgoingPacket->secondaryPayloadDataSize + 1; // We need to include the checksum value here as well break; default: // We're through all the constant values, let's do the rest. @@ -617,31 +608,50 @@ void LinkConnection::handleStateLogic() { // Add the checksum and we're done with the packet. nextOutData = currOutgoingPacket->secondaryPayloadSizeChecksum; - exitState = PROCESS_PACKET; } - break; + else + { + // Now it's time to process the packet. Use a dummy packet to flush it out + currOutgoingPacket = &dummyPacket; + exitState = PROCESS_PACKET; + nextOutData = 0xFF; + } } - } - dataOutBuffer[subStateCounter] = inData; break; + } + break; case PROCESS_PACKET: currIncomingPacket = &linkPacketArr[dataOutBuffer[INP_COUNTER_INDEX] % LINK_PACKET_ARRAY_SIZE]; - processPacket(); + if (allPacketsProcessed()) + { + // We have no valid responses that we are looking for, go to the end. + exitState = END; + } + else if (processPacket()) + { + // Processing succeeded, let's load the next one. + exitState = LOAD_NEXT_PACKET; + } + else + { + // The processing failed. Let's move on and try again later + prepareNextPacket(); + exitState = PACKET_EXCHANGE; + } nextOutData = 0xFF; - exitState = LOAD_NEXT_PACKET; break; case LOAD_NEXT_PACKET: - loadNextPacket(); + consumePacket(); + if (allPacketsProcessed()) { exitState = END; } else { - linkPacketArrIndex = (linkPacketArrIndex + 1) & 0x7F; - currOutgoingPacket = &linkPacketArr[linkPacketArrIndex % LINK_PACKET_ARRAY_SIZE]; + prepareNextPacket(); exitState = PACKET_EXCHANGE; } nextOutData = 0xFF; @@ -768,7 +778,7 @@ bool LinkConnection::earlyExit() { if (key_hit(KEY_A)) { - return false; // Even if paused, run once + return false; // Even if paused, run once5 } } @@ -804,12 +814,7 @@ bool LinkConnection::processPacket() (dataOutBuffer[INP_DATA_INDEX + i] << 1) | ((lsbByte >> (7 - i)) & 0b1); } - // The soft reset command has no response, don't expect one. - if (currIncomingPacket->command == CMD_SoftReset) - { - // If this is a soft reset packet, that means that we don't care what we recieve from the final packet. - } - else if (checksum != dataOutBuffer[INP_CHECKSUM_INDEX]) + if (checksum != dataOutBuffer[INP_CHECKSUM_INDEX]) { // The checksum has to match in order for it to be valid, if we've made it this far down the line. currIncomingPacket->latestError = CHECKSUM_MISMATCH; @@ -838,7 +843,7 @@ bool LinkConnection::processPacket() return true; } -void LinkConnection::loadNextPacket() +void LinkConnection::consumePacket() { /* ---------------- @@ -850,14 +855,12 @@ void LinkConnection::loadNextPacket() has all been read and we are finished. ---------------- */ - //currIncomingPacket = &linkPacketArr[dataOutBuffer[INP_COUNTER_INDEX] & (LINK_PACKET_ARRAY_SIZE - 1)]; if (currIncomingPacket->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 - currIncomingPacket->latestError = PACKET_READ; - if (((currIncomingPacket->command == CMD_ReadDataRequest) && (currIncomingPacket->pointer - linkPacketDataStart) < linkPacketDataSize)) + if (currIncomingPacket->command == CMD_ReadDataRequest) { for (int i = 0; i < 8; i++) { @@ -866,13 +869,21 @@ void LinkConnection::loadNextPacket() outDataArrayPtr[(currIncomingPacket->pointer - linkPacketDataStart) + i] = currIncomingPacket->recievedData[i]; } } - *currIncomingPacket = LinkPacket(CMD_ReadDataRequest, 0x00, 0x00, linkPacketDataAddr); - linkPacketDataAddr += 8; + // Do we have more data to read? + if ((linkPacketDataAddr - linkPacketDataStart) < linkPacketDataSize) + { + *currIncomingPacket = LinkPacket(CMD_ReadDataRequest, 0x00, 0x00, linkPacketDataAddr); + linkPacketDataAddr += 8; + } + else + { + // Mark the packet as out of use, we've gotten all the data we need. + currIncomingPacket->inUse = false; + } } else { - // Mark the packet as out of use, we've gotten all the data we need. - currIncomingPacket->inUse = false; + // Command was not a data request, don't do anything. } } else @@ -881,6 +892,25 @@ void LinkConnection::loadNextPacket() } } +bool LinkConnection::prepareNextPacket() +{ + for (int i = 0; i < LINK_PACKET_ARRAY_SIZE - 1; i++) + { + linkPacketArrIndex = (linkPacketArrIndex + 1) & LINK_PACKET_INDEX_MASK; + + LinkPacket *candidate = &linkPacketArr[linkPacketArrIndex % LINK_PACKET_ARRAY_SIZE]; + + if (candidate->inUse && candidate->latestError != PACKET_READ) + { + currOutgoingPacket = candidate; + return true; + } + } + // We're back where we started. Send the dummy packet to get a response. + currOutgoingPacket = &dummyPacket; + return false; +} + bool LinkConnection::allPacketsProcessed() { for (int i = 0; i < LINK_PACKET_ARRAY_SIZE; i++) @@ -903,9 +933,14 @@ void LinkConnection::resetLinkPackets() // Loop the packet index around back to 0 while (linkPacketArrIndex % LINK_PACKET_ARRAY_SIZE != 0) { - linkPacketArrIndex = (linkPacketArrIndex + 1) & 0x7F; + linkPacketArrIndex = (linkPacketArrIndex + 1) & LINK_PACKET_INDEX_MASK; } + // Set the current outgoing packet to be the first in order. + currOutgoingPacket = &linkPacketArr[0]; + // And set the incoming packet to nullptr since we don't know what that is yet. + currIncomingPacket = nullptr; + for (int i = 0; i < 16; i++) { dataOutBuffer[i] = 0; @@ -947,12 +982,15 @@ bool LinkConnection::LinkCommand_ReloadCurrentBox(bool waitForCompletion) return true; }; -bool LinkConnection::LinkCommand_TransferPokemon(bool waitForCompletion) +bool LinkConnection::LinkCommand_TransferPokemon(byte payload[], int payloadLength, bool waitForCompletion) { // Check that box number is correct resetLinkPackets(); - linkPacketArr[0] = LinkPacket(CMD_ReloadCurrentBox, 0x00, 0x00, 0xC6DC); + + // TODO: THIS SHOULD NOT BE HARDCODED TO A BOX + linkPacketArr[0] = LinkPacket(CMD_RunSecondaryPayload, payloadLength + SECONDARY_PAYLOAD_HEADER_SIZE, 0x03, 0xC6DC); + linkPacketArr[0].loadSecondaryPayload(payload, payloadLength); globalLinkCable.startConnection(PACKET_EXCHANGE); if (waitForCompletion) @@ -1001,15 +1039,15 @@ bool LinkConnection::LinkCommand_ModifySRAMAccess(bool enableSRAM, byte SRAMbank return true; }; -bool LinkConnection::LinkCommand_RunSecondaryPayload(bool waitForCompletion) +bool LinkConnection::LinkCommand_RunSecondaryPayload(byte payload[], int payloadLength, bool waitForCompletion) { resetLinkPackets(); byte tempPayload[] = {0x21, 0xA0, 0xC3, 0x75, 0xC9}; byte size = 5; - linkPacketArr[0] = LinkPacket(CMD_RunSecondaryPayload, size, 0x00, 0xC6DC); - linkPacketArr[1] = LinkPacket(tempPayload, size); + linkPacketArr[0] = LinkPacket(CMD_RunSecondaryPayload, size + SECONDARY_PAYLOAD_HEADER_SIZE, 0x00, 0xC6DC); + linkPacketArr[0].loadSecondaryPayload(tempPayload, size); globalLinkCable.startConnection(PACKET_EXCHANGE); if (waitForCompletion) diff --git a/source/script_array.cpp b/source/script_array.cpp index 7a3d2a6..5b92658 100644 --- a/source/script_array.cpp +++ b/source/script_array.cpp @@ -727,7 +727,8 @@ bool run_conditional(int index) link_animation_state(STATE_CONNECTION); if (g_debug_options.ignore_link_cable) { - // TODO - Fix debug data being added here + // TODO - Make this less hardcoded + //party_data.box.loadData(1, ENGLISH, gen1_rb_debug_box_data); } else { @@ -795,10 +796,7 @@ bool run_conditional(int index) globalLinkCable.skipPrint = false; globalLinkCable.pauseOnPacket = true; - //globalLinkCable.LinkCommand_ReadMemorySection(0xDA80, party_data.box_data_array, 1122); - //globalLinkCable.LinkCommand_ModifySRAMAccess(true, 3); - globalLinkCable.LinkCommand_RunSecondaryPayload(); - //globalLinkCable.LinkCommand_SoftReset(); + globalLinkCable.LinkCommand_ReadMemorySection(0xDA80, party_data.box_data_array, 1122); party_data.box.loadData(globalLinkCable.gen, globalLinkCable.lang, party_data.box_data_array); } @@ -884,6 +882,26 @@ bool run_conditional(int index) return true; case CMD_CONTINUE_LINK: + { + byte boxRemovalPayload[31]; + int arrayIndex = 0; + for (int i = 29; i >= 0; i--) + { + if (party_data.box.getGen3Pokemon(i)->isValid) + { + party_data.box.removePokemon(i); + if (!(DONT_TRANSFER_POKEMON_AT_INDEX_X && i == POKEMON_INDEX_TO_SKIP)) + { + boxRemovalPayload[arrayIndex] = i; + arrayIndex++; + } + } + } + boxRemovalPayload[arrayIndex] = 0xFF; + arrayIndex++; + + globalLinkCable.LinkCommand_TransferPokemon(boxRemovalPayload, arrayIndex); + } return true; case CMD_BOX_MENU: @@ -900,6 +918,7 @@ bool run_conditional(int index) return party_data.box.getNumValid() > 0 || g_debug_options.dont_hide_invalid_pkmn; case CMD_CANCEL_LINK: + globalLinkCable.LinkCommand_SoftReset(); return true; case CMD_END_MISSINGNO: diff --git a/source/sound.c b/source/sound.c index 29bf420..3b49eb9 100644 --- a/source/sound.c +++ b/source/sound.c @@ -2,14 +2,20 @@ #include "sound.h" #include "soundbank_bin.h" +//#define INCLUDE_SOUND + + static void sound_irq_handler(void) { + #ifdef INCLUDE_SOUND mmVBlank(); mmFrame(); + #endif } bool sound_init(void) { + #ifdef INCLUDE_SOUND irq_add(II_VBLANK, sound_irq_handler); mm_addr soundbank = (mm_addr)soundbank_bin; @@ -20,49 +26,68 @@ bool sound_init(void) mmInitDefault(soundbank, 16); return true; + #endif } void play_song(u32 song_index, bool loop) { + #ifdef INCLUDE_SOUND mmStart(song_index, loop ? MM_PLAY_LOOP : MM_PLAY_ONCE); + #endif } bool is_song_playing(void) { + #ifdef INCLUDE_SOUND return mmActive(); + #endif } void stop_song(void) { + #ifdef INCLUDE_SOUND mmStop(); + #endif } PTGBSFXHandle play_sound_effect(u32 sound_effect_index) { + #ifdef INCLUDE_SOUND return (PTGBSFXHandle)mmEffect(sound_effect_index); + #endif } void stop_sound_effect(PTGBSFXHandle handle) { + #ifdef INCLUDE_SOUND mmEffectCancel((mm_sfxhand)handle); + #endif } void stop_all_sound_effects(void) { + #ifdef INCLUDE_SOUND mmEffectCancelAll(); + #endif } void release_sound_effect(PTGBSFXHandle handle) { + #ifdef INCLUDE_SOUND mmEffectRelease((mm_sfxhand)handle); + #endif } void play_jingle(u32 jingle_index) { + #ifdef INCLUDE_SOUND mmJingle(jingle_index); + #endif } bool is_jingle_playing(void) { + #ifdef INCLUDE_SOUND return mmActiveSub(); + #endif } \ No newline at end of file