This page reflects the understanding of the MotionPlus extension as reverse engineered and implemented in CWiid. Ticket #89 contains additional information on development goals and status.

Operational Description

Initially, the MotionPlus extension populates the 0xA60000 register space many of the values change seemingly randomly shortly after physical connection before settling down on consistent values. Most notably, the following bytes identify the MotionPlus:

0xA600FC: A6 20 00 05

At this point, the register space usually occupied by the extension port is dedicated to whatever is plugged into the MotionPlus' pass-through port, and can be initialized, read from, and by reported on as usual.

To activate the MotionPlus, write 0x04 to register 0xA600FE. This populates the 0xA40000 register space with what is probably calibration and other data, and populates extension reports with MotionPlus data. The format is:

zz yy xx ZZ YY XX

where the rotation about the X axis is ((XX AND 0xFA)<<6) OR xx) in a right-handed orientation, and the other angles are defined in identical fashion. Note that I'm not 100% sure about the least significant bytes, but they seem to be right. The problem with this method is that there is no way to automatically detect the connection of the MotionPlus - no status report is sent until it is activated. It is unknown if it is possible to read from both the MotionPlus and the pass-through extension at the same time. Writing 0x55 to 0xA400F0 (first step of standard extension init) deactivates the MotionPlus.

CWiid Example Program (Python)

This program assumes that the MotionPlus and a nunchuk are already plugged in.

import cwiid
wm = cwiid.Wiimote()
wm.enable(cwiid.FLAG_MOTIONPLUS)
wm.rpt_mode = cwiid.RPT_ACC | cwiid.RPT_MOTIONPLUS | cwiid.RPT_NUNCHUK
print wm.state
wm.disable(cwiid.FLAG_MOTIONPLUS)
print wm.state
{'acc': (141, 137, 161), 'led': 0, 'rpt_mode': 148, 'ext_type': 4, 'motionplus': {'angle_rate': (126, 131, 135)}, 'rumble': 0, 'error': 0, 'battery': 105}
{'acc': (141, 136, 161), 'led': 0, 'rpt_mode': 148, 'ext_type': 1, 'rumble': 0, 'error': 0, 'nunchuk': {'acc': (118, 166, 102), 'buttons': 0, 'stick': (129, 130)}, 'battery': 104}

CWiid Implementation

The process goes something like this:

  1. user enables CWIID_FLAG_MOTIONPLUS
    1. Write 0x04 to register 0xA600FE.
    2. Request a status report.*
  2. Wiimote send a status report, status_thread processes it
    1. Read 0xA400FE.
      1. If there was no change in extension (no MotionPlus, or MotionPlus already runnning), this value is the current extension, already initialized, and nothing more need be done.
      2. If this value is EXT_PARTIAL (0xFF), then the current extension is one that needs initialization (not a MotionPlus).
        1. Write 0x55 to 0xA400F0.
        2. Write 0x00 to 0xA400FB.
        3. Read 0xA400FE again.
  3. Whatever extension was detected, if any (let's assume it was a MotionPlus), if reporting is enabled, will show up in the state and messages.
  4. user disables CWIID_FLAG_MOTIONPLUS
    1. Write 0x55 to register 0xA400F0, then 0x00 to 0xA400FB. This is standard extension init, although it works fine even with no extension. It disables the MotionPlus, although there may be an easier way.
    2. Request a status report.*
  5. Status processing, same as 2

* A status report is necessary to activate the the extension identification logic the status thread. If there is no extension in the pass-through port, the status changes from Unattached to Attached, so a status report is generated automatically, and we just detect it twice. If there is an extension in the pass-through port, the attachment state doesn't change, no status report is automatically generated, and we have to manually request one to detect the new extension.