Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pairing gamepad with no display #19

Open
nelgin opened this issue Mar 21, 2023 · 6 comments
Open

Pairing gamepad with no display #19

nelgin opened this issue Mar 21, 2023 · 6 comments

Comments

@nelgin
Copy link

nelgin commented Mar 21, 2023

It was a challenge trying to pair the gamepad when you get no screen output. You cannot see which numbers to type. It seems the pin is generated from the MAC address so as long as you don't change your wifi module in the console, it should stay the same so make a note when you have a working Wii U.

The following snippet of code added in the option_pairDRC function will turn off the led, and then wait 3 seconds Then for each of the 4 numbers in the pincode, the red led will flash for 1/2 second with a 3 second pause between each number If you get a 6 second gap between numbers, then you know that number is a 0.

Example

BLANK....FLASH FLASH / PAUSE / FLASH / PAUSE / PAUSE / FLASH FLASH FLASH 

Would be read as 2, 1, 0, 3.

0 = spade
1 = heart
2 = diamond
3 = club

So on your gamepad you'd press diamond, heart, spade, club.

Insert the following code after the "static const char symbol_names" code block.

    setNotificationLED(NOTIF_LED_OFF);

    for (int i = 0; i < 4; i++) {
        usleep(3*1000*1000);
        for (int j = 1; j < pincode[i]+1; j++ ) {
            setNotificationLED(NOTIF_LED_RED);
            usleep(1000*500);
            setNotificationLED(NOTIF_LED_OFF);
            usleep(1000*500);
        }
    }
    setNotificationLED(NOTIF_LED_BLUE|NOTIF_LED_RED);
@vgmoose
Copy link

vgmoose commented Mar 29, 2023

Another potentially useful way to pair a gamepad with no display would be to write the pin to the SD card, so it can be checked on a computer (maybe alongside other hw information?)

@nelgin
Copy link
Author

nelgin commented Mar 29, 2023

That's actually what I did first. If you want to use that method, you can add this section in the same place:

    int pairHandle;
    int pairres = FSA_OpenFile(fsaHandle, "/vol/storage_recovsd/pairing.txt", "w", &pairHandle);
    if (pairres < 0) {
        FSA_CloseFile(fsaHandle, pairHandle);
    }
    void* dataBuffer = IOS_HeapAllocAligned(CROSS_PROCESS_HEAP_ID, 0x100, 0x40);
    snprintf(dataBuffer, 0x40, "%d %d %d %d\n", pincode[0], pincode[1], pincode[2], pincode[3]);
    pairres = FSA_WriteFile(fsaHandle, dataBuffer, 1, strnlen(dataBuffer, 0x40), pairHandle, 0);
    FSA_CloseFile(fsaHandle, pairHandle);

This will write a numbers to the sdcard in a file called pairing. The numbers shouldn't ever chance for that WiiU as long as you don't change the network module. You could modify it to write out the words instead. I actually now have both included. It's obviously going to be in a file pairing.txt

As for adding other information, I tried to dump the manufacturer of the emmc chip to a file but I only got NULL characters so not sure what's going on there. I may need Gary's assistance to figure that out.

@filipe-maia
Copy link

filipe-maia commented May 21, 2023

Hi.
I'm facing the same problem.
I have a Wii U that doesn't show any image and I don't have any gamepad connected.
I can brute force the code on the gamepad, but it would take a long time.
I know the Wii U works, because I was able to blindly use udpih and recovery_menu to dump OTP+SEEPROM.
A new option that could log into a file on the SD card the code to connect a gamepad to the console would be great.
The sugestion from @Sierraffinity in issue 13 is also great.
Please implement one or the other or both.
Thanks.

EDIT: Using recovery_menu_dc_init did not solve my problem, because I believe the problem of this Wii U is in the HDMI port.

@filipe-maia
Copy link

filipe-maia commented May 23, 2023

Hi.

Thank you @nelgin .

I've added your code, the end result is:

(...)
#include "utils.h"
#include "fsa.h"
#include <string.h>
(...)
void option_PairDRC(void)
{
    gfx_clear(COLOR_BACKGROUND);
    drawTopBar("Pairing Gamepad...");

    uint32_t index = 16 + 8 + 2 + 8;

    int res = CCRCDCSetup();
    if (res < 0) {
        gfx_set_font_color(COLOR_ERROR);
        gfx_printf(16, index, 0, "CCRCDCSetup() failed: %x", res);

        waitButtonInput();
        return;
    }

    gfx_print(16, index, 0, "Get pincode...");
    index += CHAR_SIZE_DRC_Y + 4;

    uint8_t pincode[4];
    res = CCRSysGetPincode(pincode);
    if (res < 0) {
        gfx_set_font_color(COLOR_ERROR);
        gfx_printf(16, index, 0, "Failed to get pincode: %x", res);

        waitButtonInput();
        return;
    }

    static const char symbol_names[][8] = {
        "spade",
        "heart",
        "diamond",
        "clubs",
    };

    int pairHandle;
    int pairres = FSA_OpenFile(fsaHandle, "/vol/storage_recovsd/pairing.txt", "w", &pairHandle);
    if (pairres < 0) {
        FSA_CloseFile(fsaHandle, pairHandle);
    }
    void* dataBuffer = IOS_HeapAllocAligned(CROSS_PROCESS_HEAP_ID, 0x100, 0x40);
    snprintf(dataBuffer, 0x40, "%d %d %d %d\n", pincode[0], pincode[1], pincode[2], pincode[3]);
    pairres = FSA_WriteFile(fsaHandle, dataBuffer, 1, strnlen(dataBuffer, 0x40), pairHandle, 0);
    FSA_CloseFile(fsaHandle, pairHandle);
    SMC_SetNotificationLED(NOTIF_LED_OFF);
    for (int i = 0; i < 4; i++) {
        usleep(3*1000*1000);
        for (int j = 1; j < pincode[i]+1; j++ ) {
            SMC_SetNotificationLED(NOTIF_LED_RED);
            usleep(1000*500);
            SMC_SetNotificationLED(NOTIF_LED_OFF);
            usleep(1000*500);
        }
    }
    SMC_SetNotificationLED(NOTIF_LED_BLUE|NOTIF_LED_RED);

    gfx_set_font_color(COLOR_SUCCESS);
    gfx_printf(16, index, 0, "Pincode: %x%x%x%x (%s %s %s %s)",
        pincode[0], pincode[1], pincode[2], pincode[3],
        symbol_names[pincode[0]], symbol_names[pincode[1]], symbol_names[pincode[2]], symbol_names[pincode[3]]);
    gfx_set_font_color(COLOR_PRIMARY);
    index += CHAR_SIZE_DRC_Y + 4;

    // DRC pairing timeout
    int timeout = DRC_PAIRING_TIMEOUT;

    // display a "this gamepad has already been paired" message, if a gamepad is alrady connected
    res = CCRCDCDevicePing(CCR_DEST_DRC0);
    if (res == 0) {
        gfx_print(16, index, 0, "Gamepad already connected, displaying message...");
        index += CHAR_SIZE_DRC_Y + 4;

        uint16_t args[2] = { 0, timeout + 5 };
        CCRCDCSysDrcDisplayMessage(CCR_DEST_DRC0, args);
    }

    usleep(1000 * 100);

    uint8_t mute = 0xff;
    CCRCDCPerSetLcdMute(CCR_DEST_DRC0, &mute);

    gfx_print(16, index, 0, "Starting pairing...");
    index += CHAR_SIZE_DRC_Y + 4;

    res = CCRSysStartPairing(CCR_DEST_DRC0, timeout, pincode);
    if (res < 0) {
        gfx_set_font_color(COLOR_ERROR);
        gfx_printf(16, index, 0, "Failed to start pairing: %x", res);

        waitButtonInput();
        return;
    }

    uint32_t status;
    while (timeout--) {
        res = CCRCDCWpsStatus(&status);
        if (res < 0) {
            gfx_set_font_color(COLOR_ERROR);
            gfx_printf(16, index, GfxPrintFlag_ClearBG, "Failed to get status: %x", res);

            CCRCDCWpsStop();

            waitButtonInput();
            return;
        }

        if (status == 0) {
            // paired
            break;
        } else if (status == 2) {
            // pairing
        } else if (status == 1) {
            // searching
        } else {
            // error
            break;
        }

        gfx_printf(16, index, GfxPrintFlag_ClearBG, "Waiting for Gamepad... (%lx) (Timeout: %d) ", status, timeout);
        usleep(1000 * 1000);
    }

    if (status != 0 || timeout <= 0) {
        gfx_set_font_color(COLOR_ERROR);
        gfx_printf(16, index, GfxPrintFlag_ClearBG, "Failed to pair GamePad: %lx", status);

        CCRCDCWpsStop();
    } else {
        gfx_set_font_color(COLOR_SUCCESS);
        gfx_print(16, index, GfxPrintFlag_ClearBG, "Paired GamePad");
    }

    waitButtonInput();
}

I've attached the built files (they also contain the changes of issue 18).
recovery_menu.zip

@filipe-maia
Copy link

filipe-maia commented May 29, 2023

Hi.
Just adding here this idea that "W00fer" said on discord:
The LED blinking could be accompanied with the Wii U beeping, to understand the code easier.
I think it's a good idea, if it is possible.

EDIT: The Wii U beeps when turning ON, doesn't it? Now I can't remember :S

@Leerz
Copy link

Leerz commented Jun 26, 2024

Hi.

Thank you @nelgin .

I've added your code, the end result is:

(...)
#include "utils.h"
#include "fsa.h"
#include <string.h>
(...)
void option_PairDRC(void)
{
    gfx_clear(COLOR_BACKGROUND);
    drawTopBar("Pairing Gamepad...");

    uint32_t index = 16 + 8 + 2 + 8;

    int res = CCRCDCSetup();
    if (res < 0) {
        gfx_set_font_color(COLOR_ERROR);
        gfx_printf(16, index, 0, "CCRCDCSetup() failed: %x", res);

        waitButtonInput();
        return;
    }

    gfx_print(16, index, 0, "Get pincode...");
    index += CHAR_SIZE_DRC_Y + 4;

    uint8_t pincode[4];
    res = CCRSysGetPincode(pincode);
    if (res < 0) {
        gfx_set_font_color(COLOR_ERROR);
        gfx_printf(16, index, 0, "Failed to get pincode: %x", res);

        waitButtonInput();
        return;
    }

    static const char symbol_names[][8] = {
        "spade",
        "heart",
        "diamond",
        "clubs",
    };

    int pairHandle;
    int pairres = FSA_OpenFile(fsaHandle, "/vol/storage_recovsd/pairing.txt", "w", &pairHandle);
    if (pairres < 0) {
        FSA_CloseFile(fsaHandle, pairHandle);
    }
    void* dataBuffer = IOS_HeapAllocAligned(CROSS_PROCESS_HEAP_ID, 0x100, 0x40);
    snprintf(dataBuffer, 0x40, "%d %d %d %d\n", pincode[0], pincode[1], pincode[2], pincode[3]);
    pairres = FSA_WriteFile(fsaHandle, dataBuffer, 1, strnlen(dataBuffer, 0x40), pairHandle, 0);
    FSA_CloseFile(fsaHandle, pairHandle);
    SMC_SetNotificationLED(NOTIF_LED_OFF);
    for (int i = 0; i < 4; i++) {
        usleep(3*1000*1000);
        for (int j = 1; j < pincode[i]+1; j++ ) {
            SMC_SetNotificationLED(NOTIF_LED_RED);
            usleep(1000*500);
            SMC_SetNotificationLED(NOTIF_LED_OFF);
            usleep(1000*500);
        }
    }
    SMC_SetNotificationLED(NOTIF_LED_BLUE|NOTIF_LED_RED);

    gfx_set_font_color(COLOR_SUCCESS);
    gfx_printf(16, index, 0, "Pincode: %x%x%x%x (%s %s %s %s)",
        pincode[0], pincode[1], pincode[2], pincode[3],
        symbol_names[pincode[0]], symbol_names[pincode[1]], symbol_names[pincode[2]], symbol_names[pincode[3]]);
    gfx_set_font_color(COLOR_PRIMARY);
    index += CHAR_SIZE_DRC_Y + 4;

    // DRC pairing timeout
    int timeout = DRC_PAIRING_TIMEOUT;

    // display a "this gamepad has already been paired" message, if a gamepad is alrady connected
    res = CCRCDCDevicePing(CCR_DEST_DRC0);
    if (res == 0) {
        gfx_print(16, index, 0, "Gamepad already connected, displaying message...");
        index += CHAR_SIZE_DRC_Y + 4;

        uint16_t args[2] = { 0, timeout + 5 };
        CCRCDCSysDrcDisplayMessage(CCR_DEST_DRC0, args);
    }

    usleep(1000 * 100);

    uint8_t mute = 0xff;
    CCRCDCPerSetLcdMute(CCR_DEST_DRC0, &mute);

    gfx_print(16, index, 0, "Starting pairing...");
    index += CHAR_SIZE_DRC_Y + 4;

    res = CCRSysStartPairing(CCR_DEST_DRC0, timeout, pincode);
    if (res < 0) {
        gfx_set_font_color(COLOR_ERROR);
        gfx_printf(16, index, 0, "Failed to start pairing: %x", res);

        waitButtonInput();
        return;
    }

    uint32_t status;
    while (timeout--) {
        res = CCRCDCWpsStatus(&status);
        if (res < 0) {
            gfx_set_font_color(COLOR_ERROR);
            gfx_printf(16, index, GfxPrintFlag_ClearBG, "Failed to get status: %x", res);

            CCRCDCWpsStop();

            waitButtonInput();
            return;
        }

        if (status == 0) {
            // paired
            break;
        } else if (status == 2) {
            // pairing
        } else if (status == 1) {
            // searching
        } else {
            // error
            break;
        }

        gfx_printf(16, index, GfxPrintFlag_ClearBG, "Waiting for Gamepad... (%lx) (Timeout: %d) ", status, timeout);
        usleep(1000 * 1000);
    }

    if (status != 0 || timeout <= 0) {
        gfx_set_font_color(COLOR_ERROR);
        gfx_printf(16, index, GfxPrintFlag_ClearBG, "Failed to pair GamePad: %lx", status);

        CCRCDCWpsStop();
    } else {
        gfx_set_font_color(COLOR_SUCCESS);
        gfx_print(16, index, GfxPrintFlag_ClearBG, "Paired GamePad");
    }

    waitButtonInput();
}

I've attached the built files (they also contain the changes of issue 18). recovery_menu.zip

20240626
If anyone faces this issue before where the wiiu doesn't work on hdmi and is not set on the av-multi or with a broken hdmi circuit (filters/encoder)

get the recovery files attached above
then once the led turns purple
press Eject 5 times (this puts the cursor to the gamepad sync row)
then power to accept - observe the light then key in to your gamepad

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants