diff --git a/Source/Core/Core/HW/WiimoteCommon/WiimoteReport.h b/Source/Core/Core/HW/WiimoteCommon/WiimoteReport.h index 3a7da9188a..38b00e89c1 100644 --- a/Source/Core/Core/HW/WiimoteCommon/WiimoteReport.h +++ b/Source/Core/Core/HW/WiimoteCommon/WiimoteReport.h @@ -405,7 +405,10 @@ struct wm_write_data u8 rumble : 1; u8 space : 2; // see WM_SPACE_* u8 : 5; - u8 address[3]; + // used only for register space (i2c bus) + u8 slave_address; + // big endian: + u8 address[2]; u8 size; u8 data[16]; }; @@ -424,8 +427,11 @@ struct wm_read_data u8 rumble : 1; u8 space : 2; // see WM_SPACE_* u8 : 5; - u8 address[3]; - u16 size; + // used only for register space (i2c bus) + u8 slave_address; + // big endian: + u8 address[2]; + u8 size[2]; }; static_assert(sizeof(wm_read_data) == 6, "Wrong size"); diff --git a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp index bec9920b00..2dd95780b1 100644 --- a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp @@ -44,8 +44,9 @@ void Wiimote::ReportMode(const wm_report_mode* const dr) // DEBUG_LOG(WIIMOTE, " All The Time: %x", dr->all_the_time); // DEBUG_LOG(WIIMOTE, " Mode: 0x%02x", dr->mode); + // TODO: what does the 'all_the_time' bit really do? // m_reporting_auto = dr->all_the_time; - m_reporting_auto = dr->continuous; // this right? + m_reporting_auto = dr->continuous; m_reporting_mode = dr->mode; // m_reporting_channel = _channelID; // this is set in every Interrupt/Control Channel now @@ -126,8 +127,14 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack) break; case RT_WRITE_SPEAKER_DATA: // 0x18 + // Not sure if speaker mute stops the bus write on real hardware, but it's not that important if (!m_speaker_mute) - Wiimote::SpeakerData(reinterpret_cast(sr->data)); + { + auto sd = reinterpret_cast(sr->data); + if (sd->length > 20) + PanicAlert("EmuWiimote: bad speaker data length!"); + m_i2c_bus.BusWrite(0x51, 0x00, sd->length, sd->data); + } return; // no ack break; @@ -218,10 +225,9 @@ void Wiimote::RequestStatus(const wm_request_status* const rs) /* Write data to Wiimote and Extensions registers. */ void Wiimote::WriteData(const wm_write_data* const wd) { - u32 address = Common::swap24(wd->address); + u16 address = Common::swap16(wd->address); - // ignore the 0x010000 bit - address &= ~0x010000; + INFO_LOG(WIIMOTE, "Wiimote::WriteData: 0x%02x @ 0x%02x (%d)", wd->space, address, wd->size); if (wd->size > 16) { @@ -261,8 +267,8 @@ void Wiimote::WriteData(const wm_write_data* const wd) { // Write to Control Register - // TODO: generate a writedata error reply for wrong number of bytes written.. - m_i2c_bus.BusWrite(address >> 17, address & 0xff, wd->size, wd->data); + // TODO: generate a writedata error reply, 7 == no such slave (no ack) + m_i2c_bus.BusWrite(wd->slave_address >> 1, address & 0xff, wd->size, wd->data); return; @@ -290,11 +296,10 @@ void Wiimote::WriteData(const wm_write_data* const wd) /* Read data from Wiimote and Extensions registers. */ void Wiimote::ReadData(const wm_read_data* const rd) { - u32 address = Common::swap24(rd->address); + u16 address = Common::swap16(rd->address); u16 size = Common::swap16(rd->size); - // ignore the 0x010000 bit - address &= 0xFEFFFF; + //INFO_LOG(WIIMOTE, "Wiimote::ReadData: %d @ 0x%02x @ 0x%02x (%d)", rd->space, rd->slave_address, address, size); ReadRequest rr; u8* const block = new u8[size]; @@ -312,7 +317,8 @@ void Wiimote::ReadData(const wm_read_data* const rd) delete[] block; return; } - // generate a read error + + // generate a read error, even if the start of the block is readable a real wiimote just sends error code 8 size = 0; } @@ -337,23 +343,24 @@ void Wiimote::ReadData(const wm_read_data* const rd) { // Read from Control Register - m_i2c_bus.BusRead(address >> 17, address & 0xff, rd->size, block); - // TODO: generate read errors + m_i2c_bus.BusRead(rd->slave_address >> 1, address & 0xff, size, block); + // TODO: generate read errors, 7 == no such slave (no ack) } break; default: - PanicAlert("WmReadData: unimplemented parameters (size: %i, address: 0x%x)!", size, rd->space); + PanicAlert("Wiimote::ReadData: unimplemented address space (space: 0x%x)!", rd->space); break; } - // want the requested address, not the above modified one - rr.address = Common::swap24(rd->address); + rr.address = address; rr.size = size; - // rr.channel = _channelID; rr.position = 0; rr.data = block; + // TODO: read requests suppress normal input reports + // TODO: if there is currently an active read request ignore new ones + // send up to 16 bytes SendReadDataReply(rr); @@ -391,7 +398,7 @@ void Wiimote::SendReadDataReply(ReadRequest& request) { // Limit the amt to 16 bytes // AyuanX: the MTU is 640B though... what a waste! - const int amt = std::min((unsigned int)16, request.size); + const int amt = std::min((u16)16, request.size); // no error reply->error = 0; @@ -432,13 +439,13 @@ void Wiimote::DoState(PointerWrap& p) p.Do(m_shake_step); p.Do(m_sensor_bar_on_top); p.Do(m_status); - p.Do(m_adpcm_state); + p.Do(m_speaker_logic.adpcm_state); p.Do(m_ext_logic.ext_key); p.DoArray(m_eeprom); p.Do(m_reg_motion_plus); p.Do(m_camera_logic.reg_data); p.Do(m_ext_logic.reg_data); - p.Do(m_reg_speaker); + p.Do(m_speaker_logic.reg_data); // Do 'm_read_requests' queue { diff --git a/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp b/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp index fb66bfb093..257f82741c 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Speaker.cpp @@ -68,39 +68,40 @@ void stopdamnwav() } #endif -void Wiimote::SpeakerData(const wm_speaker_data* sd) +void Wiimote::SpeakerLogic::SpeakerData(const u8* data, int length) { if (!SConfig::GetInstance().m_WiimoteEnableSpeaker) return; - if (m_reg_speaker.volume == 0 || m_reg_speaker.sample_rate == 0 || sd->length == 0) + if (reg_data.volume == 0 || reg_data.sample_rate == 0 || + length == 0) return; // TODO consider using static max size instead of new - std::unique_ptr samples(new s16[sd->length * 2]); + std::unique_ptr samples(new s16[length * 2]); unsigned int sample_rate_dividend, sample_length; u8 volume_divisor; - if (m_reg_speaker.format == 0x40) + if (reg_data.format == 0x40) { // 8 bit PCM - for (int i = 0; i < sd->length; ++i) + for (int i = 0; i < length; ++i) { - samples[i] = ((s16)(s8)sd->data[i]) << 8; + samples[i] = ((s16)(s8)data[i]) << 8; } // Following details from http://wiibrew.org/wiki/Wiimote#Speaker sample_rate_dividend = 12000000; volume_divisor = 0xff; - sample_length = (unsigned int)sd->length; + sample_length = (unsigned int)length; } - else if (m_reg_speaker.format == 0x00) + else if (reg_data.format == 0x00) { // 4 bit Yamaha ADPCM (same as dreamcast) - for (int i = 0; i < sd->length; ++i) + for (int i = 0; i < length; ++i) { - samples[i * 2] = adpcm_yamaha_expand_nibble(m_adpcm_state, (sd->data[i] >> 4) & 0xf); - samples[i * 2 + 1] = adpcm_yamaha_expand_nibble(m_adpcm_state, sd->data[i] & 0xf); + samples[i * 2] = adpcm_yamaha_expand_nibble(adpcm_state, (data[i] >> 4) & 0xf); + samples[i * 2 + 1] = adpcm_yamaha_expand_nibble(adpcm_state, data[i] & 0xf); } // Following details from http://wiibrew.org/wiki/Wiimote#Speaker @@ -109,19 +110,20 @@ void Wiimote::SpeakerData(const wm_speaker_data* sd) // 0 - 127 // TODO: does it go beyond 127 for format == 0x40? volume_divisor = 0x7F; - sample_length = (unsigned int)sd->length * 2; + sample_length = (unsigned int)length * 2; } else { - ERROR_LOG(IOS_WIIMOTE, "Unknown speaker format %x", m_reg_speaker.format); + ERROR_LOG(IOS_WIIMOTE, "Unknown speaker format %x", reg_data.format); return; } // Speaker Pan - unsigned int vol = (unsigned int)(m_options->numeric_settings[0]->GetValue() * 100); + // TODO: fix + unsigned int vol = 0;//(unsigned int)(m_options->numeric_settings[0]->GetValue() * 100); - unsigned int sample_rate = sample_rate_dividend / m_reg_speaker.sample_rate; - float speaker_volume_ratio = (float)m_reg_speaker.volume / volume_divisor; + unsigned int sample_rate = sample_rate_dividend / reg_data.sample_rate; + float speaker_volume_ratio = (float)reg_data.volume / volume_divisor; unsigned int left_volume = (unsigned int)((128 + vol) * speaker_volume_ratio); unsigned int right_volume = (unsigned int)((128 - vol) * speaker_volume_ratio); @@ -147,12 +149,12 @@ void Wiimote::SpeakerData(const wm_speaker_data* sd) File::OpenFStream(ofile, "rmtdump.bin", ofile.binary | ofile.out); wav.Start("rmtdump.wav", 6000); } - wav.AddMonoSamples(samples.get(), sd->length * 2); + wav.AddMonoSamples(samples.get(), length * 2); if (ofile.good()) { - for (int i = 0; i < sd->length; i++) + for (int i = 0; i < length; i++) { - ofile << sd->data[i]; + ofile << data[i]; } } num++; diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 93c985b300..f71cb55470 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -328,9 +328,9 @@ void Wiimote::Reset() memcpy(m_eeprom + 0x16D0, eeprom_data_16D0, sizeof(eeprom_data_16D0)); // set up the register - memset(&m_reg_speaker, 0, sizeof(m_reg_speaker)); // TODO: kill/move these + memset(&m_speaker_logic.reg_data, 0, sizeof(m_speaker_logic.reg_data)); memset(&m_camera_logic.reg_data, 0, sizeof(m_camera_logic.reg_data)); memset(&m_ext_logic.reg_data, 0, sizeof(m_ext_logic.reg_data)); @@ -361,14 +361,15 @@ void Wiimote::Reset() } // Yamaha ADPCM state initialize - m_adpcm_state.predictor = 0; - m_adpcm_state.step = 127; + m_speaker_logic.adpcm_state.predictor = 0; + m_speaker_logic.adpcm_state.step = 127; // Initialize i2c bus // TODO: kill magic numbers m_i2c_bus.Reset(); m_i2c_bus.AddSlave(0x58, &m_camera_logic); m_i2c_bus.AddSlave(0x52, &m_ext_logic); + m_i2c_bus.AddSlave(0x51, &m_speaker_logic); } Wiimote::Wiimote(const unsigned int index) : m_index(index), ir_sin(0), ir_cos(1) diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index 622b6857aa..ccd7337b2d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -255,6 +255,8 @@ public: { INFO_LOG(WIIMOTE, "i2c bus read: 0x%02x @ 0x%02x (%d)", slave_addr, addr, count); + // TODO: reads loop around at end of address space (0xff) + auto it = m_slaves.find(slave_addr); if (m_slaves.end() != it) return it->second->BusRead(addr, count, data_out); @@ -266,6 +268,8 @@ public: { INFO_LOG(WIIMOTE, "i2c bus write: 0x%02x @ 0x%02x (%d)", slave_addr, addr, count); + // TODO: writes loop around at end of address space (0xff) + auto it = m_slaves.find(slave_addr); if (m_slaves.end() != it) return it->second->BusWrite(addr, count, data_in); @@ -396,10 +400,49 @@ private: } m_ext_logic; + struct SpeakerLogic : public I2CSlave + { + struct + { + // Speaker reports result in a write of samples to addr 0x00 (which also plays sound) + u8 speaker_data; + u8 unk_1; + u8 format; + // seems to always play at 6khz no matter what this is set to? + // or maybe it only applies to pcm input + u16 sample_rate; + u8 volume; + u8 unk_6; + u8 unk_7; + u8 play; + u8 unk_9; + } reg_data; + + ADPCMState adpcm_state; + + void SpeakerData(const u8* data, int length); + + int BusRead(u8 addr, int count, u8* data_out) override + { + return raw_read(®_data, addr, count, data_out); + } + + int BusWrite(u8 addr, int count, const u8* data_in) override + { + if (0x00 == addr) + { + SpeakerData(data_in, count); + return count; + } + else + return raw_write(®_data, addr, count, data_in); + } + + } m_speaker_logic; + struct ReadRequest { - // u16 channel; - u32 address, size, position; + u16 address, size, position; u8* data; }; @@ -409,7 +452,6 @@ private: void ReadData(const wm_read_data* rd); void WriteData(const wm_write_data* wd); void SendReadDataReply(ReadRequest& request); - void SpeakerData(const wm_speaker_data* sd); bool NetPlay_GetWiimoteData(int wiimote, u8* data, u8 size, u8 reporting_mode); // control groups @@ -463,8 +505,6 @@ private: wm_status_report m_status; - ADPCMState m_adpcm_state; - // read data request queue // maybe it isn't actually a queue // maybe read requests cancel any current requests @@ -485,21 +525,6 @@ private: u8 ext_identifier[6]; } m_reg_motion_plus; - struct SpeakerReg - { - u8 unused_0; - u8 unk_1; - u8 format; - // seems to always play at 6khz no matter what this is set to? - // or maybe it only applies to pcm input - u16 sample_rate; - u8 volume; - u8 unk_6; - u8 unk_7; - u8 play; - u8 unk_9; - } m_reg_speaker; - #pragma pack(pop) }; } // namespace WiimoteEmu