Changes

2,746 bytes removed ,  20:42, 20 August 2023
Clean up and merge in preparation for documentation
Line 1: Line 1: −
Joy-Con is the name for the Switch's primary game controllers. The controllers communicate to the console through bluetooth and can be disconnected from the main unit.
+
Joy-Con is the name for the Switch's primary game controllers. The Joy-Con are internally called Ukyo (Left) and Sakyo (Right).
    
= Hardware =
 
= Hardware =
The controllers themselves are simple to disassemble and identify.
+
== Ukyo ==
[[File:JoyconFront.jpg|400px|thumb|The front of the Joy-Con internal[https://www.ifixit.com/Teardown/Nintendo+Switch+Teardown/78263]]]
  −
[[File:JoyconRear.jpg|400px|thumb|The rear of the Joy-Con internal[https://www.ifixit.com/Teardown/Nintendo+Switch+Teardown/78263]]]
   
{| class="wikitable"
 
{| class="wikitable"
! Color || Item
+
! Component || Description
 
|-
 
|-
| Red || Broadcom BCM20734 Bluetooth 4.1/2.4 GHz Transceiver
+
| SoC || Broadcom BCM20734
 
|-
 
|-
| Orange || STMicroelectronics NFCBEA 812006 33 (Likely NFC reader IC)
+
| IMU || STMicroelectronics LSM6DS3H
 
|-
 
|-
| Yellow|| Macronix International MX25U4033E 4 Mb CMOS Flash
+
| PMIC || Texas Instruments BQ24072
 +
|-
 +
| Storage || Macronix International MX25U4033E 4 Mb CMOS Flash
 
|}
 
|}
   −
= Firmware =
+
== Sakyo ==
''See also: [[Joy-Con Firmware]]''
  −
 
  −
The firmware of the Joy-Cons seems to be generic across all instances. Details such as the handedness of the controller and the color is just indicated in a configuration part of the flash. Judging by quick glance at the firmware, it's probably identical to that used on the Pro Controller as well.
   
{| class="wikitable"
 
{| class="wikitable"
! Controller || 1.0.0
+
! Component || Description
 
|-
 
|-
| Joy-Con Left (Blue) || [[:File:pad.L.bin|flash dump]]
+
| SoC || Broadcom BCM20734
 
|-
 
|-
| Joy-Con Right (Red) || [[:File:pad.R.bin|flash dump]]
+
| MCU || STMicroelectronics STM32P411
 +
|-
 +
| NFC || STMicroelectronics ST21NFCB
 +
|-
 +
| IMU || STMicroelectronics LSM6DS3H
 +
|-
 +
| PMIC || Texas Instruments BQ24072
 +
|-
 +
| Storage || Macronix International MX25U4033E 4 Mb CMOS Flash
 
|}
 
|}
  −
The flash is in a patch-ram format. Tools for dealing with it are available [https://github.com/shuffle2/nxpad].
  −
A dump of the ROM region (taken while firmware was running) can be found [[:File:bcm20734_rom.bin|here]]. Note this is the same SoC used on the other controller models, as well.
      
= Protocol =
 
= Protocol =
Line 295: Line 297:  
|}
 
|}
   −
== Left & Right Separate Joy-con ==
+
= Firmware =
When paired directly to a computer over bluetooth, the joy-con both provide identical HID input report descriptor. This does not appear to include motion controls, IR data, or NFC. They both behave as detached single-player controllers.
+
The firmware is stored inside the flash in Broadcom's PatchRAM format as follows:
   −
HID Input Report Descriptor (Hexadecimal):
+
{| class="wikitable" border="1"
<pre>
  −
00000000: 05010905 A1010601 FF852109 21750895  ....¡...ÿ…!.!u.•
  −
00000010: 30810285 30093075 08953081 02853109  0..…0.0u.•0..…1.
  −
00000020: 31750896 69018102 85320932 75089669  1u.–i...…2.2u.–i
  −
00000030: 01810285 33093375 08966901 8102853F  ...…3.3u.–i...…?
  −
00000040: 05091901 29101500 25017501 95108102  ....)...%.u.•...
  −
00000050: 05010939 15002507 75049501 81420509  ...9..%.u.•..B..
  −
00000060: 75049501 81010501 09300931 09330934  u.•......0.1.3.4
  −
00000070: 16000027 FFFF0000 75109504 81020601  ...'ÿÿ..u.•.....
  −
00000080: FF850109 01750895 30910285 10091075  ÿ…...u.•0‘.…...u
  −
00000090: 08953091 02851109 11750895 30910285  .•0‘.…...u.•0‘.…
  −
000000A0: 12091275 08953091 02C0              ...u.•0‘.À
  −
</pre>
  −
 
  −
{| class="wikitable"
  −
! Parsed Bytes || Description
   
|-
 
|-
|0x05, 0x01,        || Usage Page (Generic Desktop Ctrls)
+
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
|0x09, 0x05,        || Usage (Game Pad)
+
| 0x00 || 0x14 || Magic number??
 
|-
 
|-
|0xA1, 0x01,        || Collection (Application)
+
| 0x15 || 0x06 || Unique MAC Address of controller
 
|-
 
|-
|0x06, 0x01, 0xFF,  ||   Usage Page (Vendor Defined 0xFF01)
+
| 0x3B3 || 0x04 || Offset to Factory Firmware
 
|-
 
|-
|0x85, 0x21,        ||   Report ID (33)
+
| 0x1FF4 || 0x08 || OTA Magic, if the controller is Over-The-Air updated.
 
|-
 
|-
|0x09, 0x21,        ||   Usage (0x21)
+
| 0x1FFC || 0x04 || Offset to OTA Firmware, if OTA Magic is valid.
 
|-
 
|-
|0x75, 0x08,        ||   Report Size (8)
+
| 0x2000 || 0x1000 || PairingInfo
 
|-
 
|-
|0x95, 0x30,        ||   Report Count (48)
+
| 0x5000 || 0x1 || Shipment
 
|-
 
|-
|0x81, 0x02,        ||   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+
| 0x6000 || 0x1000 || [[#FactoryConfiguration|FactoryConfiguration]]
 
|-
 
|-
|0x85, 0x30,        ||   Report ID (48)
+
| 0x8000 || 0x1000 || [[#UserCalibration|UserCalibration]]
 +
|}
 +
 
 +
== FactoryConfiguration ==
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x09, 0x30,        ||  Usage (0x30)
+
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
|0x75, 0x08,        ||   Report Size (8)
+
| 0x00 || 0x10 || IdentificationCode
 
|-
 
|-
|0x95, 0x30,        ||   Report Count (48)
+
| 0x12 || 0x01 || [[#Type|Type]]
 
|-
 
|-
|0x81, 0x02,        ||   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+
| 0x1B || 0x01 || FormatVersion
 
|-
 
|-
|0x85, 0x31,        ||   Report ID (49)
+
| 0x20 || 0x18 || [[#Cal1|Cal1]]
 
|-
 
|-
|0x09, 0x31,        ||   Usage (0x31)
+
| 0x3D || 0x12 || [[#Cal2|Cal2]]
 
|-
 
|-
|0x75, 0x08,        ||   Report Size (8)
+
| 0x4F || 0x01 || Reserved
 
|-
 
|-
|0x96, 0x69, 0x01,  ||   Report Count (361)
+
| 0x50 || 0x0D || [[#Design|Design]]
 
|-
 
|-
|0x81, 0x02,        ||   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+
| 0x80 || 0x18 || [[#Model1|Model1]]
 
|-
 
|-
|0x85, 0x32,        ||   Report ID (50)
+
| 0x98 || 0x12 || [[#Model2|Model2]]
 +
|}
 +
 
 +
=== Type ===
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x09, 0x32,        ||  Usage (0x32)
+
! Value
 +
! Description
 
|-
 
|-
|0x75, 0x08,        ||   Report Size (8)
+
| 0x01 || JoyLeft
 
|-
 
|-
|0x96, 0x69, 0x01,  ||   Report Count (361)
+
| 0x02 || JoyRight
 
|-
 
|-
|0x81, 0x02,        ||   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+
| 0x03 || SwitchProController
 
|-
 
|-
|0x85, 0x33,        ||   Report ID (51)
+
| 0x04 || ([[HID_services#DeviceTypeInternal|DeviceType]] 4)
 
|-
 
|-
|0x09, 0x33,        ||   Usage (0x33)
+
| 0x05 || ([[HID_services#DeviceTypeInternal|DeviceType]] 5)
 
|-
 
|-
|0x75, 0x08,        ||   Report Size (8)
+
| 0x06 || ([[HID_services#DeviceTypeInternal|DeviceType]] 6)
 
|-
 
|-
|0x96, 0x69, 0x01,  ||   Report Count (361)
+
| 0x07 || LarkHvc1
 
|-
 
|-
|0x81, 0x02,        ||   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+
| 0x08 || LarkHvc2
 
|-
 
|-
|0x85, 0x3F,        ||   Report ID (63)
+
| 0x09 || LarkNesLeft
 
|-
 
|-
|0x05, 0x09,        ||   Usage Page (Button)
+
| 0x0A || LarkNesRight
 
|-
 
|-
|0x19, 0x01,        ||   Usage Minimum (0x01)
+
| 0x0B || Lucia
 
|-
 
|-
|0x29, 0x10,        ||   Usage Maximum (0x10)
+
| 0x0C || [12.0.0+] Lagon
 
|-
 
|-
|0x15, 0x00,        ||   Logical Minimum (0)
+
| 0x0D || [13.0.0+] Lager
 
|-
 
|-
|0x25, 0x01,        ||   Logical Maximum (1)
+
| 0x0E || [14.0.0+] ([[HID_services#DeviceTypeInternal|DeviceType]] 30)
 
|-
 
|-
|0x75, 0x01,        ||   Report Size (1)
+
| 0x21 || FiftyLeft ([[HID_services#DeviceTypeInternal|DeviceType]] 14)
 
|-
 
|-
|0x95, 0x10,        ||   Report Count (16)
+
| 0x22 || FiftyRight ([[HID_services#DeviceTypeInternal|DeviceType]] 18)
 +
|}
 +
 
 +
=== Cal1 ===
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x81, 0x02,        ||  Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
|0x05, 0x01,        ||   Usage Page (Generic Desktop Ctrls)
+
| 0x00 || 0x18 || SixAxisSensorCalibrationValue
 +
|}
 +
 
 +
=== Cal2 ===
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x09, 0x39,        ||  Usage (Hat switch)
+
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
|0x15, 0x00,        ||   Logical Minimum (0)
+
| 0x00 || 0x09 || LeftAnalogStickCalibrationValue
 
|-
 
|-
|0x25, 0x07,        ||   Logical Maximum (7)
+
| 0x09 || 0x09 || RightAnalogStickCalibrationValue
 +
|}
 +
 
 +
=== Design ===
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x75, 0x04,        ||  Report Size (4)
+
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
|0x95, 0x01,        ||   Report Count (1)
+
| 0x00 || 0x0C || [[#ControllerColor|ControllerColor]]
 
|-
 
|-
|0x81, 0x42,        ||   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
+
| 0x0C || 0x01 || [[#DesignVariation|DesignVariation]]
 +
|}
 +
 
 +
==== ControllerColor ====
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x05, 0x09,        ||  Usage Page (Button)
+
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
|0x75, 0x04,        ||   Report Size (4)
+
| 0x00 || 0x03 || Body color of controller in RGB Hex (see [[Joy-Con#Colors|Joy-Con Colors]])
 
|-
 
|-
|0x95, 0x01,        ||   Report Count (1)
+
| 0x03 || 0x03 || Button color of controller in RGB Hex (see [[Joy-Con#Colors|Joy-Con Colors]])
 
|-
 
|-
|0x81, 0x01,        ||   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+
| 0x06 || 0x03 || Left grip color of controller in RGB Hex
 
|-
 
|-
|0x05, 0x01,        ||   Usage Page (Generic Desktop Ctrls)
+
| 0x09 || 0x03 || Right grip color of controller in RGB Hex
 +
|}
 +
 
 +
==== DesignVariation ====
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x09, 0x30,        ||  Usage (X)
+
! Value
 +
! Name
 
|-
 
|-
|0x09, 0x31,        ||   Usage (Y)
+
| 0x00 || LuciaJ, LagerJ
 
|-
 
|-
|0x09, 0x33,        ||   Usage (Rx)
+
| 0x01 || LuciaE, LagerE
 
|-
 
|-
|0x09, 0x34,       ||   Usage (Ry)
+
| 0x02 || LuciaU, LagerU
 +
|}
 +
 
 +
=== Model1 ===
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x16, 0x00, 0x00,  ||  Logical Minimum (0)
+
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
|0x27, 0xFF, 0xFF, 0x00, 0x00,  ||   Logical Maximum (65534)
+
| 0x00 || 0x06 || SensorData
 
|-
 
|-
|0x75, 0x10,        ||   Report Size (16)
+
| 0x06 || 0x12 || AnalogStickModuleParam
 +
|}
 +
 
 +
=== Model2 ===
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x95, 0x04,        ||  Report Count (4)
+
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
|0x81, 0x02,        ||   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+
| 0x00 || 0x12 || AnalogStickModuleParam
 +
|}
 +
 
 +
== UserCalibration ==
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x06, 0x01, 0xFF,  ||  Usage Page (Vendor Defined 0xFF01)
+
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
|0x85, 0x01,        ||   Report ID (1)
+
| 0x10 || 0x18 || [[#UserCal1|UserCal1]]
 
|-
 
|-
|0x09, 0x01,        ||   Usage (0x01)
+
| 0x28 || 0x18 || [[#UserCal2|UserCal2]]
 +
|}
 +
 
 +
=== UserCal1 ===
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x75, 0x08,        ||  Report Size (8)
+
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
|0x95, 0x30,        ||   Report Count (48)
+
| 0x00 || 0x02 || UserCalMagicNumber
 
|-
 
|-
|0x91, 0x02,        ||   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+
| 0x02 || 0x09 || LeftAnalogStickCalibrationValue
 
|-
 
|-
|0x85, 0x10,        ||   Report ID (16)
+
| 0x0B || 0x02 || UserCalMagicNumber
 
|-
 
|-
|0x09, 0x10,        ||   Usage (0x10)
+
| 0x0D || 0x09 || RightAnalogStickCalibrationValue
 
|-
 
|-
|0x75, 0x08,        ||   Report Size (8)
+
| 0x16 || 0x02 || UserCalMagicNumber
 +
|}
 +
 
 +
=== UserCal2 ===
 +
{| class="wikitable" border="1"
 
|-
 
|-
|0x95, 0x30,        ||  Report Count (48)
+
! Offset
|-
+
! Size
|0x91, 0x02,        ||  Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+
! Description
|-
  −
|0x85, 0x11,        ||  Report ID (17)
  −
|-
  −
|0x09, 0x11,        ||  Usage (0x11)
  −
|-
  −
|0x75, 0x08,        ||  Report Size (8)
  −
|-
  −
|0x95, 0x30,        ||  Report Count (48)
  −
|-
  −
|0x91, 0x02,        ||  Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
  −
|-
  −
|0x85, 0x12,        ||  Report ID (18)
  −
|-
  −
|0x09, 0x12,        ||  Usage (0x12)
  −
|-
  −
|0x75, 0x08,        ||  Report Size (8)
  −
|-
  −
|0x95, 0x30,        ||  Report Count (48)
  −
|-
  −
|0x91, 0x02,        ||  Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
   
|-
 
|-
|0xC0,              || End Collection
+
| 0x00 || 0x18 || SixAxisSensorCalibrationValue
 
|}
 
|}
    
== Colors ==
 
== Colors ==
 
HEX codes for the colors shown in the "Controllers" menu of the Switch UI can be found in a Joy-con SPI dump starting at offset 0x6050. Body color is first followed by button color and each is 3 bytes long. These values are able to be re-written with any HEX color value to make the Joy-cons show up as different colors in the UI. The following is a list of official HEX colors recovered from SPI dumps.
 
HEX codes for the colors shown in the "Controllers" menu of the Switch UI can be found in a Joy-con SPI dump starting at offset 0x6050. Body color is first followed by button color and each is 3 bytes long. These values are able to be re-written with any HEX color value to make the Joy-cons show up as different colors in the UI. The following is a list of official HEX colors recovered from SPI dumps.
 +
 
{| class="wikitable"
 
{| class="wikitable"
 
! Developer Kit Joy-Con || Release || Body HEX || Button HEX
 
! Developer Kit Joy-Con || Release || Body HEX || Button HEX
Line 580: Line 617:  
| // *(Prize Awarded for Labo Contest - No Retail) // **(Available Japan Only)
 
| // *(Prize Awarded for Labo Contest - No Retail) // **(Available Japan Only)
 
|}
 
|}
  −
= Additional Links =
  −
[https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering Reverse Engineering of the Joy-Con by Github user dekuNukem]