-
Notifications
You must be signed in to change notification settings - Fork 6
Added support for NES controllers. #38
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
Added support for NES controllers. #38
Conversation
|
Based on Davidobot#1220 |
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.
Thanks for your contribution. Please look at the review.
BetterJoy/Joycon.cs
Outdated
| { | ||
| Span<byte> resp = stackalloc byte[ReportLength]; | ||
|
|
||
| for (int i = 0; i < 100; ++i) { |
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.
100 is too much, reduce this to 5. (same as ReadSPICheck) and keep the style as
for ()
{
}
instead of
for () {
}
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.
Fixed.
BetterJoy/Joycon.cs
Outdated
| Span<byte> resp = stackalloc byte[ReportLength]; | ||
|
|
||
| for (int i = 0; i < 100; ++i) { | ||
| int respLength = SubcommandCheck(0x02, Array.Empty<byte>(), resp, false, 200); |
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.
Remove the ", 200" parameter and use a collection expression [] instead of Array.Empty<byte>().
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.
Fixed.
BetterJoy/Joycon.cs
Outdated
| for (int i = 0; i < 100; ++i) { | ||
| int respLength = SubcommandCheck(0x02, Array.Empty<byte>(), resp, false, 200); | ||
|
|
||
| if (respLength >= 15 && resp[15] == 0x03) { |
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.
15 is incorrect, it's the index to the first byte of the firmware version. You should use 17. (information here)
You might want to change 0x03 too unless it's really the value that is used for the NES controller. (I don't have one to test). 1 is left joycon, 2 is right joycon and 3 is pro controller.
You should use > and not >= since the index starts at 0.
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.
Great catch! I think I misread the output and was for some reason thinking it was replying as a pro controller. I was having a heck of a time getting a response on the original fork (hence the massive attempt numbers) so I also may have read the wrong packet at some point and it just happen to have worked due to firmware versioning.
BetterJoy/Joycon.cs
Outdated
| break; | ||
| } | ||
|
|
||
| if (resp[15] == 0x02) { |
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.
Any other value than the one for the NES should break the loop. So the content of the for should be changed to :
if (respLength > 17)
{
if (resp[17] == 0x03) // you should check that the 0x03 value is correct as stated in my previous comment
{
Type = ControllerType.NES;
}
break;
}
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.
Fixed.
BetterJoy/Joycon.cs
Outdated
| } | ||
|
|
||
| //Make sure we're not actually a nes controller | ||
| if (this.Type == ControllerType.JoyconRight) |
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.
You can remove this.
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.
Removed.
BetterJoy/Joycon.cs
Outdated
| } | ||
|
|
||
| private int SubcommandCheck(byte sc, ReadOnlySpan<byte> bufParameters, Span<byte> response, bool print = true) | ||
| private int SubcommandCheck(byte sc, ReadOnlySpan<byte> bufParameters, Span<byte> response, bool print = true, int retries = 10) |
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.
Remove this change , int retries = 10
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.
Removed.
BetterJoy/Joycon.cs
Outdated
| JoyconLeft, | ||
| JoyconRight, | ||
| SNES, | ||
| NES, |
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.
You need to add NES at the end of the enum or it will break the saved datas for third party controller window.
Also for the third party controller feature to work properly, you need to add to the switch in the TypeToProdId function :
case 6:
return ProductNES;
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.
Fixed, and made the numerics explicit in the enum to reduce brittleness.
|
Thanks for the review! I'll fix these and get back to you. |
|
Hold on, I think I broke something. |
|
Ok, that should have fixed it. Turns out the NES controllers report differently (left or right) as to what they are. |
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.
A few more changes and we're good.
BetterJoy/Joycon.cs
Outdated
| //Make sure we're not actually a nes controller | ||
| if (Type == ControllerType.JoyconRight) | ||
| { | ||
| CheckIfRightIsNes(); | ||
| } |
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.
Move this below just after SetReportMode(ReportMode.SimpleHID, false);
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.
Fixed.
BetterJoy/Joycon.cs
Outdated
| { | ||
| var respLength = SubcommandCheck(0x02, [], response, false); | ||
|
|
||
| if (respLength >= 20 && response[0] == 0x21 && response[14] == 0x02) |
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.
You can remove && response[0] == 0x21 && response[14] == 0x02 as it is already checked by SubcommandCheck. Keeping respLength >= 20 is fine.
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.
While this is checked, it is not checked in a way that is useful for us here.
private int SubcommandCheck(byte sc, ReadOnlySpan<byte> bufParameters, Span<byte> response, bool print = true)
{
int length = Subcommand(sc, bufParameters, print);
if (length <= 0)
{
DebugPrint($"Subcommand write error: {ErrorMessage()}", DebugType.Comms);
return length;
}
int tries = 0;
bool responseFound;
do
{
length = Read(response, 100); // don't set the timeout lower than 100 or might not always work
responseFound = length >= 20 && response[0] == 0x21 && response[14] == sc;
if (length < 0)
{
DebugPrint($"Subcommand read error: {ErrorMessage()}", DebugType.Comms);
}
tries++;
} while (tries < 10 && !responseFound && length >= 0);
if (!responseFound)
{
DebugPrint("No response.", DebugType.Comms);
return length;
}
if (print)
{
PrintArray<byte>(
response,
DebugType.Comms,
length - 1,
1,
$"Response ID {response[0]:X2}." + " Data: {0:S}"
);
}
return length;
}
The while loop continues until a response is found OR until we run out of tries. In the event we run out of tries, the function just gives us the last read item, regardless of if it passed that check or not. We check it again here so we can run another iteration of the for loop if necessary.
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.
Good catch, that was a bug I fixed yesterday in e2d603e, now it returns 0 properly if no response was found so you can remove it.
BetterJoy/Joycon.cs
Outdated
| SetNFCIR(false); | ||
| SetReportMode(ReportMode.StandardFull); | ||
|
|
||
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.
Unwanted white spaces.
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.
Fixed.
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.
Those files shouldn't be changed. It was changed by your merge commit.
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.
Sorry, this is my first time working with submodules. I think I fixed it.
| return true; | ||
| } | ||
|
|
||
| private void CheckIfRightIsNes() |
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.
Should throw a DeviceComFailedException if it failed so it tries to reconnect the controller like so :
private void CheckIfRightIsNes()
{
Span<byte> response = stackalloc byte[ReportLength];
var ok = false;
for (var i = 0; i < 5; ++i)
{
var respLength = SubcommandCheck(0x02, [], response, false);
if (respLength >= 20)
{
// NES controllers share the hardware ID of the right joycon, but respond here differently.
if (response[17] == 0x0A || response[17] == 0x09)
{
Type = ControllerType.NES;
}
ok = true;
break;
}
}
if (!ok)
{
throw new DeviceComFailedException("reset device info");
}
}
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.
Fixed
BetterJoy/Joycon.cs
Outdated
|
|
||
| if (respLength >= 20 && response[0] == 0x21 && response[14] == 0x02) | ||
| { | ||
| if (response[17] == 0x0A || response[17] == 0x09) //NES controllers share the Right hardware ID of the right joycon, but respond here differently. |
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.
Please add to the comment which value correspond to left and right for 0x0A and 0x09
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.
Fixed
|
I got all the stuff that needed fixes and replied to your one comment regarding the duplicated message check. Let me know if that is sufficient or if you need anything tweaked. 👍 |
|
Thank you, only the duplicate check in CheckIfRightIsNes needs to be removed since it was a bug that was fixed very recently and I can merge. |
|
Ok, I removed the redundant check, now we just check for a valid response via looking if the response length is greater than 0. |
|
Thanks, merged! |
Added support for nes controllers.