Ring-Con: Difference between revisions
No edit summary |
|||
(12 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
This page documents how the Ring Fit Adventure game uses [[HID_services#hidbus|hidbus]] for using the Ring-Con ExternalDevice, which attaches to Joy-Cons. | This page documents how the Ring Fit Adventure game uses [[HID_services#hidbus|hidbus]] for using the Ring-Con [[HID_services#ExternalDevices|ExternalDevice]], which attaches to Joy-Cons. | ||
After EnableExternalDevice is used successfully during initialization, EnableJoyPollingReceiveMode(flag=true) is used with command [[#0x00020101]]. For cleanup, DisableJoyPollingReceiveMode is used then on success EnableExternalDevice(flag=false) is used. | |||
Commands (input data for EnableJoyPollingReceiveMode / SendAndReceive) start with the u32 cmd. Data in the replies are at least 0x4-bytes, with fields being 4-byte aligned. Reply+0 is the u8 status. When the output size doesn't match the expected size, or status is non-zero, error 0xEDA is returned. When status is non-zero, a func is called with the status value which updates global state. | |||
The status field is not listed below since all replies have it. | |||
Note that the app saves various PlayReports, this includes various Ring-Con data (which includes field-name strings). | |||
= CRC = | = CRC = | ||
Line 15: | Line 15: | ||
= Commands = | = Commands = | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 39: | Line 38: | ||
|- | |- | ||
| [[#0x00020A04]] || 0x4 || 0x14 | | [[#0x00020A04]] || 0x4 || 0x14 | ||
|- | |||
| [[#0x00021104]] || 0x4 || 0x8 | |||
|- | |||
| [[#0x00021204]] || 0x4 || 0x8 | |||
|- | |||
| [[#0x00021304]] || 0x4 || 0x8 | |||
|- | |||
| [[#0x00021A04]] || 0x4 || 0x14 | |||
|- | |- | ||
| [[#0x00023104]] || 0x4 || 0x8 | | [[#0x00023104]] || 0x4 || 0x8 | ||
Line 58: | Line 65: | ||
The two u8s at reply+0x4 are copied to an output struct, with the order swapped in the output struct. This is also used directly by various funcs, without the struct. | The two u8s at reply+0x4 are copied to an output struct, with the order swapped in the output struct. This is also used directly by various funcs, without the struct. | ||
This | Reply u8 +0x4 is "fw_sub_ver", +0x5 is "fw_main_ver". | ||
This gets the firmware version. Funcs using this do: <code>if (fw_main_ver >= 0x20) {} else {}</code> | |||
== 0x00020100 == | == 0x00020100 == | ||
This gets the ID. The first 0x6-bytes from the below output is "id_l", the remaining 0x6-bytes are "id_h". During PlayReport saving the cached ID is copied to u64s, which are then used with the PlayReport. | |||
Reply: | Reply: | ||
Line 67: | Line 78: | ||
! Offset || Size || Description | ! Offset || Size || Description | ||
|- | |- | ||
| 0x4 | | | 0x4 || 0xC || This is copied to an output buffer. | ||
| 0xC || | |||
|} | |} | ||
== 0x00020101 == | == 0x00020101 == | ||
This is used with EnableJoyPollingReceiveMode/GetJoyPollingReceivedData. Reply+0x4 is an u16 which is copied to an output struct, the [[HID_services#JoyPollingReceivedData|timestamp]] is also copied. | This is used with EnableJoyPollingReceiveMode/GetJoyPollingReceivedData. Reply+0x4 is an u16 which is copied to an output struct, the [[HID_services#JoyPollingReceivedData|timestamp]] is also copied. This seems to be the current sensor state. | ||
== 0x00020104 == | == 0x00020104 == | ||
Line 81: | Line 90: | ||
== 0x00020105 == | == 0x00020105 == | ||
Reply+0x4 is the output u8. | Reply+0x4 is the output u8, which copied to an output u32. | ||
== 0x00020204 == | == 0x00020204 == | ||
Line 99: | Line 108: | ||
== 0x00020504 == | == 0x00020504 == | ||
Reply+0x4 is a s16. After successfully using this cmd, this calls the func for [[#0x00020A04]]. When that's successful, this does the following with the output from that func and the earlier reply data: <code>s16 tmp = | Reply+0x4 is a s16. After successfully using this cmd, this calls the func for [[#0x00020A04]]. When that's successful, this does the following with the output from that func and the earlier reply data: <code>s16 tmp = s16 manu_hk_max - s16 manu_os_max; if (tmp < 0) tmp++; *16bit_outparam = replydata + (tmp>>1);</code> Then this returns 0, regardless of whether [[#0x00020A04]] was successful. | ||
== 0x00020A04 == | == 0x00020A04 == | ||
The app uses cmd [[#0x00020000]] first. When | The app uses cmd [[#0x00020000]] first. When fw_main_ver from that cmd is >=0x20, it proceeds to use cmd 0x00020A04 then returns. Otherwise, the following cmds are used with the output being copied to the output struct, then returns: [[#0x00020104]] (output_struct+0x0), [[#0x00020204]] (output_struct+0x2), [[#0x00020404]] (output_struct+0x6), [[#0x00020304]] (output_struct+0x4). | ||
Reply: | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x4 || 0x2 || "manu_os_max". s16 value copied to output_struct+0x0. | |||
|- | |||
| 0x8 || 0x2 || "manu_hk_max". s16 value copied to output_struct+0x2. | |||
|- | |||
| 0xC || 0x2 || "manu_zero_min". s16 value copied to output_struct+0x4. | |||
|- | |||
| 0x10 || 0x2 || "manu_zero_max". s16 value copied to output_struct+0x6. | |||
|} | |||
== 0x00021104 == | |||
This is implemented in the app with the cmd to use being specified via an input param. | |||
See [[#0x00021A04]]. | |||
Reply: | |||
The | {| class="wikitable" border="1" | ||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x4 || 0x2 || Data, copied to an output struct as an 16bit value. | |||
|- | |||
| 0x6 || 0x1 || [[#CRC]] over the previous 0x2-bytes. | |||
|} | |||
== 0x00021204 == | |||
See [[#0x00021104]]. | |||
== 0x00021304 == | |||
See [[#0x00021104]]. | |||
== 0x00021A04 == | |||
The app uses cmd [[#0x00020000]] first. When fw_main_ver from that cmd is >=0x20, it proceeds to use cmd 0x00021A04. Otherwise, the following cmds are used, with the output being written to the output_struct: [[#0x00021104]] (output_struct+0x0), [[#0x00021204]] (output_struct+0x2), [[#0x00021304]] (output_struct+0x4). | |||
Then, if any of the 16bit output fields in output_struct are set to 0xCAFE, a flag is set to 0x2 (same field used for invalid-CRC, which uses value 0x1 for that). Then this returns 0. This field is "user_state". | |||
This reads the user calibration. This is normally (?) not calibrated (fields are set to 0xCAFE). | |||
Reply: | Reply: | ||
Line 112: | Line 163: | ||
! Offset || Size || Description | ! Offset || Size || Description | ||
|- | |- | ||
| 0x4 || 0x2 || | | 0x4 || 0x2 || "user_os_max"/"os_max". s16 value copied to output_struct+0x0. | ||
|- | |- | ||
| | | 0x6 || 0x1 || [[#CRC]] over the previous 0x2-bytes. | ||
|- | |- | ||
| | | 0x7 || 0x1 || Padding. | ||
|- | |- | ||
| | | 0x8 || 0x2 || "user_hk_max"/"hk_max". s16 value copied to output_struct+0x2. | ||
|- | |||
| 0xA || 0x1 || [[#CRC]] over the previous 0x2-bytes. | |||
|- | |||
| 0xB || 0x1 || Padding. | |||
|- | |||
| 0xC || 0x2 || "user_zero"/"zero". s16 value copied to output_struct+0x4. | |||
|- | |||
| 0xE || 0x1 || [[#CRC]] over the previous 0x2-bytes. | |||
|- | |||
| 0xF || 0x1 || Padding. | |||
|} | |} | ||
== 0x00023104 == | == 0x00023104 == | ||
The code which calls the func implementing this clamps the output value to range 0-500, then copies it elsewhere. | |||
This gets the rep-count for Multitask-Mode. | |||
Reply: | Reply: | ||
Line 128: | Line 193: | ||
! Offset || Size || Description | ! Offset || Size || Description | ||
|- | |- | ||
| 0x4 || 0x3 || Data, copied to an output struct as | | 0x4 || 0x3 || Data, copied to an output struct as a s32. | ||
|- | |- | ||
| 0x7 || 0x1 || [[#CRC]] over the previous 0x3-bytes. | | 0x7 || 0x1 || [[#CRC]] over the previous 0x3-bytes, followed a value-0 byte. | ||
|} | |} | ||
== 0x00023204 == | == 0x00023204 == | ||
The func implementing this in the app is identical to [[#0x00023104]] except for the cmd u32. | The func implementing this in the app is identical to [[#0x00023104]] except for the cmd u32. The output field is "total_push_count". This is only updated in Multitask Mode. | ||
The code calling this func copies the output into a global field, when it's valid. | |||
== 0x04013104 == | == 0x04013104 == | ||
Line 140: | Line 207: | ||
Unlike the other cmds, this checks for output_size==0x4, instead of {output buffer size} (it's unknown whether this is intended). | Unlike the other cmds, this checks for output_size==0x4, instead of {output buffer size} (it's unknown whether this is intended). | ||
This resets the value returned by [[#0x00023104]] to 0. | |||
== 0x04011104 == | == 0x04011104 == | ||
Line 157: | Line 226: | ||
== 0x10011A04 == | == 0x10011A04 == | ||
The app uses cmd [[#0x00020000]] first. When | The app uses cmd [[#0x00020000]] first. When fw_main_ver from that cmd is >=0x20, it proceeds to use cmd 0x10011A04 then returns. Otherwise, the following cmds are used, with the same 4-byte input listed in the below table: [[#0x04011104]] (below cmd+0x4), [[#0x04011204]] (below cmd+0x8), [[#0x04011304]] (below cmd+0xC). | ||
The app doesn't use reply data here besides the status, and the output_size is not checked. | The app doesn't use reply data here besides the status, and the output_size is not checked. | ||
The code calling this func saves PlayReports with EventId "write_user_cal". This is the Write version of [[#0x00021A04]], the s16s here are the same as [[#0x00021A04]]. | |||
The code calling this func will first call this func, then on success a PlayReport is saved. Then [[#0x00021A04]] is used, on success if the output matches the data used for 0x10011A04 and the is_valid flag is 0, this returns 0. Otherwise: the func for 0x10011A04 is used again, handling error on failure. Then a PlayReport is saved again. [[#0x00021A04]] is used, with error handling on failure. Then the same validation checks run again. If it didn't return at this point, error handling runs. | |||
Cmd: | Cmd: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 169: | Line 241: | ||
| 0x4 || 0x2 || Func input param & 0xFFFF | | 0x4 || 0x2 || Func input param & 0xFFFF | ||
|- | |- | ||
| 0x6 || 0x1 || [[#CRC]] over the previous | | 0x6 || 0x1 || [[#CRC]] over the previous 0x2-bytes. | ||
|- | |- | ||
| 0x7 || 0x1 || Padding. | | 0x7 || 0x1 || Padding. | ||
Line 175: | Line 247: | ||
| 0x8 || 0x2 || (Func input param >> 16) & 0xFFFF | | 0x8 || 0x2 || (Func input param >> 16) & 0xFFFF | ||
|- | |- | ||
| 0xA || 0x1 || [[#CRC]] over the previous | | 0xA || 0x1 || [[#CRC]] over the previous 0x2-bytes. | ||
|- | |- | ||
| 0xB || 0x1 || Padding. | | 0xB || 0x1 || Padding. | ||
Line 181: | Line 253: | ||
| 0xC || 0x2 || (Func input param >> 32) & 0xFFFF | | 0xC || 0x2 || (Func input param >> 32) & 0xFFFF | ||
|- | |- | ||
| 0xE || 0x1 || [[#CRC]] over the previous | | 0xE || 0x1 || [[#CRC]] over the previous 0x2-bytes. | ||
|- | |- | ||
| 0xF || 0x1 || Padding. | | 0xF || 0x1 || Padding. |