New Wiimote Plugin: Fix Emulated Wiimote Problem.(fixes issue 3230) Made the "Connect...
[dolphin.git] / Source / Plugins / Plugin_WiimoteNew / Src / WiimoteEmu / EmuSubroutines.cpp
blobfe457477e60e047a29141a48d735943bb6fdaa21
1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
19 /* HID reports access guide. */
21 /* 0x10 - 0x1a Output EmuMain.cpp: HidOutputReport()
22 0x10 - 0x14: General
23 0x15: Status report request from the Wii
24 0x16 and 0x17: Write and read memory or registers
25 0x19 and 0x1a: General
26 0x20 - 0x22 Input EmuMain.cpp: HidOutputReport() to the destination
27 0x15 leads to a 0x20 Input report
28 0x17 leads to a 0x21 Input report
29 0x10 - 0x1a leads to a 0x22 Input report
30 0x30 - 0x3f Input This file: Update() */
32 #include <vector>
33 #include <string>
34 #include <fstream>
36 #include "Common.h" // Common
37 #include "FileUtil.h"
38 #include "pluginspecs_wiimote.h"
40 #include "WiimoteEmu.h"
41 #include "WiimoteHid.h"
42 #include "../WiimoteReal/WiimoteReal.h"
44 #include "Attachment/Attachment.h"
46 /* Bit shift conversions */
47 u32 swap24(const u8* src)
49 return (src[0] << 16) | (src[1] << 8) | src[2];
52 namespace WiimoteEmu
55 void Wiimote::ReportMode(const wm_report_mode* const dr)
57 //INFO_LOG(WIIMOTE, "Set data report mode");
58 //DEBUG_LOG(WIIMOTE, " Rumble: %x", dr->rumble);
59 //DEBUG_LOG(WIIMOTE, " Continuous: %x", dr->continuous);
60 //DEBUG_LOG(WIIMOTE, " All The Time: %x", dr->all_the_time);
61 //DEBUG_LOG(WIIMOTE, " Mode: 0x%02x", dr->mode);
63 //m_reporting_auto = dr->all_the_time;
64 m_reporting_auto = dr->continuous; // this right?
65 m_reporting_mode = dr->mode;
66 //m_reporting_channel = _channelID; // this is set in every Interrupt/Control Channel now
68 // reset IR camera
69 //memset(m_reg_ir, 0, sizeof(*m_reg_ir)); //ugly hack
71 if (dr->mode > 0x37)
72 PanicAlert("Wiimote: Unsupported Reporting mode.");
73 else if (dr->mode < WM_REPORT_CORE)
74 PanicAlert("Wiimote: Reporting mode < 0x30.");
77 /* Here we process the Output Reports that the Wii sends. Our response will be
78 an Input Report back to the Wii. Input and Output is from the Wii's
79 perspective, Output means data to the Wiimote (from the Wii), Input means
80 data from the Wiimote.
82 The call browser:
84 1. Wiimote_InterruptChannel > InterruptChannel > HidOutputReport
85 2. Wiimote_ControlChannel > ControlChannel > HidOutputReport
87 The IR enable/disable and speaker enable/disable and mute/unmute values are
88 bit2: 0 = Disable (0x02), 1 = Enable (0x06)
90 void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack)
92 INFO_LOG(WIIMOTE, "HidOutputReport (page: %i, cid: 0x%02x, wm: 0x%02x)", m_index, m_reporting_channel, sr->wm);
94 // wiibrew:
95 // In every single Output Report, bit 0 (0x01) of the first byte controls the Rumble feature.
96 m_rumble_on = sr->rumble;
98 switch (sr->wm)
100 case WM_RUMBLE : // 0x10
101 // this is handled above
102 return; // no ack
103 break;
105 case WM_LEDS : // 0x11
106 //INFO_LOG(WIIMOTE, "Set LEDs: 0x%02x", sr->data[0]);
107 m_status.leds = sr->data[0] >> 4;
108 break;
110 case WM_REPORT_MODE : // 0x12
111 ReportMode((wm_report_mode*)sr->data);
112 break;
114 case WM_IR_PIXEL_CLOCK : // 0x13
115 //INFO_LOG(WIIMOTE, "WM IR Clock: 0x%02x", sr->data[0]);
116 //m_ir_clock = sr->enable;
117 if (false == sr->ack)
118 return;
119 break;
121 case WM_SPEAKER_ENABLE : // 0x14
122 //INFO_LOG(WIIMOTE, "WM Speaker Enable: 0x%02x", sr->data[0]);
123 //PanicAlert( "WM Speaker Enable: %d", sr->data[0] );
124 m_status.speaker = sr->enable;
125 if (false == sr->ack)
126 return;
127 break;
129 case WM_REQUEST_STATUS : // 0x15
130 RequestStatus((wm_request_status*)sr->data);
131 return; // sends its own ack
132 break;
134 case WM_WRITE_DATA : // 0x16
135 WriteData((wm_write_data*)sr->data);
136 break;
138 case WM_READ_DATA : // 0x17
139 ReadData((wm_read_data*)sr->data);
140 return; // sends its own ack
141 break;
143 case WM_WRITE_SPEAKER_DATA : // 0x18
144 #ifdef USE_WIIMOTE_EMU_SPEAKER
145 SpeakerData((wm_speaker_data*)sr->data);
146 #endif
147 // TODO: Does this need an ack?
148 return; // no ack
149 break;
151 case WM_SPEAKER_MUTE : // 0x19
152 //INFO_LOG(WIIMOTE, "WM Speaker Mute: 0x%02x", sr->data[0]);
153 //PanicAlert( "WM Speaker Mute: %d", sr->data[0] & 0x04 );
154 #ifdef USE_WIIMOTE_EMU_SPEAKER
155 // testing
156 if (sr->data[0] & 0x04)
157 memset(&m_channel_status, 0, sizeof(m_channel_status));
158 #endif
159 m_speaker_mute = sr->enable;
160 if (false == sr->ack)
161 return;
162 break;
164 case WM_IR_LOGIC: // 0x1a
165 // comment from old plugin:
166 // This enables or disables the IR lights, we update the global variable g_IR
167 // so that WmRequestStatus() knows about it
168 //INFO_LOG(WIIMOTE, "WM IR Enable: 0x%02x", sr->data[0]);
169 m_status.ir = sr->enable;
170 if (false == sr->ack)
171 return;
172 break;
174 default:
175 PanicAlert("HidOutputReport: Unknown channel 0x%02x", sr->wm);
176 return; // no ack
177 break;
180 // send ack
181 if (send_ack)
182 SendAck(sr->wm);
185 /* This will generate the 0x22 acknowledgement for most Input reports.
186 It has the form of "a1 22 00 00 _reportID 00".
187 The first two bytes are the core buttons data,
188 00 00 means nothing is pressed.
189 The last byte is the success code 00. */
190 void Wiimote::SendAck(u8 _reportID)
192 u8 data[6];
194 data[0] = 0xA1;
195 data[1] = WM_ACK_DATA;
197 wm_acknowledge* const ack = (wm_acknowledge*)(data + 2);
199 ack->buttons = m_status.buttons;
200 ack->reportID = _reportID;
201 ack->errorID = 0;
203 g_WiimoteInitialize.pWiimoteInterruptChannel( m_index, m_reporting_channel, data, sizeof(data));
206 void Wiimote::HandleExtensionSwap()
208 // handle switch extension
209 if (m_extension->active_extension != m_extension->switch_extension)
211 // if an extension is currently connected and we want to switch to a different extension
212 if ((m_extension->active_extension > 0) && m_extension->switch_extension)
213 // detach extension first, wait til next Update() or RequestStatus() call to change to the new extension
214 m_extension->active_extension = 0;
215 else
216 // set the wanted extension
217 m_extension->active_extension = m_extension->switch_extension;
219 // update status struct
220 m_status.extension = m_extension->active_extension ? 1 : 0;
222 // set register, I hate this line
223 m_register[0xa40000] = ((WiimoteEmu::Attachment*)m_extension->attachments[m_extension->active_extension])->reg;
227 // old comment
228 /* Here we produce a 0x20 status report to send to the Wii. We currently ignore
229 the status request rs and all its eventual instructions it may include (for
230 example turn off rumble or something else) and just send the status
231 report. */
232 void Wiimote::RequestStatus(const wm_request_status* const rs)
234 HandleExtensionSwap();
236 // set up report
237 u8 data[8];
238 data[0] = 0xA1;
239 data[1] = WM_STATUS_REPORT;
241 // status values
242 *(wm_status_report*)(data + 2) = m_status;
244 // hybrid wiimote stuff
245 if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index] && (m_extension->switch_extension <= 0))
247 using namespace WiimoteReal;
249 g_refresh_critsec.Enter();
250 if (g_wiimotes[m_index])
252 wm_request_status rpt;
253 rpt.rumble = 0;
254 g_wiimotes[m_index]->SendPacket(WM_REQUEST_STATUS, &rpt, sizeof(rpt));
256 g_refresh_critsec.Leave();
258 return;
261 // send report
262 g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_reporting_channel, data, sizeof(data));
265 /* Write data to Wiimote and Extensions registers. */
266 void Wiimote::WriteData(const wm_write_data* const wd)
268 u32 address = swap24(wd->address);
270 // ignore the 0x010000 bit
271 address &= 0xFEFFFF;
273 if (wd->size > 16)
275 PanicAlert("WriteData: size is > 16 bytes");
276 return;
279 switch (wd->space)
281 case WM_SPACE_EEPROM :
283 // Write to EEPROM
285 if (address + wd->size > WIIMOTE_EEPROM_SIZE)
287 ERROR_LOG(WIIMOTE, "WriteData: address + size out of bounds!");
288 PanicAlert("WriteData: address + size out of bounds!");
289 return;
291 memcpy(m_eeprom + address, wd->data, wd->size);
293 // write mii data to file
294 // i need to improve this greatly
295 if (address >= 0x0FCA && address < 0x12C0)
297 // writing the whole mii block each write :/
298 std::ofstream file;
299 file.open( (std::string(File::GetUserPath(D_WIIUSER_IDX)) + "mii.bin").c_str(), std::ios::binary | std::ios::out);
300 file.write((char*)m_eeprom + 0x0FCA, 0x02f0);
301 file.close();
304 break;
305 case WM_SPACE_REGS1 :
306 case WM_SPACE_REGS2 :
308 // Write to Control Register
310 // ignore second byte for extension area
311 if (0xA4 == (address >> 16))
312 address &= 0xFF00FF;
314 // write to the register
315 m_register.Write(address, wd->data, wd->size);
317 switch (address >> 16)
319 // speaker
320 case 0xa2 :
321 //PanicAlert("Write to speaker!!");
322 break;
323 // extension register
324 case 0xa4 :
326 // Run the key generation on all writes in the key area, it doesn't matter
327 // that we send it parts of a key, only the last full key will have an effect
328 // I might have f'ed this up
329 if ( address >= 0xa40040 && address <= 0xa4004c )
330 wiimote_gen_key(&m_ext_key, m_reg_ext->encryption_key);
331 //else if ( address >= 0xa40020 && address < 0xa40040 )
332 // PanicAlert("Writing to extension calibration data! Extension may misbehave");
334 break;
335 // ir
336 case 0xB0 :
337 if (5 == m_reg_ir->mode)
338 PanicAlert("IR Full Mode is Unsupported!");
339 break;
343 break;
344 default:
345 PanicAlert("WriteData: unimplemented parameters!");
346 break;
350 /* Read data from Wiimote and Extensions registers. */
351 void Wiimote::ReadData(const wm_read_data* const rd)
353 u32 address = swap24(rd->address);
354 u16 size = Common::swap16(rd->size);
356 // ignore the 0x010000 bit
357 address &= 0xFEFFFF;
359 // hybrid wiimote stuff
360 // relay the read data request to real-wiimote
361 if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index] && ((0xA4 != (address >> 16)) || (m_extension->switch_extension <= 0)))
363 WiimoteReal::InterruptChannel(m_index, m_reporting_channel, ((u8*)rd) - 2, sizeof(wm_read_data) + 2); // hacky
365 // don't want emu-wiimote to send reply
366 return;
369 ReadRequest rr;
370 u8* block = new u8[size];
372 switch (rd->space)
374 case WM_SPACE_EEPROM :
376 //PanicAlert("ReadData: reading from EEPROM: address: 0x%x size: 0x%x", address, size);
377 // Read from EEPROM
378 if (address + size >= WIIMOTE_EEPROM_FREE_SIZE)
380 if (address + size > WIIMOTE_EEPROM_SIZE)
382 PanicAlert("ReadData: address + size out of bounds");
383 return;
385 // generate a read error
386 size = 0;
389 // read mii data from file
390 // i need to improve this greatly
391 if (address >= 0x0FCA && address < 0x12C0)
393 // reading the whole mii block :/
394 std::ifstream file;
395 file.open( (std::string(File::GetUserPath(D_WIIUSER_IDX)) + "mii.bin").c_str(), std::ios::binary | std::ios::in);
396 file.read((char*)m_eeprom + 0x0FCA, 0x02f0);
397 file.close();
400 // read mem to be sent to wii
401 memcpy( block, m_eeprom + address, size);
403 break;
404 case WM_SPACE_REGS1 :
405 case WM_SPACE_REGS2 :
407 // Read from Control Register
409 // ignore second byte for extension area
410 if (0xA4 == (address >> 16))
411 address &= 0xFF00FF;
413 // read block to send to wii
414 m_register.Read( address, block, size );
416 switch (address >> 16)
418 // speaker
419 case 0xa2 :
420 //PanicAlert("read from speaker!!");
421 break;
422 // extension
423 case 0xa4 :
425 // Encrypt data read from extension register
426 // Check if encrypted reads is on
427 if (0xaa == m_reg_ext->encryption)
428 wiimote_encrypt(&m_ext_key, block, address & 0xffff, (u8)size);
430 //if ( address >= 0xa40008 && address < 0xa40020 )
431 // PanicAlert("Reading extension data from register");
433 break;
434 // motion plus
435 case 0xa6 :
437 // motion plus crap copied from old wiimote plugin
438 //block[0xFC] = 0xA6;
439 //block[0xFD] = 0x20;
440 //block[0xFE] = 0x00;
441 //block[0xFF] = 0x05;
443 break;
446 break;
447 default :
448 PanicAlert("WmReadData: unimplemented parameters (size: %i, addr: 0x%x)!", size, rd->space);
449 break;
452 // want the requested address, not the above modified one
453 rr.address = swap24(rd->address);
454 rr.size = size;
455 //rr.channel = _channelID;
456 rr.position = 0;
457 rr.data = block;
459 // send up to 16 bytes
460 SendReadDataReply(rr);
462 // if there is more data to be sent, add it to the queue
463 if (rr.size)
464 m_read_requests.push( rr );
465 else
466 delete[] rr.data;
469 // old comment
470 /* Here we produce the actual 0x21 Input report that we send to the Wii. The
471 message is divided into 16 bytes pieces and sent piece by piece. There will
472 be five formatting bytes at the begging of all reports. A common format is
473 00 00 f0 00 20, the 00 00 means that no buttons are pressed, the f means 16
474 bytes in the message, the 0 means no error, the 00 20 means that the message
475 is at the 00 20 offest in the registry that was read.
477 void Wiimote::SendReadDataReply(ReadRequest& _request)
479 u8 data[23];
480 data[0] = 0xA1;
481 data[1] = WM_READ_DATA_REPLY;
483 wm_read_data_reply* const reply = (wm_read_data_reply*)(data + 2);
484 reply->buttons = m_status.buttons;
485 reply->address = Common::swap16(_request.address);
487 // generate a read error
488 // Out of bounds. The real Wiimote generate an error for the first
489 // request to 0x1770 if we dont't replicate that the game will never
490 // read the calibration data at the beginning of Eeprom. I think this
491 // error is supposed to occur when we try to read above the freely
492 // usable space that ends at 0x16ff.
493 if (0 == _request.size)
495 reply->size = 0x0f;
496 reply->error = 0x08;
498 memset(reply->data, 0, sizeof(reply->data));
500 else
502 // Limit the amt to 16 bytes
503 // AyuanX: the MTU is 640B though... what a waste!
504 const int amt = std::min( (unsigned int)16, _request.size );
506 // no error
507 reply->error = 0;
509 // 0x1 means two bytes, 0xf means 16 bytes
510 reply->size = amt - 1;
512 // Clear the mem first
513 memset(reply->data, 0, sizeof(reply->data));
515 // copy piece of mem
516 memcpy(reply->data, _request.data + _request.position, amt);
518 // update request struct
519 _request.size -= amt;
520 _request.position += amt;
521 _request.address += amt;
524 // Send a piece
525 g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_reporting_channel, data, sizeof(data));
528 void Wiimote::DoState(PointerWrap& p)
530 // not working :(
531 //if (p.MODE_READ == p.GetMode())
533 // // LOAD
534 // Reset(); // should cause a status report to be sent, then wii should re-setup wiimote
536 //p.Do(m_reporting_channel);