Open greasysock opened 7 years ago
Can you give an example of your full command?
EDIT:
If you send
80 92 00 31 00 00 00 00 01 00 00 00 00 00 00 00 00 00 10 26 80 00 00 0f
and you haven't manually calibrated the motion sensor before,
then the response you get is correct and the x8026 data should be 0xFF.
Also the data you want to read should be x1a size. 2 bytes magic + 24bytes user sensor calibration.
Lastly, notice that the maximum size of data it can reply is 0x1D in BT. I never checked for USB, but from other users, it's probably x1B. You can test it by reading 0x0000 address and find out.
Thank you for the thoughtful response and insight.
I did not realize that I had not calibrated this device before. However, even trying to read the serial for the controller I am given the same response.
here is a better look at what I am sending and receiving for the serial number.
80 92 00 31 00 00 00 00 01 04 00 01 40 40 00 01 40 40 10 02 60 00 00 0e
80 92 00 31 00 00 00 00 01 05 00 01 40 40 00 01 40 40 10 02 60 00 00 0e
81 92 00 92 00 31 00 00 bc 77 21 6a 81 00 80 00 b6 67 7a 10 78 7f 00 90 10 02 60 00 00 0e ff ff ff ff ff ff ff ff ff ff ff ff ff ff
So now looking at this, it appears that I am sending the command twice in the function spi_read.
Below are the functions that are used to send subcommands to the device and to read from SPI, taken from the HID-Joy-Con-Whispering project.
void joycon_send_command(hid_device *handle, int command, uint8_t *data, int len)
{
unsigned char buf[0x400];
memset(buf, 0, 0x400);
if(!bluetooth)
{
buf[0x00] = 0x80;
buf[0x01] = 0x92;
buf[0x03] = 0x31;
}
buf[bluetooth ? 0x0 : 0x8] = command;
if(data != NULL && len != 0)
memcpy(buf + (bluetooth ? 0x1 : 0x9), data, len);
printf("command: ");
hex_dump_line(buf, 40);
printf("\n");
hid_exchange(handle, buf, len + (bluetooth ? 0x1 : 0x9));
if(data)
memcpy(data, buf, 0x40);
}
void joycon_send_subcommand(hid_device *handle, int command, int subcommand, uint8_t *data, int len)
{
unsigned char buf[0x400];
memset(buf, 0, 0x400);
uint8_t rumble_base[9] = {(++global_count) & 0xF, 0x00, 0x01, 0x40, 0x40, 0x00, 0x01, 0x40, 0x40};
memcpy(buf, rumble_base, 9);
buf[9] = subcommand;
if(data && len != 0)
memcpy(buf + 10, data, len);
joycon_send_command(handle, command, buf, 10 + len);
if(data)
memcpy(data, buf, 0x40); //TODO
}
void spi_read(hid_device *handle, uint32_t offs, uint8_t *data, uint8_t len)
{
unsigned char buf[0x400];
uint8_t *spi_read_cmd = (uint8_t*)calloc(1, 0x26 * sizeof(uint8_t));
uint32_t* offset = (uint32_t*)(&spi_read_cmd[0]);
uint8_t* length = (uint8_t*)(&spi_read_cmd[4]);
*length = len;
*offset = offs;
int max_read_count = 2000;
int read_count = 0;
do
{
//usleep(300000);
read_count += 1;
memcpy(buf, spi_read_cmd, 0x36);
joycon_send_subcommand(handle, 0x1, 0x10, buf, 0x26);
}
while(*(uint32_t*)&buf[0xF + (bluetooth ? 0 : 10)] != *offset && read_count < max_read_count);
if(read_count > max_read_count)
printf("ERROR: Read error or timeout\nSkipped reading of %dBytes at address 0x%05X...\n",
*length, *offset);
printf("SERIAL: \n");
hex_dump_line(buf, 0x40);
printf("\n");
memcpy(data, &buf[0x14 + (bluetooth ? 0 : 10)], len);
}
Pro controller maybe? Pro controllers do not have S/N and they are 0xFF. Additionally, your command and the reply structure are absolutely correct.
I would suggest to first dump the whole SPI of your device and then check if your individual spi read commands work and you got the correct data.
Also, read the documentation here to know what to expect and what not in each SPI address.
Lastly, if you want to experiment with USB commands other than x80, I can provide you the full list (not only what you can see here).
Yes, it is a pro controller. I would really appreciate seeing the full command list for USB.
Asking for the device model gave me the right response from SPI.
I am having the same problems as greasysock, whereby reading SPI data from USB gives the wrong values.
If a solution was found, could you post it?
@Davidobot What do you send and what do you get?
Doing ReadSPI(0x80, 0x12, 9);
to read from 0x8012 and get the user stick calibration data would hang the code for a while and then just output a completely zero array.
I use the same implementation of the spi read function as shown further up in this thread.
If the function doesn't hang, it just outputs an array of FFs the length of the requested read.
The hanging comes from the retries. That's because in USB mode the x30 input report mode is enabled by default. So the code expects a x21 but also gets x30 reports. This can be mitigated by rejecting the x31 report around 8 times and then retry to send the command again.
To do this, you need to change the joycon_send_subcommand() to identify the x10 subcmd and check for x21 inputreports in hid_read(). And better change the hid_read to hid_read_timeout with 100ms timeout.
About the xFF problem, as I said before, this section is empty (all 0xFF) if the controller was never manually calibrated. You said in the email that everything works as it should in BT mode, so I assume you have calibration data there. Then what happens is that you reach max_read_count.
So, if max_read_count is the problem, it will probably be fixed if you implement the x30 reports reject mechanism above.
Thanks for your help! Setting the input mode to 0x3F (before dumping the spi data) and then back to 0x30 solved the problem!
I'm trying to read from SPI via USB, but all I ever am returned is "FF" of the length of the request.
81 92 00 92 00 31 00 00 6d 55 21 60 81 00 80 00 aa 97 77 18 18 81 00 90 10 26 80 00 00 0f ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
Here is an example response.
Does anybody know what I should be doing differently? I'm using the subcommand 10 to read from spi