Changes

14,673 bytes added ,  21:06, 29 September 2024
Line 1: Line 1: −
Joy-Con is the name for the Switch's primary game controllers. The Joy-Con are internally called Ukyo (Left) and Sakyo (Right).
+
Joy-Con is the name for the Switch's primary game controllers. The Joy-Con are internally called Sakyo (Left) and Ukyo (Right).
    
= Hardware =
 
= Hardware =
== Ukyo ==
+
== Sakyo ==
 
{| class="wikitable"
 
{| class="wikitable"
 
! Component || Description
 
! Component || Description
Line 15: Line 15:  
|}
 
|}
   −
== Sakyo ==
+
== Ukyo ==
 
{| class="wikitable"
 
{| class="wikitable"
 
! Component || Description
 
! Component || Description
Line 33: Line 33:     
= Protocol =
 
= Protocol =
The Joy-Con can communicate wirelessly over Bluetooth or through the rails over UART. This uses a Nintendo proprietary protocol called "Nwcp".  
+
The Joy-Con can communicate wirelessly over Bluetooth or through the rails over UART. The latter uses a Nintendo proprietary protocol called "Nwcp".  
    
== NwcpPacket ==
 
== NwcpPacket ==
Line 128: Line 128:  
! Description
 
! Description
 
|-
 
|-
| 0x91 || DeviceCommandToDevice
+
| 0x43 || ReportOut
 +
|-
 +
| 0x53 || ReportIn
 +
|-
 +
| 0x91 || DeviceCommandIn
 
|-
 
|-
 
| 0x92 || Hid
 
| 0x92 || Hid
 
|-
 
|-
| 0x94 || DeviceCommandFromDevice
+
| 0x93 ||  
 
|-
 
|-
| 0x9A ||  
+
| 0x94 || DeviceCommandOut
 
|-
 
|-
| 0xA3 ||  
+
| 0x95 ||
 +
|-
 +
| 0x9A || Fifty
 +
|-
 +
| 0xA3 || ReportComplete
 
|-
 
|-
 
| 0xA5 || Handshake
 
| 0xA5 || Handshake
 +
|}
 +
 +
== HidCommandInputReport ==
 +
This is a 0x31-byte struct.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1
 +
| [[#HidReportId|ReportId]]
 +
|-
 +
| 0x1
 +
| 0x1
 +
| LatencyTimer
 +
|-
 +
| 0x2
 +
| 0x1
 +
| PowerInfo
 +
|-
 +
| 0x3
 +
| 0x1
 +
| RightPadButtonStatus
 +
|-
 +
| 0x4
 +
| 0x1
 +
| SharedButtonStatus
 +
|-
 +
| 0x5
 +
| 0x1
 +
| LeftPadButtonStatus
 +
|-
 +
| 0x6
 +
| 0x3
 +
| LeftAnalogStickData
 +
|-
 +
| 0x9
 +
| 0x3
 +
| RightAnalogStickData
 +
|-
 +
| 0xC
 +
| 0x1
 +
| MotorStatus
 +
|-
 +
| 0xD
 +
| 0x1
 +
| CommandAck
 +
|-
 +
| 0xE
 +
| 0x1
 +
| [[#HidCommand|CommandId]]
 +
|-
 +
| 0xF
 +
| 0x22
 +
| CommandReply
 +
|}
 +
 +
== HidMcuUpdateInputReport ==
 +
This is a 0x30-byte struct.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1
 +
| [[#HidReportId|ReportId]]
 +
|-
 +
| 0x1
 +
| 0x1
 +
| LatencyTimer
 +
|-
 +
| 0x2
 +
| 0x1
 +
| PowerInfo
 +
|-
 +
| 0x3
 +
| 0x1
 +
| RightPadButtonStatus
 +
|-
 +
| 0x4
 +
| 0x1
 +
| SharedButtonStatus
 +
|-
 +
| 0x5
 +
| 0x1
 +
| LeftPadButtonStatus
 +
|-
 +
| 0x6
 +
| 0x3
 +
| LeftAnalogStickData
 +
|-
 +
| 0x9
 +
| 0x3
 +
| RightAnalogStickData
 +
|-
 +
| 0xC
 +
| 0x1
 +
| MotorStatus
 +
|-
 +
| 0xD
 +
| 0x23
 +
| McuUpdateData
 +
|}
 +
 +
== HidBasicInputReport ==
 +
This is a 0x31-byte struct.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1
 +
| [[#HidReportId|ReportId]]
 +
|-
 +
| 0x1
 +
| 0x1
 +
| LatencyTimer
 +
|-
 +
| 0x2
 +
| 0x1
 +
| PowerInfo
 +
|-
 +
| 0x3
 +
| 0x1
 +
| RightPadButtonStatus
 +
|-
 +
| 0x4
 +
| 0x1
 +
| SharedButtonStatus
 +
|-
 +
| 0x5
 +
| 0x1
 +
| LeftPadButtonStatus
 +
|-
 +
| 0x6
 +
| 0x3
 +
| LeftAnalogStickData
 +
|-
 +
| 0x9
 +
| 0x3
 +
| RightAnalogStickData
 +
|-
 +
| 0xC
 +
| 0x1
 +
| MotorStatus
 +
|-
 +
| 0xD
 +
| 0x24
 +
| BasicData
 +
|}
 +
 +
== HidMcuInputReport ==
 +
This is a 0x16A-byte struct.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1
 +
| [[#HidReportId|ReportId]]
 +
|-
 +
| 0x1
 +
| 0x1
 +
| LatencyTimer
 +
|-
 +
| 0x2
 +
| 0x1
 +
| PowerInfo
 +
|-
 +
| 0x3
 +
| 0x1
 +
| RightPadButtonStatus
 +
|-
 +
| 0x4
 +
| 0x1
 +
| SharedButtonStatus
 +
|-
 +
| 0x5
 +
| 0x1
 +
| LeftPadButtonStatus
 +
|-
 +
| 0x6
 +
| 0x3
 +
| LeftAnalogStickData
 +
|-
 +
| 0x9
 +
| 0x3
 +
| RightAnalogStickData
 +
|-
 +
| 0xC
 +
| 0x1
 +
| MotorStatus
 +
|-
 +
| 0xD
 +
| 0x6
 +
| SensorAccelSample0
 +
|-
 +
| 0x13
 +
| 0x6
 +
| SensorGyroSample0
 +
|-
 +
| 0x19
 +
| 0x6
 +
| SensorAccelSample1
 +
|-
 +
| 0x1F
 +
| 0x6
 +
| SensorGyroSample1
 +
|-
 +
| 0x25
 +
| 0x6
 +
| SensorAccelSample2
 +
|-
 +
| 0x2B
 +
| 0x6
 +
| SensorGyroSample2
 +
|-
 +
| 0x31
 +
| 0x139
 +
| McuData
 +
|}
 +
 +
== HidAttachmentInputReport ==
 +
This is a 0x16A-byte struct.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1
 +
| [[#HidReportId|ReportId]]
 +
|-
 +
| 0x1
 +
| 0x1
 +
| LatencyTimer
 +
|-
 +
| 0x2
 +
| 0x1
 +
| PowerInfo
 +
|-
 +
| 0x3
 +
| 0x1
 +
| RightPadButtonStatus
 +
|-
 +
| 0x4
 +
| 0x1
 +
| SharedButtonStatus
 +
|-
 +
| 0x5
 +
| 0x1
 +
| LeftPadButtonStatus
 +
|-
 +
| 0x6
 +
| 0x3
 +
| LeftAnalogStickData
 +
|-
 +
| 0x9
 +
| 0x3
 +
| RightAnalogStickData
 +
|-
 +
| 0xC
 +
| 0x1
 +
| MotorStatus
 +
|-
 +
| 0xD
 +
| 0x6
 +
| SensorAccelSample0
 +
|-
 +
| 0x13
 +
| 0x6
 +
| SensorGyroSample0
 +
|-
 +
| 0x19
 +
| 0x6
 +
| SensorAccelSample1
 +
|-
 +
| 0x1F
 +
| 0x6
 +
| SensorGyroSample1
 +
|-
 +
| 0x25
 +
| 0x6
 +
| SensorAccelSample2
 +
|-
 +
| 0x2B
 +
| 0x6
 +
| SensorGyroSample2
 +
|-
 +
| 0x31
 +
| 0x139
 +
| AttachmentData
 +
|}
 +
 +
== HidGenericInputReport ==
 +
This is a 0xC-byte struct.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1
 +
| [[#HidReportId|ReportId]]
 +
|-
 +
| 0x1
 +
| 0x2
 +
| ButtonStatus
 +
|-
 +
| 0x3
 +
| 0x1
 +
| StickHatData
 +
|-
 +
| 0x4
 +
| 0x4
 +
| LeftAnalogStickData
 +
|-
 +
| 0x8
 +
| 0x4
 +
| RightAnalogStickData
 +
|}
 +
 +
== HidCommandOutputReport ==
 +
This is a 0x31-byte struct.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1
 +
| [[#HidReportId|ReportId]]
 +
|-
 +
| 0x1
 +
| 0x1
 +
| PacketNumber
 +
|-
 +
| 0x2
 +
| 0x8
 +
| [[#HidMotorData|MotorData]]
 +
|-
 +
| 0xA
 +
| 0x1
 +
| [[#HidCommand|CommandId]]
 +
|-
 +
| 0xB
 +
| 0x26
 +
| CommandData
 +
|}
 +
 +
== HidMcuUpdateOutputReport ==
 +
This is a 0x13E-byte struct.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1
 +
| [[#HidReportId|ReportId]]
 +
|-
 +
| 0x1
 +
| 0x1
 +
| PacketNumber
 +
|-
 +
| 0x2
 +
| 0x8
 +
| [[#HidMotorData|MotorData]]
 +
|-
 +
| 0xA
 +
| 0x134
 +
| McuUpdateData
 +
|}
 +
 +
== HidBasicOutputReport ==
 +
This is a 0xA-byte struct.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1
 +
| [[#HidReportId|ReportId]]
 +
|-
 +
| 0x1
 +
| 0x1
 +
| PacketNumber
 +
|-
 +
| 0x2
 +
| 0x8
 +
| [[#HidMotorData|MotorData]]
 +
|}
 +
 +
== HidMcuOutputReport ==
 +
This is a 0x30-byte struct.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1
 +
| [[#HidReportId|ReportId]]
 +
|-
 +
| 0x1
 +
| 0x1
 +
| PacketNumber
 +
|-
 +
| 0x2
 +
| 0x8
 +
| [[#HidMotorData|MotorData]]
 +
|-
 +
| 0xA
 +
| 0x26
 +
| McuData
 +
|}
 +
 +
== HidAttachmentOutputReport ==
 +
This is a 0x30-byte struct.
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1
 +
| [[#HidReportId|ReportId]]
 +
|-
 +
| 0x1
 +
| 0x1
 +
| PacketNumber
 +
|-
 +
| 0x2
 +
| 0x8
 +
| [[#HidMotorData|MotorData]]
 +
|-
 +
| 0xA
 +
| 0x26
 +
| AttachmentData
 +
|}
 +
 +
== HidReportId ==
 +
{| class="wikitable" border="1"
 +
! Value
 +
! Description
 +
|-
 +
| 0x01 || CommandOutputReport
 +
|-
 +
| 0x03 || McuUpdateOutputReport
 +
|-
 +
| 0x10 || BasicOutputReport
 +
|-
 +
| 0x11 || McuOutputReport
 +
|-
 +
| 0x12 || AttachmentOutputReport
 +
|-
 +
| 0x21 || CommandInputReport
 +
|-
 +
| 0x23 || McuUpdateInputReport
 +
|-
 +
| 0x30 || BasicInputReport
 +
|-
 +
| 0x31 || McuInputReport
 +
|-
 +
| 0x32 || AttachmentInputReport
 +
|-
 +
| 0x33 ||
 +
|-
 +
| 0x3F || GenericInputReport
 +
|-
 +
| 0x70 || OtaEnableFwuReport
 +
|-
 +
| 0x71 || OtaSetupReadReport
 +
|-
 +
| 0x72 || OtaReadReport
 +
|-
 +
| 0x73 || OtaWriteReport
 +
|-
 +
| 0x74 || OtaEraseReport
 +
|-
 +
| 0x75 || OtaLaunchReport
 +
|-
 +
| 0x80 || ExtGripOutputReport
 +
|-
 +
| 0x81 || ExtGripInputReport
 +
|-
 +
| 0x82 ||
 +
|}
 +
 +
== HidMotorData ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x4 || [[#VibrationAmFmPackTag|JoyLeftVibrationAmFmPackTag]]
 +
|-
 +
| 0x4 || 0x8 || [[#VibrationAmFmPackTag|JoyRightVibrationAmFmPackTag]]
 +
|}
 +
 +
== VibrationAmFmPackTag ==
 +
This is "nn::xcd::VibrationAmFmPackTag". This is a BitPack object.
 +
 +
=== VibrationAmFmPackFormatZero ===
 +
{| class="wikitable" border="1"
 +
! Bits
 +
! Description
 +
|-
 +
| 0-29 || Reserved
 +
|-
 +
| 30-31 || PackFormat (must be 0)
 +
|}
 +
 +
=== VibrationAmFmPackFormatOne ===
 +
{| class="wikitable" border="1"
 +
! Bits
 +
! Description
 +
|-
 +
| 0-19 || Reserved
 +
|-
 +
| 20-24 || ChannelCodesHigh
 +
|-
 +
| 25-29 || ChannelCodesLow
 +
|-
 +
| 30-31 || PackFormat (must be 1)
 +
|}
 +
 +
=== VibrationAmFmPackFormatOne28bit ===
 +
{| class="wikitable" border="1"
 +
! Bits
 +
! Description
 +
|-
 +
| 0-1 || Reserved
 +
|-
 +
| 2-8 || ChannelFrequencyHigh
 +
|-
 +
| 9-15 || ChannelAmplitudeHigh
 +
|-
 +
| 16-22 || ChannelFrequencyLow
 +
|-
 +
| 23-29 || ChannelAmplitudeLow
 +
|-
 +
| 30-31 || PackFormat (must be 1)
 +
|}
 +
 +
=== VibrationAmFmPackFormatTwo ===
 +
{| class="wikitable" border="1"
 +
! Bits
 +
! Description
 +
|-
 +
| 0-9 || Reserved
 +
|-
 +
| 10-14 || VibrationCodesHigh
 +
|-
 +
| 15-19 || VibrationCodesLow
 +
|-
 +
| 20-24 || ChannelCodesHigh
 +
|-
 +
| 25-29 || ChannelCodesLow
 +
|-
 +
| 30-31 || PackFormat (must be 2)
 +
|}
 +
 +
=== VibrationAmFmPackFormatTwo14bitLow ===
 +
{| class="wikitable" border="1"
 +
! Bits
 +
! Description
 +
|-
 +
| 0 || IsChannelHigh (must be 0)
 +
|-
 +
| 1-7 || ChannelFrequency
 +
|-
 +
| 8-12 || VibrationCodesHigh1
 +
|-
 +
| 13-17 || VibrationCodesLow1
 +
|-
 +
| 18-22 || VibrationCodesHigh0
 +
|-
 +
| 23-29 || ChannelAmplitude
 +
|-
 +
| 30-31 || PackFormat (must be 2)
 +
|}
 +
 +
=== VibrationAmFmPackFormatTwo14bitHigh ===
 +
{| class="wikitable" border="1"
 +
! Bits
 +
! Description
 +
|-
 +
| 0 || IsChannelHigh (must be 1)
 +
|-
 +
| 1-7 || ChannelFrequency
 +
|-
 +
| 8-12 || VibrationCodesHigh1
 +
|-
 +
| 13-17 || VibrationCodesLow1
 +
|-
 +
| 18-22 || VibrationCodesLow0
 +
|-
 +
| 23-29 || ChannelAmplitude
 +
|-
 +
| 30-31 || PackFormat (must be 2)
 +
|}
 +
 +
=== VibrationAmFmPackFormatThree ===
 +
{| class="wikitable" border="1"
 +
! Bits
 +
! Description
 +
|-
 +
| 0-4 || VibrationCodesHigh1
 +
|-
 +
| 5-9 || VibrationCodesLow1
 +
|-
 +
| 10-14 || VibrationCodesHigh0
 +
|-
 +
| 15-19 || VibrationCodesLow0
 +
|-
 +
| 20-24 || ChannelCodesHigh
 +
|-
 +
| 25-29 || ChannelCodesLow
 +
|-
 +
| 30-31 || PackFormat (must be 3)
 +
|}
 +
 +
=== VibrationAmFmPackFormatThree7bit ===
 +
{| class="wikitable" border="1"
 +
! Bits
 +
! Description
 +
|-
 +
| 0 || IsChannelHigh
 +
|-
 +
| 1 || IsThree7bit (must be 1)
 +
|-
 +
| 2 || IsFm
 +
|-
 +
| 3-7 || VibrationCodesHigh1
 +
|-
 +
| 8-12 || VibrationCodesLow1
 +
|-
 +
| 13-17 || VibrationCodesHigh0
 +
|-
 +
| 18-22 || VibrationCodesLow0
 +
|-
 +
| 23-29 || ChannelAmFm
 +
|-
 +
| 30-31 || PackFormat (must be 1, instead of 3)
 +
|}
 +
 +
== AmFmCodes ==
 +
These are 32-bit values used by the Joy-Con firmware to represent combinations of amplitude/frequency pairs for vibration.
 +
 +
=== Unpacking ===
 +
The Joy-Con firmware receives vibration data packed as [[#VibrationAmFmPackTag|VibrationAmFmPackTag]] from output reports. Depending on the packing format, these tags are then converted to an array of AmFmCodes as follows.
 +
 +
==== AmFm5BitCodes ====
 +
Converted from [[#VibrationAmFmPackFormatOne|VibrationAmFmPackFormatOne]], [[#VibrationAmFmPackFormatTwo|VibrationAmFmPackFormatTwo]] or [[#VibrationAmFmPackFormatThree|VibrationAmFmPackFormatThree]].
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x4 || <nowiki>(ChannelCodesLow & 0x1F)</nowiki>
 +
|-
 +
| 0x4 || 0x4 || <nowiki>(ChannelCodesHigh & 0x1F)</nowiki>
 +
|-
 +
| 0x8 || 0x4 || <nowiki>(VibrationCodesLow0 & 0x1F)</nowiki>
 +
|-
 +
| 0xC || 0x4 || <nowiki>(VibrationCodesHigh0 & 0x1F)</nowiki>
 +
|-
 +
| 0x10 || 0x4 || <nowiki>(VibrationCodesLow1 & 0x1F)</nowiki>
 +
|-
 +
| 0x14 || 0x4 || <nowiki>(VibrationCodesHigh1 & 0x1F)</nowiki>
 +
|}
 +
 +
==== AmFm7BitOneCodes ====
 +
Converted from [[#VibrationAmFmPackFormatOne28bit|VibrationAmFmPackFormatOne28bit]].
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x4 || <nowiki>(((ChannelFrequencyLow & 0x7F) << 8) | (ChannelAmplitudeLow & 0x7F) | 0x8080)</nowiki>
 +
|-
 +
| 0x4 || 0x4 || <nowiki>(((ChannelFrequencyHigh & 0x7F) << 8) | (ChannelAmplitudeHigh & 0x7F) | 0x8080)</nowiki>
 +
|}
 +
 +
==== AmFm7BitTwoCodes ====
 +
Converted from [[#VibrationAmFmPackFormatTwo14bitLow|VibrationAmFmPackFormatTwo14bitLow]] or [[#VibrationAmFmPackFormatTwo14bitHigh|VibrationAmFmPackFormatTwo14bitHigh]].
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x4 || <nowiki>IsChannelHigh ? (VibrationCodesLow0 & 0x1F) : (((ChannelFrequency & 0x7F) << 8) | (ChannelAmplitude & 0x7F) | 0x8080)</nowiki>
 +
|-
 +
| 0x4 || 0x4 || <nowiki>IsChannelHigh ? (((ChannelFrequency & 0x7F) << 8) | (ChannelAmplitude & 0x7F) | 0x8080) : (VibrationCodesHigh0 & 0x1F)</nowiki>
 +
|-
 +
| 0x8 || 0x4 || <nowiki>(VibrationCodesLow1 & 0x1F)</nowiki>
 +
|-
 +
| 0xC || 0x4 || <nowiki>(VibrationCodesHigh1 & 0x1F)</nowiki>
 +
|-
 +
| 0x10 || 0x4 || <nowiki>Always 0x18</nowiki>
 +
|-
 +
| 0x14 || 0x4 || <nowiki>Always 0x18</nowiki>
 +
|}
 +
 +
==== AmFm7BitThreeCodes ====
 +
Converted from [[#VibrationAmFmPackFormatThree7bit|VibrationAmFmPackFormatThree7bit]].
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x4 || <nowiki>IsChannelHigh ? 0x18 : (IsFm ? (((ChannelAmFm & 0x7F) << 8) | 0x8000) : ((ChannelAmFm & 0x7F) | 0x80))</nowiki>
 +
|-
 +
| 0x4 || 0x4 || <nowiki>IsChannelHigh ? (IsFm ? (((ChannelAmFm & 0x7F) << 8) | 0x8000) : ((ChannelAmFm & 0x7F) | 0x80)) : 0x18</nowiki>
 +
|-
 +
| 0x8 || 0x4 || <nowiki>(VibrationCodesLow0 & 0x1F)</nowiki>
 +
|-
 +
| 0xC || 0x4 || <nowiki>(VibrationCodesHigh0 & 0x1F)</nowiki>
 +
|-
 +
| 0x10 || 0x4 || <nowiki>(VibrationCodesLow1 & 0x1F)</nowiki>
 +
|-
 +
| 0x14 || 0x4 || <nowiki>(VibrationCodesHigh1 & 0x1F)</nowiki>
 
|}
 
|}
   Line 295: Line 1,062:  
|-
 
|-
 
| 0xD9 || ExtDevInfo
 
| 0xD9 || ExtDevInfo
 +
|}
 +
 +
== ExtGripCommand ==
 +
{| class="wikitable" border="1"
 +
! Value
 +
! Description
 +
|-
 +
| 0x01 || Inquiry
 +
|-
 +
| 0x02 || CreateHidConnection
 +
|-
 +
| 0x03 || DeleteHidConnection
 +
|-
 +
| 0x04 || StartHidData
 +
|-
 +
| 0x05 || StopHidData
 +
|-
 +
| 0x06 ||
 +
|-
 +
| 0x07 || GetFirmwareVersion
 +
|-
 +
| 0x08 ||
 +
|-
 +
| 0x91 || LoopbackTest
 +
|-
 +
| 0x92 ||
 +
|-
 +
| 0xA0 || SetUartClockTrim
 
|}
 
|}
   Line 306: Line 1,101:  
! Description
 
! Description
 
|-
 
|-
| 0x00 || 0x14 || Magic number??
+
| 0x0 || 0x1000 || StaticSection
 
|-
 
|-
| 0x15 || 0x06 || Unique MAC Address of controller
+
| 0x1000 || 0x1000 || [[#FailsafeSection|FailsafeSection]]
 
|-
 
|-
| 0x3B3 || 0x04 || Offset to Factory Firmware
+
| 0x2000 || 0x1000 || [[#VolatileSection|VolatileSection]]
 
|-
 
|-
| 0x1FF4 || 0x08 || OTA Magic, if the controller is Over-The-Air updated.
+
| 0x3000 || 0x1000 || VolatileSectionBackup1
 
|-
 
|-
| 0x1FFC || 0x04 || Offset to OTA Firmware, if OTA Magic is valid.
+
| 0x4000 || 0x1000 || VolatileSectionBackup2
 
|-
 
|-
| 0x2000 || 0x1000 || PairingInfo
+
| 0x5000 || 0x1000 || [[#ShipmentInfo|ShipmentInfo]]
 
|-
 
|-
| 0x5000 || 0x1 || Shipment
+
| 0x6000 || 0x1000 || [[#FactoryConfiguration|FactoryConfiguration]]
 
|-
 
|-
| 0x6000 || 0x1000 || [[#FactoryConfiguration|FactoryConfiguration]]
+
| 0x7000 || 0x1000 || Reserved
 
|-
 
|-
 
| 0x8000 || 0x1000 || [[#UserCalibration|UserCalibration]]
 
| 0x8000 || 0x1000 || [[#UserCalibration|UserCalibration]]
 +
|-
 +
| 0x9000 || 0x7000 || Reserved
 +
|-
 +
| 0x10000 || 0x18000 || DynamicSection1
 +
|-
 +
| 0x28000 || 0x18000 || DynamicSection2
 +
|-
 +
| 0x40000 || 0x40000 || Reserved
 +
|}
 +
 +
== FailsafeSection ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0xFF4 || Reserved
 +
|-
 +
| 0xFF4 || 0x8 || Signature
 +
|-
 +
| 0xFFC || 0x4 || Ds2Offset
 +
|}
 +
 +
== VolatileSection ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x26 ||
 +
|-
 +
| 0x26 || 0xFDA || Reserved
 +
|}
 +
 +
== ShipmentInfo ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x1 || Shipment
 +
|-
 +
| 0x1 || 0xFFF || Reserved
 
|}
 
|}
   Line 332: Line 1,173:  
! Description
 
! Description
 
|-
 
|-
| 0x00 || 0x10 || IdentificationCode
+
| 0x0 || 0x10 || IdentificationCode
 
|-
 
|-
| 0x12 || 0x01 || [[#Type|Type]]
+
| 0x10 || 0x2 || Reserved
 
|-
 
|-
| 0x1B || 0x01 || FormatVersion
+
| 0x12 || 0x1 || [[#DeviceType|DeviceType]]
 +
|-
 +
| 0x13 || 0x1 || BoardRevision
 +
|-
 +
| 0x14 || 0x7 || Reserved
 +
|-
 +
| 0x1B || 0x1 || FormatVersion
 +
|-
 +
| 0x1C || 0x4 || Reserved
 
|-
 
|-
 
| 0x20 || 0x18 || [[#Cal1|Cal1]]
 
| 0x20 || 0x18 || [[#Cal1|Cal1]]
 +
|-
 +
| 0x38 || 0x5 || Reserved
 
|-
 
|-
 
| 0x3D || 0x12 || [[#Cal2|Cal2]]
 
| 0x3D || 0x12 || [[#Cal2|Cal2]]
 
|-
 
|-
| 0x4F || 0x01 || Reserved
+
| 0x4F || 0x1 || Reserved
 
|-
 
|-
| 0x50 || 0x0D || [[#Design|Design]]
+
| 0x50 || 0xD || [[#Design|Design]]
 +
|-
 +
| 0x5D || 0x23 || Reserved
 
|-
 
|-
 
| 0x80 || 0x18 || [[#Model1|Model1]]
 
| 0x80 || 0x18 || [[#Model1|Model1]]
 
|-
 
|-
 
| 0x98 || 0x12 || [[#Model2|Model2]]
 
| 0x98 || 0x12 || [[#Model2|Model2]]
 +
|-
 +
| 0xAA || 0x1 || Reserved
 +
|-
 +
| 0xAB || 0x1 || AccelerometerAxisAssignment
 +
|-
 +
| 0xAC || 0x1 || GyroscopeAxisAssignment
 +
|-
 +
| 0xAD || 0x1 || AnalogStickMainAxisAssignment
 +
|-
 +
| 0xAE || 0x1 || AnalogStickSubAxisAssignment
 +
|-
 +
| 0xAF || 0x151 || Reserved
 +
|-
 +
| 0x200 || 0x2 || BatteryVoltage
 +
|-
 +
| 0x202 || 0xB7E || Reserved
 +
|-
 +
| 0xD80 || 0x2 || TarragonVid
 +
|-
 +
| 0xD82 || 0x2 || TarragonPid
 +
|-
 +
| 0xD84 || 0x7C || Reserved
 +
|-
 +
| 0xE00 || 0x100 || InspectionLog
 +
|-
 +
| 0xF00 || 0x100 || Reserved
 
|}
 
|}
   −
=== Type ===
+
=== DeviceType ===
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 357: Line 1,236:  
! Description
 
! Description
 
|-
 
|-
| 0x01 || JoyLeft
+
| 0x01 || JoyConLeft
 
|-
 
|-
| 0x02 || JoyRight
+
| 0x02 || JoyConRight
 
|-
 
|-
 
| 0x03 || SwitchProController
 
| 0x03 || SwitchProController
 
|-
 
|-
| 0x04 || ([[HID_services#DeviceTypeInternal|DeviceType]] 4)
+
| 0x04 || MiyabiLeft
 
|-
 
|-
| 0x05 || ([[HID_services#DeviceTypeInternal|DeviceType]] 5)
+
| 0x05 || MiyabiRight
 
|-
 
|-
| 0x06 || ([[HID_services#DeviceTypeInternal|DeviceType]] 6)
+
| 0x06 || Tarragon
 
|-
 
|-
| 0x07 || LarkHvc1
+
| 0x07 || LarkH1
 
|-
 
|-
| 0x08 || LarkHvc2
+
| 0x08 || LarkH2
 
|-
 
|-
| 0x09 || LarkNesLeft
+
| 0x09 || LarkNL
 
|-
 
|-
| 0x0A || LarkNesRight
+
| 0x0A || LarkNR
 
|-
 
|-
 
| 0x0B || Lucia
 
| 0x0B || Lucia
Line 383: Line 1,262:  
| 0x0D || [13.0.0+] Lager
 
| 0x0D || [13.0.0+] Lager
 
|-
 
|-
| 0x0E || [14.0.0+] ([[HID_services#DeviceTypeInternal|DeviceType]] 30)
+
| 0x0E || [14.0.0+] Tarragon2
 
|-
 
|-
| 0x21 || FiftyLeft ([[HID_services#DeviceTypeInternal|DeviceType]] 14)
+
| 0x21 || FiftyL
 
|-
 
|-
| 0x22 || FiftyRight ([[HID_services#DeviceTypeInternal|DeviceType]] 18)
+
| 0x22 || FiftyR
 
|}
 
|}
   Line 397: Line 1,276:  
! Description
 
! Description
 
|-
 
|-
| 0x00 || 0x18 || SixAxisSensorCalibrationValue
+
| 0x0 || 0x18 || [[#SixAxisSensorCalibrationValue|SixAxisSensorCalibrationValue]]
 +
|}
 +
 
 +
==== SixAxisSensorCalibrationValue ====
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x2 || Accelerometer0OffsetX
 +
|-
 +
| 0x2 || 0x2 || Accelerometer0OffsetY
 +
|-
 +
| 0x4 || 0x2 || Accelerometer0OffsetZ
 +
|-
 +
| 0x6 || 0x2 || Accelerometer1gScaleX
 +
|-
 +
| 0x8 || 0x2 || Accelerometer1gScaleY
 +
|-
 +
| 0xA || 0x2 || Accelerometer1gScaleZ
 +
|-
 +
| 0xC || 0x2 || Gyroscope0OffsetX
 +
|-
 +
| 0xE || 0x2 || Gyroscope0OffsetY
 +
|-
 +
| 0x10 || 0x2 || Gyroscope0OffsetZ
 +
|-
 +
| 0x12 || 0x2 || Gyroscope78rpmScaleX
 +
|-
 +
| 0x14 || 0x2 || Gyroscope78rpmScaleY
 +
|-
 +
| 0x16 || 0x2 || Gyroscope78rpmScaleZ
 
|}
 
|}
   Line 407: Line 1,318:  
! Description
 
! Description
 
|-
 
|-
| 0x00 || 0x09 || LeftAnalogStickCalibrationValue
+
| 0x0 || 0x9 || [[#AnalogStickCalibrationValue|AnalogStickMainCalibrationValue]]
 +
|-
 +
| 0x9 || 0x9 || [[#AnalogStickCalibrationValue|AnalogStickSubCalibrationValue]]
 +
|}
 +
 
 +
==== AnalogStickCalibrationValue ====
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x1 || AnalogStickCalXPositive
 +
|-
 +
| 0x1 || 0x2 || AnalogStickCalYPositive
 +
|-
 +
| 0x3 || 0x1 || AnalogStickCalX0
 
|-
 
|-
| 0x09 || 0x09 || RightAnalogStickCalibrationValue
+
| 0x4 || 0x2 || AnalogStickCalY0
 +
|-
 +
| 0x6 || 0x1 || AnalogStickCalXNegative
 +
|-
 +
| 0x7 || 0x2 || AnalogStickCalYNegative
 
|}
 
|}
   Line 419: Line 1,350:  
! Description
 
! Description
 
|-
 
|-
| 0x00 || 0x0C || [[#ControllerColor|ControllerColor]]
+
| 0x0 || 0xC || [[#ControllerColor|ControllerColor]]
 
|-
 
|-
| 0x0C || 0x01 || [[#DesignVariation|DesignVariation]]
+
| 0xC || 0x1 || [[#DesignVariation|DesignVariation]]
 
|}
 
|}
   Line 431: Line 1,362:  
! Description
 
! Description
 
|-
 
|-
| 0x00 || 0x03 || Body color of controller in RGB Hex (see [[Joy-Con#Colors|Joy-Con Colors]])
+
| 0x0 || 0x1 || MainColorR
 
|-
 
|-
| 0x03 || 0x03 || Button color of controller in RGB Hex (see [[Joy-Con#Colors|Joy-Con Colors]])
+
| 0x1 || 0x1 || MainColorG
 
|-
 
|-
| 0x06 || 0x03 || Left grip color of controller in RGB Hex
+
| 0x2 || 0x1 || MainColorB
 
|-
 
|-
| 0x09 || 0x03 || Right grip color of controller in RGB Hex
+
| 0x3 || 0x1 || SubColorR
 +
|-
 +
| 0x4 || 0x1 || SubColorG
 +
|-
 +
| 0x5 || 0x1 || SubColorB
 +
|-
 +
| 0x6 || 0x1 || 3rdColorR
 +
|-
 +
| 0x7 || 0x1 || 3rdColorG
 +
|-
 +
| 0x8 || 0x1 || 3rdColorB
 +
|-
 +
| 0x9 || 0x1 || 4thColorR
 +
|-
 +
| 0xA || 0x1 || 4thColorG
 +
|-
 +
| 0xB || 0x1 || 4thColorB
 
|}
 
|}
   Line 446: Line 1,393:  
! Name
 
! Name
 
|-
 
|-
| 0x00 || LuciaJ, LagerJ
+
| 0x0 || LuciaJ, LagerJ
 
|-
 
|-
| 0x01 || LuciaE, LagerE
+
| 0x1 || LuciaE, LagerE
 
|-
 
|-
| 0x02 || LuciaU, LagerU
+
| 0x2 || LuciaU, LagerU
 
|}
 
|}
   Line 460: Line 1,407:  
! Description
 
! Description
 
|-
 
|-
| 0x00 || 0x06 || SensorData
+
| 0x0 || 0x6 || [[#SixAxisSensorModelValue|SixAxisSensorModelValue]]
 +
|-
 +
| 0x6 || 0x12 || [[#AnalogStickModelValue|AnalogStickMainModelValue]]
 +
|}
 +
 
 +
==== SixAxisSensorModelValue ====
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x2 || SixAxisHorizontalOffsetX
 +
|-
 +
| 0x2 || 0x2 || SixAxisHorizontalOffsetY
 
|-
 
|-
| 0x06 || 0x12 || AnalogStickModuleParam
+
| 0x4 || 0x2 || SixAxisHorizontalOffsetZ
 +
|}
 +
 
 +
==== AnalogStickModelValue ====
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x1 || AnalogStickModelNoise
 +
|-
 +
| 0x1 || 0x2 || AnalogStickModelTypicalStroke
 +
|-
 +
| 0x3 || 0x1 || AnalogStickModelCenterDeadZoneSize
 +
|-
 +
| 0x4 || 0x2 || AnalogStickModelCircuitDeadZoneScale
 +
|-
 +
| 0x6 || 0x1 || AnalogStickModelMinimumStrokeXPositive
 +
|-
 +
| 0x7 || 0x2 || AnalogStickModelMinimumStrokeYPositive
 +
|-
 +
| 0x9 || 0x1 || AnalogStickModelMinimumStrokeXNegative
 +
|-
 +
| 0xA || 0x2 || AnalogStickModelMinimumStrokeYNegative
 +
|-
 +
| 0xC || 0x1 || AnalogStickModelCenterRangeXPositive
 +
|-
 +
| 0xD || 0x2 || AnalogStickModelCenterRangeYPositive
 +
|-
 +
| 0xF || 0x1 || AnalogStickModelCenterRangeXNegative
 +
|-
 +
| 0x10 || 0x2 || AnalogStickModelCenterRangeYNegative
 
|}
 
|}
   Line 472: Line 1,465:  
! Description
 
! Description
 
|-
 
|-
| 0x00 || 0x12 || AnalogStickModuleParam
+
| 0x0 || 0x12 || [[#AnalogStickModelValue|AnalogStickSubModelValue]]
 
|}
 
|}
   Line 482: Line 1,475:  
! Description
 
! Description
 
|-
 
|-
| 0x10 || 0x18 || [[#UserCal1|UserCal1]]
+
| 0x0 || 0x10 || Reserved
 
|-
 
|-
| 0x28 || 0x18 || [[#UserCal2|UserCal2]]
+
| 0x10 || 0x16 || [[#UserCal1|UserCal1]]
 +
|-
 +
| 0x26 || 0x1A || [[#UserCal2|UserCal2]]
 +
|-
 +
| 0x40 || 0xFC0 || Reserved
 
|}
 
|}
   Line 494: Line 1,491:  
! Description
 
! Description
 
|-
 
|-
| 0x00 || 0x02 || UserCalMagicNumber
+
| 0x0 || 0x2 || AnalogStickMainUserMagicNumber
|-
  −
| 0x02 || 0x09 || LeftAnalogStickCalibrationValue
   
|-
 
|-
| 0x0B || 0x02 || UserCalMagicNumber
+
| 0x2 || 0x9 || [[#AnalogStickCalibrationValue|AnalogStickMainUserCalibrationValue]]
 
|-
 
|-
| 0x0D || 0x09 || RightAnalogStickCalibrationValue
+
| 0xB || 0x2 || AnalogStickSubUserMagicNumber
 
|-
 
|-
| 0x16 || 0x02 || UserCalMagicNumber
+
| 0xD || 0x9 || [[#AnalogStickCalibrationValue|AnalogStickSubUserCalibrationValue]]
 
|}
 
|}
   Line 512: Line 1,507:  
! Description
 
! Description
 
|-
 
|-
| 0x00 || 0x18 || SixAxisSensorCalibrationValue
+
| 0x0 || 0x2 || SixAxisUserCalibrationMagicNumber
 +
|-
 +
| 0x2 || 0x18 || [[#SixAxisSensorCalibrationValue|SixAxisUserCalibrationValue]]
 
|}
 
|}