diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 880853546d..82eceae4e7 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -290,6 +290,7 @@ void Stop() // - Hammertime! g_video_backend->Video_ExitLoop(); } + Wiimote::ResetAllWiimotes(); ResetRumble(); #ifdef USE_MEMORYWATCHER diff --git a/Source/Core/Core/HW/Wiimote.h b/Source/Core/Core/HW/Wiimote.h index 0d23637563..10c953484e 100644 --- a/Source/Core/Core/HW/Wiimote.h +++ b/Source/Core/Core/HW/Wiimote.h @@ -63,6 +63,8 @@ enum class InitializeMode // The Real Wii Remote sends report every ~5ms (200 Hz). constexpr int UPDATE_FREQ = 200; +// Custom channel ID used in ControlChannel to indicate disconnects +constexpr int DOLPHIN_DISCONNET_CONTROL_CHANNEL = 99; void Shutdown(); void Initialize(InitializeMode init_mode); diff --git a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp index 76d5848336..8e1c6945c1 100644 --- a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp @@ -291,18 +291,7 @@ void Wiimote::HandleWriteData(const OutputReportWriteData& wd) else { std::copy_n(wd.data, wd.size, m_eeprom.data.data() + address); - - // Write mii data to file - if (address >= 0x0FCA && address < 0x12C0) - { - // TODO: Only write parts of the Mii block. - // TODO: Use different files for different wiimote numbers. - std::ofstream file; - File::OpenFStream(file, File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/mii.bin", - std::ios::binary | std::ios::out); - file.write((char*)m_eeprom.data.data() + 0x0FCA, 0x02f0); - file.close(); - } + m_eeprom_dirty = true; } } break; @@ -486,18 +475,6 @@ bool Wiimote::ProcessReadDataRequest() } else { - // Mii block handling: - // TODO: different filename for each wiimote? - if (m_read_request.address >= 0x0FCA && m_read_request.address < 0x12C0) - { - // TODO: Only read the Mii block parts required - std::ifstream file; - File::OpenFStream(file, (File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/mii.bin").c_str(), - std::ios::binary | std::ios::in); - file.read((char*)m_eeprom.data.data() + 0x0FCA, 0x02f0); - file.close(); - } - // Read memory to be sent to Wii std::copy_n(m_eeprom.data.data() + m_read_request.address, bytes_to_read, reply.data); reply.size_minus_one = bytes_to_read - 1; diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index fcfbdb71c3..5ffc8aaf98 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -12,6 +12,7 @@ #include "Common/CommonTypes.h" #include "Common/Config/Config.h" +#include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/MathUtil.h" #include "Common/MsgHandler.h" @@ -77,50 +78,86 @@ void Wiimote::Reset() m_speaker_mute = false; // EEPROM + std::string eeprom_file = (File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/" + GetName() + ".bin"); + if (m_eeprom_dirty) + { + // Write out existing EEPROM + INFO_LOG(WIIMOTE, "Wrote EEPROM for %s", GetName().c_str()); + std::ofstream file; + File::OpenFStream(file, eeprom_file, std::ios::binary | std::ios::out); + file.write(reinterpret_cast(m_eeprom.data.data()), EEPROM_FREE_SIZE); + file.close(); + + m_eeprom_dirty = false; + } m_eeprom = {}; - // IR calibration: - std::array ir_calibration = { - // Point 1 - IR_LOW_X & 0xFF, - IR_LOW_Y & 0xFF, - // Mix - ((IR_LOW_Y & 0x300) >> 2) | ((IR_LOW_X & 0x300) >> 4) | ((IR_LOW_Y & 0x300) >> 6) | - ((IR_HIGH_X & 0x300) >> 8), - // Point 2 - IR_HIGH_X & 0xFF, - IR_LOW_Y & 0xFF, - // Point 3 - IR_HIGH_X & 0xFF, - IR_HIGH_Y & 0xFF, - // Mix - ((IR_HIGH_Y & 0x300) >> 2) | ((IR_HIGH_X & 0x300) >> 4) | ((IR_HIGH_Y & 0x300) >> 6) | - ((IR_LOW_X & 0x300) >> 8), - // Point 4 - IR_LOW_X & 0xFF, - IR_HIGH_Y & 0xFF, - // Checksum - 0x00, - }; - UpdateCalibrationDataChecksum(ir_calibration, 1); - m_eeprom.ir_calibration_1 = ir_calibration; - m_eeprom.ir_calibration_2 = ir_calibration; + if (File::Exists(eeprom_file)) + { + // Read existing EEPROM + std::ifstream file; + File::OpenFStream(file, eeprom_file, std::ios::binary | std::ios::in); + file.read(reinterpret_cast(m_eeprom.data.data()), EEPROM_FREE_SIZE); + file.close(); + } + else + { + // Load some default data. - // Accel calibration: - // Last byte is a checksum. - std::array accel_calibration = { - ACCEL_ZERO_G, ACCEL_ZERO_G, ACCEL_ZERO_G, 0, ACCEL_ONE_G, ACCEL_ONE_G, ACCEL_ONE_G, 0, 0, 0, - }; - UpdateCalibrationDataChecksum(accel_calibration, 1); - m_eeprom.accel_calibration_1 = accel_calibration; - m_eeprom.accel_calibration_2 = accel_calibration; + // IR calibration: + std::array ir_calibration = { + // Point 1 + IR_LOW_X & 0xFF, + IR_LOW_Y & 0xFF, + // Mix + ((IR_LOW_Y & 0x300) >> 2) | ((IR_LOW_X & 0x300) >> 4) | ((IR_LOW_Y & 0x300) >> 6) | + ((IR_HIGH_X & 0x300) >> 8), + // Point 2 + IR_HIGH_X & 0xFF, + IR_LOW_Y & 0xFF, + // Point 3 + IR_HIGH_X & 0xFF, + IR_HIGH_Y & 0xFF, + // Mix + ((IR_HIGH_Y & 0x300) >> 2) | ((IR_HIGH_X & 0x300) >> 4) | ((IR_HIGH_Y & 0x300) >> 6) | + ((IR_LOW_X & 0x300) >> 8), + // Point 4 + IR_LOW_X & 0xFF, + IR_HIGH_Y & 0xFF, + // Checksum + 0x00, + }; + UpdateCalibrationDataChecksum(ir_calibration, 1); + m_eeprom.ir_calibration_1 = ir_calibration; + m_eeprom.ir_calibration_2 = ir_calibration; - // TODO: Is this needed? - // Data of unknown purpose: - constexpr std::array EEPROM_DATA_16D0 = {0x00, 0x00, 0x00, 0xFF, 0x11, 0xEE, 0x00, 0x00, - 0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99, - 0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13}; - m_eeprom.unk_2 = EEPROM_DATA_16D0; + // Accel calibration: + // Last byte is a checksum. + std::array accel_calibration = { + ACCEL_ZERO_G, ACCEL_ZERO_G, ACCEL_ZERO_G, 0, ACCEL_ONE_G, ACCEL_ONE_G, ACCEL_ONE_G, 0, 0, 0, + }; + UpdateCalibrationDataChecksum(accel_calibration, 1); + m_eeprom.accel_calibration_1 = accel_calibration; + m_eeprom.accel_calibration_2 = accel_calibration; + + // TODO: Is this needed? + // Data of unknown purpose: + constexpr std::array EEPROM_DATA_16D0 = { + 0x00, 0x00, 0x00, 0xFF, 0x11, 0xEE, 0x00, 0x00, 0x33, 0xCC, 0x44, 0xBB, + 0x00, 0x00, 0x66, 0x99, 0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13}; + m_eeprom.unk_2 = EEPROM_DATA_16D0; + + std::string mii_file = File::GetUserPath(D_SESSION_WIIROOT_IDX) + "/mii.bin"; + if (File::Exists(mii_file)) + { + // Import from the existing mii.bin file, if present + std::ifstream file; + File::OpenFStream(file, mii_file, std::ios::binary | std::ios::in); + file.read(reinterpret_cast(m_eeprom.mii_data_1.data()), m_eeprom.mii_data_1.size()); + m_eeprom.mii_data_2 = m_eeprom.mii_data_1; + file.close(); + } + } m_read_request = {}; @@ -245,6 +282,8 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index) std::string Wiimote::GetName() const { + if (m_index == WIIMOTE_BALANCE_BOARD) + return "BalanceBoard"; return fmt::format("Wiimote{}", 1 + m_index); } @@ -533,7 +572,7 @@ void Wiimote::SendDataReport() void Wiimote::ControlChannel(const u16 channel_id, const void* data, u32 size) { // Check for custom communication - if (99 == channel_id) + if (channel_id == ::Wiimote::DOLPHIN_DISCONNET_CONTROL_CHANNEL) { // Wii Remote disconnected. Reset(); diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index 0f627e619e..1f13d29d2e 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -291,6 +291,7 @@ private: bool m_is_motion_plus_attached; + bool m_eeprom_dirty = false; ReadRequest m_read_request; UsableEEPROMData m_eeprom; diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp index a23752b792..09806a3808 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp @@ -143,7 +143,7 @@ void Wiimote::ClearReadQueue() void Wiimote::ControlChannel(const u16 channel, const void* const data, const u32 size) { // Check for custom communication - if (channel == 99) + if (channel == ::Wiimote::DOLPHIN_DISCONNET_CONTROL_CHANNEL) { if (m_really_disconnect) { diff --git a/Source/Core/Core/IOS/MIOS.cpp b/Source/Core/Core/IOS/MIOS.cpp index c94c2ee957..d7de03d494 100644 --- a/Source/Core/Core/IOS/MIOS.cpp +++ b/Source/Core/Core/IOS/MIOS.cpp @@ -20,6 +20,7 @@ #include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/Memmap.h" #include "Core/HW/SystemTimers.h" +#include "Core/HW/Wiimote.h" #include "Core/Host.h" #include "Core/PowerPC/PPCSymbolDB.h" #include "Core/PowerPC/PowerPC.h" @@ -35,6 +36,7 @@ static void ReinitHardware() // MIOS appears to only reset the DI and the PPC. DVDInterface::Reset(); PowerPC::Reset(); + Wiimote::ResetAllWiimotes(); // Note: this is specific to Dolphin and is required because we initialised it in Wii mode. DSP::Reinit(SConfig::GetInstance().bDSPHLE); DSP::GetDSPEmulator()->Initialize(SConfig::GetInstance().bWii, SConfig::GetInstance().bDSPThread); diff --git a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp index c35d094061..509347088c 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp @@ -218,7 +218,8 @@ void WiimoteDevice::EventConnectionAccepted() void WiimoteDevice::EventDisconnect() { // Send disconnect message to plugin - Wiimote::ControlChannel(m_connection_handle & 0xFF, 99, nullptr, 0); + Wiimote::ControlChannel(m_connection_handle & 0xFF, Wiimote::DOLPHIN_DISCONNET_CONTROL_CHANNEL, + nullptr, 0); m_connection_state = ConnectionState::Inactive;