-
Notifications
You must be signed in to change notification settings - Fork 19
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
Add an ir:USER service wrapper and Circle Pad Pro example #86
Conversation
I honestly thought circle pad pro was automatically recognised by the system (I don’t have one, since I own a New 3DS XL with a built-in C-Stick) |
I thought the same thing, and initially started working on wrapping the They leave the hard work of getting the CPP input to the user 🙃 |
Works in the Citra emulator, but not on device.
Need to parse packets now to make sure input signal is getting transferred correctly.
6d6875b
to
da348b2
Compare
I guess that makes sense. They noticed the difficulty to try to find a CPP and decided to make |
Yeah I don't blame them, especially since it seems like no one knew how to get a connection working anyway. The Circle Pad Pro is pretty niche, but I really want that second joystick for my PC controller emulation 😈. |
Really neat! With the idea of how IR is receiving packets back and forth, is it worth possibly creating almost like an "IRServer" or "IRThread", etc that internally manages waiting for packets? This way svc doesn't have to be exposed to the user similar to the My thought is it would be more user safe if a mpsc receiver channel was returned from the initialization and you could use The connect function could be moved to the I would write up an example but I'm currently on mobile. |
ctru-rs is supposed to be a thin or minimal wrapper around libctru which makes it nicer and safer to use than raw C calls. With that in mind, we don't want to introduce more overhead or complexity than necessary, so the user application (or another library) should be where that IR thread and other connection logic goes. Especially when it involves handling user input. We don't want to force developers to handle initialization of the service/CPP in a specific way like the demo (i.e. taking in I think it's fine to expose some svc calls, especially when it's almost harmless like the one used here. |
In that case, if some of the SVC functions are added then the I guess the main concern would be the safety implications of the exposed functions. Ex. An invalid, null, or non-event handle being passed |
# Conflicts: # ctru-rs/src/services/mod.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the New 3DS internally emulates the Circle Pad Pro, so using ir:USER on a New 3D system should give you the c-stick inputs. The ir:rst service is slightly different, where it only works on the New 3DS (doesn't give CPP inputs). Most retail 3DS games use ir:USER to be compatible with both old and new 3DS systems.
My N3DS XL won't recognize the c-stick as a CPP, it seems. It tries to check the infrared instead (I used my iPhone X's FaceID to shoot infrared in the ir sensor and it returns an error! 😆).
I can't really review the example/module if I can't run it 🤔
Found this on the libctru docs. The example is initializing |
Ok, great, we just have to make a runtime check for New3DS and state the example won’t work without the actual CPP. |
Something to note: There are a handful of devices that utilize |
Nope, didn't work. Still doesn't work. |
Friendly reminder that You may have to close Hid or do something else before being able to use the service properly. |
I had totally forgotten about that! |
Here, found it. You need to re-implement this weak function https://github.com/devkitPro/libctru/blob/d0936b879bd2088cae61b69707fe70cb66ede651/libctru/source/services/hid.c#L35. If you set the return to false any use of |
That still doesn't fix the issue. At this point I'm convinced there's a bug of some kind. |
I obtained the following log from Panda3DS, running Majora's Mask 3D, logging only
So initializing HID before ir:USER seems to be fine, but it does indeed seem that libctru initializing |
Don't suppose you can determine the parameters MM uses for initialising the CPP? Timings etc. |
I have a half-decompilation of the Majora's Mask IR code on my computer, though it's rather complicated. "Timing" is done via the IR events (eg once the game calls IR::RequireConnection to pair with the CPP, it uses WaitSync1 on the IR connection event. This way it sleeps until the connection attempts has ended and IR shared memory is properly initialized. After that, I think it uses the send/recv events for synchronizing package transfers) |
@AzureMarker Any chance of trying something like this out? |
I'm pretty sure that's how it already works. I based my implementation on Majora's Mask (even got into quite a few gdb sessions). |
Welp. Is there anything else I can do? Info to capture? |
Is there any way to know if the ir:rst service is in use? Maybe something else is initializing it. Or maybe calling the close function could help kill whatever active session there might be? I don't have a New 3DS to test with. |
The handy variable that says whether |
@ian-h-chamberlain @Meziu I think all the comments have been addressed, so let me know if we can merge the PR or if you have more comments. Thanks for taking a look! It's almost been a year since I opened the PR 😅. |
Well, it would be nice to get the example code working on New 3DS first... |
I don't have a New 3DS to test with, and it works in Citra. We can merge this and work on improving New 3DS support as a follow-up. The PR has been open for a very long time and is close to merging. |
LGTM! As you said, N3DS issues could probably be fixed in a follow up just to get this merged since it has been so long. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice PR, this is very much ready for merging!
I've also done a bit of testing with ir:rst
and ir:USER
on the side, and I can say a couple of things to help the discussion.
First of all, the ir:rst
service is NOT initialized when implementing the libctru
weak function as such:
#[no_mangle]
unsafe extern "C" fn hidShouldUseIrrst() -> bool {
false
}
I could test various uses of the irrst
service and they actually stopped working after using this implementation.
Secondly... to me this function seems to make it work! Not for long though. I can clearly see the C-Stick readings to be correct for some fraction of a second (not much more than 6 packets in a row), right before dying out and never reading anything again. This behavior (which is quite consistent, it seems) clearly means that there is something else missing for the implementation to work correctly, though I'm pretty much unable to read any further into it.
This PR can be merged, but you should open an issue since more research needs to be made.
Opened #151 |
I think this is the first time anyone from homebrew has connected to the Circle Pad Pro (or they never talked about it online). It took a while, but I figured out you just have to be persistent during the connection phase (do immediate retries).
This PR adds a service wrapper for the ir:USER service, and a example/demo of using it to connect to the Circle Pad Pro (the main usage of the service as far as I can tell).
Note that the New 3DS internally emulates the Circle Pad Pro, so using
ir:USER
on a New 3DS system should give you the c-stick inputs. Their:rst
service is slightly different, where it only works on the New 3DS (doesn't give CPP inputs). Most retail 3DS games useir:USER
to be compatible with both old and new 3DS systems.Reference links:
BTW if you're curious what I want to use this for:
https://github.com/AzureMarker/n3ds-controller
Demo:
Note: the screen no longer flickers after enabling double buffering.
CPP.demo.video.compressed.mp4