Homebrew Infra Red Resource Thread

  • Thread starter Thread starter RedHat
  • Start date Start date
  • Views Views 63,846
  • Replies Replies 226
  • Likes Likes 10

Would you like to see development for IR homebrew (CPP or not) on the 3ds?

  • Yes, and I have the CPP!

    Votes: 41 19.2%
  • Yes, why not!

    Votes: 167 78.4%
  • No.

    Votes: 5 2.3%

  • Total voters
    213
Yea the range doesn't surprise me. Nintendo always use IR at really close range. On the gbc it was meant for use at 1-3 feet for the printer or transfer.
Bet to save battery they use weak ir on the 3ds.
Actually, with some tests (phone camera and IR hacks), it appears that the range on the 3DS is much farther than I originally thought. iirc I was able to see it a good 5+ feet away (though dimly).


I suppose it would also be a good time to release 3DS-Remote.
https://github.com/RedInquisitive/3DS-Remote

WAIT! Before you go thinking "Finally, a 3DS TV remote!" PLEASE be aware that the 3DS's protocol is not quite compatible with TV remotes (so the 3DS stops listening to the full IR signal, at least, in my case :().

Here is what the app does:
  • It attempts to record IR signals when the A button is pressed. Next, it will try to interpret and dump the memory to the bottom screen.
  • Then, when select is pressed (entering send mode) and then the A button is pressed, it will try (again, try) to send the IR data it got.
Unlike my previous app, this is coded a little bit better and doesn't crash the 3DS when you quit...

Try it out, if you wish (and tell me what you get)! (please take a look at my code, my preferred language is not C...)
 
Actually, with some tests (phone camera and IR hacks), it appears that the range on the 3DS is much farther than I originally thought. iirc I was able to see it a good 5+ feet away (though dimly).


I suppose it would also be a good time to release 3DS-Remote.
https://github.com/RedInquisitive/3DS-Remote

WAIT! Before you go thinking "Finally, a 3DS TV remote!" PLEASE be aware that the 3DS's protocol is not quite compatible with TV remotes (so the 3DS stops listening to the full IR signal, at least, in my case :().

Here is what the app does:
  • It attempts to record IR signals when the A button is pressed. Next, it will try to interpret and dump the memory to the bottom screen.
  • Then, when select is pressed (entering send mode) and then the A button is pressed, it will try (again, try) to send the IR data it got.
Unlike my previous app, this is coded a little bit better and doesn't crash the 3DS when you quit...

Try it out, if you wish (and tell me what you get)! (please take a look at my code, my preferred language is not C...)
cool, i want to try to compile as a Applet as i originally planed. Maybe easier said then done but ill try.
 
Wow, that a cool progress! I really sad now that I lost both of my pokewalkers...
Meanwhile, I made some access test, and ??? System transfer may have cpp access!
Bw-black and white screens
Gs-glitches screen, ccp access hopefully
Ad-access denied
Nl-not launching. Upper screen white and gray strips, touch screen yellow on 2.5 hax (I think it was black on 2.1 hax)

Ssb demo -gs
???(system transfer)-gs
Nintendo zone-ad
Rayman origins demo-bw
Rusty's real deal baseball-ad
Ironfall 1.1-ad
Youtube old version-ad
Face raiders-ad
Sonic boom demo-nl
Strachmo-ad
Flip note studio 3d-ad
Pokemon bank-ad
Mh4u demo -gs
Oras special demo-ad
Resident evil revolution demo -gs
Kersploosh!-nl
Steel diver sub wars-ad
Health and safety-ad
Mii plaza-ad
Sytem settings-ad
Camera-ad
Nnid setings-ad
Download play-ad
Music-ad
Eshop- ad
Mii maker-ad
Activity log-ad
Ar games-ad
Kingdom hearts 3d (demo) DDD-ad
Photos with Mario-ad
Swapnote-ad
 
Any progress on making this more accessible @RedHat
Not yet, but with what I am learning from all of the homebrew development recently (thanks @mashers and more!), there is a good chance that I might be able to create a fun app in the future! I would need to get service control down first, however. We'll see soon™.
 
  • Like
Reactions: SomeGamer
Not yet, but with what I am learning from all of the homebrew development recently (thanks @mashers and more!), there is a good chance that I might be able to create a fun app in the future! I would need to get service control down first, however. We'll see soon™.
So hopefully sometime in the next month. Right? Lmao
 
Haha maybe! IR is a really finicky thing and the protocol is all wonky and stuff. Right now I am helping @mashers with gridlauncher but I think that doing so will end up helping with the project as a whole.
I know. I'm an avid follower of the mashers launcher.

That's first priority. Can focus on making a control all, turn all the TVs off everywhere device of doom later.
 
Can focus on making a control all, turn all the TVs off everywhere device of doom later.
Actually, I tried working with TVs but the 3DS really does not like working with the TV IR protocol AT ALL. I really do want CPP support however, that would be really good for a lot of homebrews.
 
Actually, I tried working with TVs but the 3DS really does not like working with the TV IR protocol AT ALL. I really do want CPP support however, that would be really good for a lot of homebrews.
Well... That sucks...

*deletes the custom remote control of doom theme that was made for mashers grid launcher*

I wanted to cause havoc and destruction and feed the need to cause DOOM...
-------------------------------
I wonder if there was a way I could make my own IR dongle to fit on my 3DS and make an "audio" recording of the IR signal.

How about something like that? I know something of that nature is possible. Just making a homebrew for it though... That's the thing.
 
I wonder if there was a way I could make my own IR dongle to fit on my 3DS and make an "audio" recording of the IR signal.

How about something like that? I know something of that nature is possible. Just making a homebrew for it though... That's the thing.
Yup, that shouldn't be too hard! Just use CSND to play sound just like gridlauncher. All you would have to do is "record" IR signals using audacity (there is a tutorial out there) and play them back using CSND on the 3DS using a 3.5mm to IR adapter. That should (should) be possible I think with some crafty designs!... but at that point you might as well use one of those TV be gone things or an android phone with IR support. Someone else other than me would have to look into something of that scale, however.
 
I'd be quite interested in making a mock-up 2 player IR mode (Like with Mortal Kombat on the SNES) or link cable support (Pokemon or even using the IR to interact with a real Gameboy Color's IR) and of course CPP. How possible do you think it would be to make these sorts of features?
 
I'd be quite interested in making a mock-up 2 player IR mode (Like with Mortal Kombat on the SNES) or link cable support (Pokemon or even using the IR to interact with a real Gameboy Color's IR) and of course CPP. How possible do you think it would be to make these sorts of features?
3ds to 3ds - Easy, just send and receive IR buffers. You would need to implement checks and hashes to confirm a message sent correctly. Might be easier to use peer to peer wifi, but IDK if ctrulib supports that kind of thing. Those types of games might be better off using the same wifi network to play.
3ds to Gameboy - Very advanced, you might run into problems like I have with IR remotes (the 3DS just kind of... stops listening). Probably not possible.
3ds to CPP - Anywhere from Easy to advanced. You would have to code services yourself and see what works. There is very little documentation in this area currently.
 
This is probably too advanced, and chances are slim that you own one, but what a about Fit Meter support? (BTW, trying to connect one results in the 3DS being sent from recording mode to sending mode in the app automatically! )
 
maybe a skylander cheater i don't play sylanders on 3ds buti have the 3ds portal and the figures are cross compatible. Also could you do some thing with the pokewalker with this
 
Last edited by hacksn5s4,
maybe a skylander cheater i don't play sylanders on 3ds buti have the 3ds portal and the figures are cross compatible. Also could you do some thing with the pokewalker with this
Yeah, but you need to record all communication and decrypt Pokemon data (if any).
I sadly lost both of my pokewalkers...
 
Hi, I hope it's not too late to revive this thread. I have been working on porting circle pad pro support to ctrulib for the past few days, basically decompiling the extra pad examples from CTR-SDK, and using dumps and the NTR debugger to check the runtime values of some variables, and I came up with a demo homebrew (cia) which tries to connect to the CPP using obviously the service ir:USER.

Here is the code (yes, I modified an example of ctrulib):
Code:
#include <3ds.h>
#include <stdio.h>

#define NN_ATTRIBUTE_ALIGN(n) __attribute__ ((aligned(n)))

u8 extraPadWorkingMemory[4096] NN_ATTRIBUTE_ALIGN(4096);
int irWorkingMemory = 0;
char peripheralId = 0x01;

Handle iruserHandle;
Handle iruserSharedMemHandle;
Handle connectionStatusEvent;

bool connected = false;
Result initializeIrnopSharedResult;
Result getConnectionStatusEventResult;
Result requireConnectionResult;

Result InitializeIrnopShared()
{
    Result ret = 0;
    u32 *cmdbuf = getThreadCommandBuffer();

    cmdbuf[0] = 0x00180182;
    cmdbuf[1] = 4096u;
    cmdbuf[2] = 3280u;
    cmdbuf[3] = (unsigned int)(0x00000500u >> 3);
    cmdbuf[4] = (unsigned int)(512 + 256);
    cmdbuf[5] = (unsigned int)(256u >> 3);
    cmdbuf[6] = (char)0x04; //byte 0x04
    cmdbuf[7] = 0;
    cmdbuf[8] = iruserSharedMemHandle; // mem handle

    if (R_FAILED(ret = svcSendSyncRequest(iruserHandle))) return ret;
    ret = (Result)cmdbuf[1];

    return ret;
}

Result GetConnectionStatusEvent(Handle *event_)
{
    Result ret = 0;
    u32 *cmdbuf = getThreadCommandBuffer();

    cmdbuf[0] = 0x000C0000;

    if (R_FAILED(ret = svcSendSyncRequest(iruserHandle))) return ret;
    ret = (Result)cmdbuf[1];

    *event_ = cmdbuf[3];

    return ret;
}

Result RequireConnection()
{
    Result ret = 0;
    u32 *cmdbuf = getThreadCommandBuffer();

    cmdbuf[0] = 0x00060040;
    cmdbuf[1] = peripheralId;

    if (R_FAILED(ret = svcSendSyncRequest(iruserHandle))) return ret;
    ret = (Result)cmdbuf[1];

    return ret;
}

Result Disconnect()
{
    Result ret = 0;
    u32 *cmdbuf = getThreadCommandBuffer();

    cmdbuf[0] = 0x00090000;

    if (R_FAILED(ret = svcSendSyncRequest(iruserHandle))) return ret;
    ret = (Result)cmdbuf[1];

    return ret;
}

int out, out_;
int StartSampling(int samplingThreadPriority, int period) // Button A
{
    int result = -1;
    // cepdSetPeriod(...);

    // Get IR:USER Handle
    Result ret = 0;
    ret = srvGetServiceHandle(&iruserHandle, "ir:USER");
    if (R_FAILED(ret)) iruserHandle = 0xFFFFFFFF;

    ret = svcCreateMemoryBlock(&iruserSharedMemHandle, irWorkingMemory, 0x1000, 1u, 3u);
    if (R_FAILED(ret)) iruserSharedMemHandle = 0xFFFFFFFF;

    initializeIrnopSharedResult = InitializeIrnopShared();

    svcCreateEvent(&connectionStatusEvent, 0);
    getConnectionStatusEventResult = GetConnectionStatusEvent(&connectionStatusEvent);

    svcWaitSynchronizationN(&out_, &connectionStatusEvent, 1, 0, 0);
    requireConnectionResult = RequireConnection();
    svcWaitSynchronizationN(&out_, &connectionStatusEvent, 1, 0, 4000000);

    /*while (true)
    {
        svcWaitSynchronizationN(&out_, &connectionStatusEvent, 1, 0, 0);
        requireConnectionResult = RequireConnection();
        int i = svcWaitSynchronizationN(&out_, &connectionStatusEvent, 1, 0, 4000000);
        s16 s = i;
        int i_ = s & 0x3FF;
        if (i_ != 1022) break;
        u8 connectionStatus = *((u8 *)(irWorkingMemory + 8));
        if (connectionStatus == 2) break;
        Disconnect();
        svcSleepThread(10416);
    }*/

    u8 connectionStatus = *((u8 *)(irWorkingMemory + 8));

    if (connectionStatus == 2) connected = true;

    out = connectionStatus;

    return result;
}

void TryToConnect() // Button B
{
    svcWaitSynchronizationN(&out_, &connectionStatusEvent, 1, 0, 0);
    RequireConnection();
    svcWaitSynchronizationN(&out_, &connectionStatusEvent, 1, 0, 4000000);

    u8 connectionStatus = *((u8 *)(irWorkingMemory + 8));

    if (connectionStatus == 2) connected = true;

    out = connectionStatus;

    Disconnect();
}

int main(int argc, char **argv)
{
    //Matrix containing the name of each key. Useful for printing when a key is pressed
    char keysNames[32][32] = {
        "KEY_A", "KEY_B", "KEY_SELECT", "KEY_START",
        "KEY_DRIGHT", "KEY_DLEFT", "KEY_DUP", "KEY_DDOWN",
        "KEY_R", "KEY_L", "KEY_X", "KEY_Y",
        "", "", "KEY_ZL", "KEY_ZR",
        "", "", "", "",
        "KEY_TOUCH", "", "", "",
        "KEY_CSTICK_RIGHT", "KEY_CSTICK_LEFT", "KEY_CSTICK_UP", "KEY_CSTICK_DOWN",
        "KEY_CPAD_RIGHT", "KEY_CPAD_LEFT", "KEY_CPAD_UP", "KEY_CPAD_DOWN"
    };

    // Initialize services
    gfxInitDefault();

    //Initialize console on top screen. Using NULL as the second argument tells the console library to use the internal console structure as current one
    consoleInit(GFX_TOP, NULL);

    u32 kDownOld = 0, kHeldOld = 0, kUpOld = 0; //In these variables there will be information about keys detected in the previous frame

    printf("\x1b[0;0HPress Start to exit.");
    printf("\x1b[1;0HCirclePad position:");
    printf("\x1b[20;0Hir:USER service handle: %x", iruserHandle);
    printf("\x1b[21;0HShared memory handle: %x", iruserSharedMemHandle);
    printf("\x1b[22;0HIIS result: %x", initializeIrnopSharedResult);
    printf("\x1b[23;0HGCSE result: %x", getConnectionStatusEventResult);
    printf("\x1b[24;0HConnectionStatus event handle: %x", connectionStatusEvent);
    printf("\x1b[25;0HRC result: %x", requireConnectionResult);
    if (connected)
        printf("\x1b[27;0HCONNECTED!!! %x", out);
    else
        printf("\x1b[27;0HNot connected. %x", out);

    // ---------------------------------------------------------------------------------------------------------------------------------------------------------------
    // ---------------------------------------------------------------------------------------------------------------------------------------------------------------

    irWorkingMemory = (int)extraPadWorkingMemory;
    out = *((u8 *)(irWorkingMemory + 8));

    // ---------------------------------------------------------------------------------------------------------------------------------------------------------------
    // ---------------------------------------------------------------------------------------------------------------------------------------------------------------

    // Main loop
    while (aptMainLoop())
    {
        //Scan all the inputs. This should be done once for each frame
        hidScanInput();

        //hidKeysDown returns information about which buttons have been just pressed (and they weren't in the previous frame)
        u32 kDown = hidKeysDown();
        //hidKeysHeld returns information about which buttons have are held down in this frame
        u32 kHeld = hidKeysHeld();
        //hidKeysUp returns information about which buttons have been just released
        u32 kUp = hidKeysUp();

        if (kDown & KEY_START) break; // break in order to return to hbmenu

        //Do the keys printing only if keys have changed
        if (kDown != kDownOld || kHeld != kHeldOld || kUp != kUpOld)
        {
            //Clear console
            consoleClear();

            //These two lines must be rewritten because we cleared the whole console
            printf("\x1b[0;0HPress Start to exit.");
            printf("\x1b[1;0HCirclePad position:");
            printf("\x1b[20;0Hir:USER service handle: %x", iruserHandle);
            printf("\x1b[21;0HShared memory handle: %x", iruserSharedMemHandle);
            printf("\x1b[22;0HIIS result: %x", initializeIrnopSharedResult);
            printf("\x1b[23;0HGCSE result: %x", getConnectionStatusEventResult);
            printf("\x1b[24;0HConnectionStatus event handle: %x", connectionStatusEvent);
            printf("\x1b[25;0HRC result: %x", requireConnectionResult);
            if (connected)
                printf("\x1b[27;0HCONNECTED!!! %x", out);
            else
                printf("\x1b[27;0HNot connected. %x", out);

            printf("\x1b[3;0H"); //Move the cursor to the fourth row because on the third one we'll write the circle pad position

            //Check if some of the keys are down, held or up
            int i;
            for (i = 0; i < 32; i++)
            {
                if (kDown & BIT(i)) printf("%s down\n", keysNames[i]);
                if (kHeld & BIT(i)) printf("%s held\n", keysNames[i]);
                if (kUp & BIT(i)) printf("%s up\n", keysNames[i]);
            }

            if (kDown & KEY_A)
            {
                StartSampling(0, 8);
            }
            if (kDown & KEY_B)
            {
                TryToConnect();
            }
        }

        //Set keys old values for the next frame
        kDownOld = kDown;
        kHeldOld = kHeld;
        kUpOld = kUp;

        circlePosition pos;

        //Read the CirclePad position
        hidCircleRead(&pos);

        //Print the CirclePad position
        printf("\x1b[2;0H%04d; %04d", pos.dx, pos.dy);

        // Flush and swap framebuffers
        gfxFlushBuffers();
        gfxSwapBuffers();

        //Wait for VBlank
        gspWaitForVBlank();
    }

    // Exit services
    gfxExit();
    return 0;
}

(And for you lazy, check the attachments)

BUT, it does not work. I mean it does initialize correctly and everything, it even turns on the ir of the 3ds on RequireConnection(), but it won't actually connect with the thing.

I suppose the problem is somewhere in the RequireConnection() function, specifically the peripheralId byte, which should be passed as a char, has most of my concern. I say this because I tried manually changing the value in the CTR-SDK example mentioned before with NTR debugger and it will fail to connect, apparently only 0x01 works, but not on my code.

Anyway, I thought about posting here because maybe some of you have succeded in this hard work, or maybe could help me out with this little project.

Oh and by the way, it *should* connect without pressing B, just by calling StartSampling, hence button A, and the commented out part in the StartSampling() function in what the CTR-SDK sample does to connect (more or less), but the while will just never end, because svcWaitSynchronizationN doesn't return before the maximum time has passed.
 

Attachments

Site & Scene News

Popular threads in this forum