Tuesday, June 8, 2010

Dynamic MotionPlus (WMP,WM+) Calibration - Part 1: Shaking some hands.....

You might have wondered yourself how to toggle MotionPlus dynamic calibration. Well, here we go.
Part 1 will be about the handshake and part 2 will be dedicated to the 64bytes long data structure at register 0xA40050. If you would like to know anything else, just drop a comment.



As soon as a game has verified that a MP is active, which was done by reading from the active extension register at 0xA400F0-FF, hardcoded calibration data will be read from register 0xA40020-3f. Afterwards a controlflag at 0xA400F7 will be checked. This flag can contain values like 02,06,08,0A,0C,0E or 1A.
Every value represents a different initiation state of the MP extension. For instance if the flag is below a certain state, data reports will contain invalid or 0xFF'ed MP extension data or certain actions are not able to be done. The default(inactive) is 0x10. When the MP gets activated, the flag will be reseted to 0x02 (maybe even to zero but you wont be able to read this value since it would just change too fast to catch it) and will be gradually increased until it reaches 0x1A, which represents an activate state with accomplished dynamic recalibration(doesn't matter if the recalibration was successful or not).
When there is an extension connected to the MP, the game will read 3 more bytes by reading 4 bytes from 0xA400F6. Those 3 bytes will be always 0xx00 when there's an extension connected to the MP, else they are defaultwise 0xFF. There is no direct need to read them. At this point our controlflag usually will be already 0x0C/0x0E. For the next step however its important to be at least in state 0x08.
The next step toggles dynamic calibration. It is done by writing 0x00 to 0xA400F2. Data at 0x50-0x8f will now start to change until a second 0x00 write to 0xA400F2 is issued to stop the calibration. So it would be smart to  keep track of extension data reports to make sure to trigger the routine not too early, since it might be still moving. The game will read out the initiation state flag again and verify that it's at least 0x0E. Then the calibration data will be read out twice to make sure the routine wasn't still running in between. After this is done the game will check if the data is reasonable, and write either 0x00 or 0x01 to register  0xA400F1. A write to this register will change the calibration data again, which seems to me is just some sort of correction or update. As soon as the game verified that the calibration was accomplished by simply checking the initiation state, which should read 0x1a now, it will read out the calibration data twice again from  0xA40050-8f. This data represents a rotation matrix
Stay tuned for part 2.

I hope this was of any help to ya chaps. If you like it, link it.

Best regards
Sanchez

8 comments:

  1. Hmm. My 0x04A400F7 (or A600F7) almost always reads 0x10. The only time it doesn't is after its disabled. Then it reads 0x08 the first time I read it, but 0x10 the next time. Sending 0x55 to 0x04A600F0 doesn't really seem to do anything. However, the module still enables when I send 0x04 and it sends reasonable looking data through report 0x34. However, byte F7 always has 0x10 when I read it. The byte doesn't seem to change when I write 0x00 to F2 either.

    ReplyDelete
  2. When its disabled, its 0x10 defaultwise. As soon u swap registers it gets reseted, and it starts from 0x02(mb even 0x00). Usually it changes so fast that u will read 0x08. If it changes back to 0x10 u did either the init wrong, dont forgot to write in the proper order, a600fb, a600fe and then a600f0, or you havent recalibrated it.
    The 0x1a represents a recalibrated active state.
    And you need to write 0x00 twice ! Once to activate the recalibration and once to stop it, and this will only work if you are in a state between 0x08 and 0e, so if your at 0x10 it wont work.

    ReplyDelete
  3. correction: 0xA600fb, 0xA600fe and 0xA400f0.*

    ReplyDelete
  4. I'm not sure what you mean. To initialize, I use the sequence you described in your previous post (which matches the one described on the WiiBrew site):
    1) Check 2 bytes at 0x04A600FE. Ensure 2nd byte is 0x05.
    2) Write 0x55 to 0x04A600F0
    3) Write 0x04 to 0x04A600FE (I don't have any passthrough)
    4) Read the extension ID at 0x04A400FA
    5) Read the calibration data from 0x04A40020-0x04A400cf
    I must have misread your previous instructions because I don't think I ever write to 0xA600FB. Could you clarify?

    Interestingly, if I write 0x00 to a400f2 (only once) while streaming data, the baseline values change if I'm moving the wiimote at the time. Normally I get 8170, 8590, 8360 as my zero values. When I send the 0x00 to 0xf2, those values are biased toward the opposite direction from my current movement.

    ReplyDelete
  5. Also interesting is the fact that this update only seems to happen to motion around the x and y axes, not the z axis. Also, although the output values change, the numbers stored in the 50h block don't. I'm curious to see what you've discovered about that block.

    ReplyDelete
  6. Writing to A400FB is part of the proper initiation of the extension, just like for regular extension, but due the register swap we need 3 commands to fullfil a proper complete init.
    this consits of writng to A600F0, then to A600FE and then to A400FB (just like the regular init).
    The data at 0x50 is a simple rotation matrix.
    I'll publish it within the next days, stay tuned, hope u enjoy my work^^

    ReplyDelete
  7. Ah. I looked back at the init script and I do write 0x00 to 0x04a400fb right after step 3. However, it doesn't seem to make a difference whether I do it or not. The register swap happens, a status report announces the new extension, and extension reports contain valid data. But my 0xf7 byte never goes past 0x10. Weird. I wonder if it's because the wiimote/mp has never actually been paired with a Wii. Wiibrew says that the MP data are "at 0x(4)a40008 (or 0x(4)a40000 in some cases)". My data are definitely the second case. I wonder if that's indicative of an underlying difference.

    I suppose if the data represent a rotation matrix, it could be because I'm not using the IR bar and so there's no ground truth for yaw information. You can't calibrate for orientation if you don't have any way of figuring out which way you're oriented.

    ReplyDelete
  8. It might be that theres also a timing issue, I'm not sure about that tho. However yes, the MP will read out accel data and mostlikely IR data as well from the Wiimote register to generate the orientation matrix. So that could be an issue.
    Apart from that I will add some bluetooth dumps soon.

    ReplyDelete