Przeglądaj źródła

implement 2wicc style reporting

Jariullah Safi 4 miesięcy temu
rodzic
commit
8451fd3aae
1 zmienionych plików z 29 dodań i 5 usunięć
  1. 29 5
      OpenPuck/mode_switch_pro.cpp

+ 29 - 5
OpenPuck/mode_switch_pro.cpp

@@ -81,11 +81,14 @@ static void jcInputPrefix(uint8_t* out){
   if(b&TB_L4)jc|=codeToJc(g_back[0],fA,fB,fX,fY); if(b&TB_R4)jc|=codeToJc(g_back[1],fA,fB,fX,fY);
   if(b&TB_L5)jc|=codeToJc(g_back[2],fA,fB,fX,fY); if(b&TB_R5)jc|=codeToJc(g_back[3],fA,fB,fX,fY);
   out[0]=g_jcTimer++;
-  out[1]=0x81;   // full battery + USB powered (hid-nintendo bat_con)
+  out[1]=0x91;   // battery full+charging (hi nibble 0x9), connection_info=1 (lo nibble): a wired/charging Pro Controller.
+                 // A real Switch reads this to show the pad as connected; Steam/hid-nintendo accept it too. (2wiCC parity)
   out[2]=(uint8_t)(jc); out[3]=(uint8_t)(jc>>8); out[4]=(uint8_t)(jc>>16);
+  out[3]|=0x80;  // charging_grip bit (button "common" byte, bit7): genuine Pro Controller always sets it on USB; real
+                 // Switch uses it to recognise a wired controller. Not a button, so hid-nintendo ignores it.
   jcPackStick(out+5, g_in.lx, g_in.ly);
   jcPackStick(out+8, g_in.rx, g_in.ry);
-  out[11]=0;
+  out[11]=0x09;  // rumble_input_report echo: genuine pad emits 0x09..0x0C; some Switch firmware expects this nonzero.
 }
 static void switchProBuild(uint8_t out[63]){
   memset(out,0,63);
@@ -121,6 +124,18 @@ static void jcBuildStickCal(){
   uint16_t Rr[6]={C,C, R,R, R,R};  // right order: center(x,y), min(x,y), max(x,y)
   jcPack12(&g_spiStickCal[0], L); jcPack12(&g_spiStickCal[9], Rr);
 }
+// Manual-pairing (subcommand 0x01) reply payloads. A real Switch runs this 3-stage BT key exchange over USB so it
+// can register the pad (Steam/hid-nintendo never do, which is why this was previously unneeded). The data is the
+// canonical hid handshake blob; the Switch only validates the shape, not the key contents. Each is the 31-byte
+// reply body that follows the 0x21 input prefix + ack(0x81) + echoed-subcommand(0x01). (adapted from 2wiCC)
+static const uint8_t BT_PAIR_1[31]={   // type 1: echo type + controller BT addr + "Pro Controller" name
+  0x01, JC_MAC[0],JC_MAC[1],JC_MAC[2],JC_MAC[3],JC_MAC[4],JC_MAC[5], 0x00,0x25,0x08,
+  0x50,0x72,0x6F,0x20,0x43,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x6C,0x65,0x72,   // "Pro Controller"
+  0x00,0x00,0x00,0x00,0x00,0x68};
+static const uint8_t BT_PAIR_2[31]={   // type 2: LTK exchange
+  0x02, 0xE5,0xC8,0xE4,0x92,0x05,0xFF,0xC9,0x8A,0x7D,0xEA,0x15,0xF6,0x19,0xBA,0x82,0x13,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+static const uint8_t BT_PAIR_3[31]={0x03};   // type 3: save pairing (all zero body)
 static void spiRead(uint32_t addr, uint8_t len, uint8_t* dst){
   for(uint8_t i=0;i<len;i++){
     uint32_t a=addr+i; uint8_t v=0xFF;
@@ -155,14 +170,20 @@ static void jcSubcmd(uint8_t sub, const uint8_t* args, uint16_t alen){
   jcInputPrefix(p);
   p[13]=sub;
   switch(sub){
+    case 0x01: {                       // manual BT pairing: 3-stage key exchange a real Switch runs over USB
+      const uint8_t* d=BT_PAIR_3; uint8_t t=(alen>=1)?args[0]:3;
+      if(t==1) d=BT_PAIR_1; else if(t==2) d=BT_PAIR_2;
+      p[12]=0x81;                      // pairing ACK
+      memcpy(&p[14], d, 31);
+      break; }
     case 0x02:                         // request device info
       p[12]=0x82;
-      p[14]=0x04; p[15]=0x21;          // firmware version (4.33)
+      p[14]=0x03; p[15]=0x48;          // firmware version 3.72 (genuine Pro Controller value)
       p[16]=0x03;                      // controller type: Pro Controller
       p[17]=0x02;                      // fixed
       memcpy(&p[18], JC_MAC, 6);
       p[24]=0x01;                      // colors stored in SPI (0x6050)
-      p[25]=0x02;                      // fixed
+      p[25]=0x01;                      // fixed
       break;
     case 0x10: {                       // SPI flash read -> echo [addr][len] then the data
       if(alen<5){ p[12]=0x80; break; }
@@ -175,7 +196,10 @@ static void jcSubcmd(uint8_t sub, const uint8_t* args, uint16_t alen){
     case 0x03:                         // set input report mode (0x30 = standard full) -> begin streaming
       if(alen>=1 && args[0]==0x30) g_swProReportMode=0x30;
       p[12]=0x80; break;
-    case 0x04: p[12]=0x83; break;      // trigger buttons elapsed time
+    case 0x04:                         // trigger buttons elapsed time -> canned reply (genuine pad returns data)
+      p[12]=0x83;
+      p[14]=0x00; p[15]=0xCC; p[16]=0x00; p[17]=0xEE; p[18]=0x00; p[19]=0xFF;
+      break;
     case 0x21: p[12]=0xA0; break;      // set NFC/IR config
     default:   p[12]=0x80; break;      // 0x06/0x08/0x30/0x38/0x40/0x41/0x48/... generic positive ACK
   }