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

OpenRGB Support #151

Closed
CalcProgrammer1 opened this issue Jun 25, 2020 · 7 comments · Fixed by #152
Closed

OpenRGB Support #151

CalcProgrammer1 opened this issue Jun 25, 2020 · 7 comments · Fixed by #152
Assignees
Labels
bug Something isn't working
Milestone

Comments

@CalcProgrammer1
Copy link
Contributor

CalcProgrammer1 commented Jun 25, 2020

Describe the bug
I'm the developer of OpenRGB and my project supports the real Lighting Node devices. I'd like to make sure it works with CorsairLightingProtocol as I would like to be able to recommend an Arduino running this project as a recommended controller for OpenRGB users.

Unfortunately, OpenRGB has trouble controlling an Arduino Pro Micro running CorsairLightingProtocol as a Lighting Node Pro. A real Lighting Node Pro works correctly. It may be that my implementation of the Corsair protocol doesn't exactly match iCue, but my code does work on a real Lighting Node Pro.

OpenRGB sends a keepalive (apply) message every 5 seconds as a real Lighting Node device will revert to the saved hardware effect mode after 20 seconds of bus inactivity. It seems like CorsairLightingProtocol is applying changes on this keepalive rather than on the actual color update message. After a few tries, it becomes unresponsive.

Here is my protocol documentation. This is what I based my driver in OpenRGB on:

https://gitlab.com/CalcProgrammer1/OpenRGB/-/wikis/Corsair-Lighting-Node-Devices

I'm entirely open to the idea that I'm doing something wrong in OpenRGB. This may not be CorsairLightingProtocol's fault.

OpenRGB issue link: https://gitlab.com/CalcProgrammer1/OpenRGB/-/issues/355

What works?
OpenRGB successfully detects my Arduino as a Lighting Node Pro. I flashed the Lighting Node CORE sketch so I'm not sure why. It shows up in Zadig/Device Manager/lsusb as a Pro. Firmware version is correctly reported.

To Reproduce
Steps to reproduce the behavior:

  1. Flash Arduino as Lighting Node Pro
  2. Start OpenRGB
  3. Resize channel 1 to number of LEDs (15 tested)
  4. Click a color and Set Device

Expected behavior
Lights immediately change to selected color

Effect modes work

Actual behavior
Lights don't immediately change, sometimes apply set color on the 5s keepalive command.

Effect modes turn off the LEDs

System:

  • OS: Windows 10 and Debian Linux
  • Board: Arduino Pro Micro
  • IDE: Arduino IDE
  • Version: 0.13.0
  • Sketch: LightingNodeCORE

Code changes
None

@CalcProgrammer1 CalcProgrammer1 added the bug Something isn't working label Jun 25, 2020
@Legion2
Copy link
Owner

Legion2 commented Jun 25, 2020

I update the leds on the command 0x33 (WRITE_LED_TRIGGER) which is send by iCUE after a completed update to the configuration, so it guarantees a consistent state (some state is persisted on the Arduino). This is especially important with software playback, because the different colors (red, blue, green) are updated in a sequence of commands, so I can only update the leds after the sequence is complete. And currently this is indicated by the command 0x33.

if (command.command == WRITE_LED_TRIGGER) {
triggerLEDUpdate();
saveIfNeeded();
} else {

After a few tries, it becomes unresponsive.

What do you send as keepalive (apply) messages? You mean after some the keepalive messages the arduino becomes unresponsive?

Here is my protocol documentation.

The "Device Types" are actually the number of LEDs of that device, at least I have implemented it that way and it works.
I called the "Effect Configuration" LEDGroup:

LEDGroup group;
group.ledIndex = data[1];
group.ledCount = data[2];
group.mode = data[3];
group.speed = static_cast<GroupSpeed>(data[4]);
group.direction = static_cast<GroupDirection>(data[5]);
group.extra = static_cast<GroupExtra>(data[6]);
group.tempGroup = data[7];
group.color1.r = data[8];
group.color1.g = data[9];
group.color1.b = data[10];
group.color2.r = data[11];
group.color2.g = data[12];
group.color2.b = data[13];
group.color3.r = data[14];
group.color3.g = data[15];
group.color3.b = data[16];
group.temp1 = CLP::fromBigEndian(data[17], data[18]);
group.temp2 = CLP::fromBigEndian(data[19], data[20]);
group.temp3 = CLP::fromBigEndian(data[21], data[22]);

@CalcProgrammer1
Copy link
Contributor Author

My keepalive loop is a trigger (0x33, I called this CORSAIR_LIGHTING_NODE_PACKET_ID_COMMIT) message sent every 5 seconds. I also send a commit after every command.

SendCommit: https://gitlab.com/CalcProgrammer1/OpenRGB/-/blob/master/Controllers/CorsairLightingNodeController/CorsairLightingNodeController.cpp#L258

My Effect Configuration function, it looks like my structure lines up with yours:

CORSAIR_LIGHTING_NODE_PACKET_ID_EFFECT_CONFIG = 0x35, /* Effect mode configuration packet */

https://gitlab.com/CalcProgrammer1/OpenRGB/-/blob/master/Controllers/CorsairLightingNodeController/CorsairLightingNodeController.cpp#L303

The *10 on the count is probably an error. I'm going to remove it.

@Legion2
Copy link
Owner

Legion2 commented Jun 25, 2020

The *10 on the count is probably an error. I'm going to remove it.

Don't remove it, it's the offset on the led strip for the effect. 10 is correct in case of corsair 10 LEDs strip, it should be the sum of all previous led_type. I use usb_buf[0x02] as offset and usb_buf[0x03] as length on the led strip for the effect and this works with iCUE(only uses offset 0) and SIV which can set multiple effects on a channel.

@Legion2
Copy link
Owner

Legion2 commented Jun 25, 2020

I can think of two possible problems (beside the *10) on my side.

  1. There is a problem when 0x33 is received but there is nothing to commit
  2. The keepalive packets are mixed with a sequence of other critical commands and cause some problem when committed in a dirty state.

I will look into these over the weekend.

@Legion2 Legion2 self-assigned this Jun 25, 2020
@CalcProgrammer1
Copy link
Contributor Author

CalcProgrammer1 commented Jun 26, 2020

I'm going to continue experimenting this weekend as well. I added some sleeps between packet sends and that seems to have made it a bit more reliable, but it's only controlling the red channel in direct mode. I haven't messed with the effect modes (built-in effects) yet.

Edit: It is a lot more reliable (and I can get all color channels working) if I perform a read every time I perform a write.

Edit 2: Definitely seems to be a timing issue, even if it's not the only issue. If I send all three channels of data back-to-back it has major trouble updating. Much more reliable with 1ms gaps between each packet. Still has a lot of stuttering when I try to send updates at 25ms though.

Edit 3: Reflashed my Arduino with the Lighting Node PRO sketch. It's doing some very strange things when I try to send a rainbow pattern in direct mode. It updates much slower than the real LNP and it seems to distort the colors a lot. I'll try to set up a demo.

Edit 4: Commented out saving and sending replies:

	if (triggerSave) {
		triggerSave = false;
		//save();
	}
void CorsairLightingProtocolHID::sendX(const uint8_t* data, const size_t x) const {
#if defined(DEBUG) && defined(VERBOSE)
	if (printResponse) {
		Serial.print(F("Send Response: "));
		Serial.println(data[0], HEX);
	}
#endif
	//CLP::RawHID.write(data, x);
}

It's running smoothly with 25ms update rate and no hid_reads.

@CalcProgrammer1
Copy link
Contributor Author

CalcProgrammer1 commented Jun 26, 2020

I uncommented the save and it is still working fine. The effect I set with OpenRGB is saved and starts back up if I unplug and reconnect it.

My guess is that there's something going on with the writes. On the real LNP I don't need to do HID reads after each write, and in fact doing so seems to cause slowdowns and stalls.

Edit: More digging. I added support for the fan controllers on the Commander Pro a few weeks ago in a branch. During that investigation I found that the Commander Pro uses a 16-byte reply and that I would have to read it after every write if I wanted the fan RPM reads to be reliable. I looked and the reply buffer in CLP is 64 bytes. I changed it to 16:

#define RESPONSE_SIZE 16
#define RAWHID_TX_SIZE 16

Now it appears to be working well with the writes and saves enabled (with 1ms delays added between transactions).

EDIT: Taking out the 1ms delay is no problem since the read acts as a delay.

@CalcProgrammer1
Copy link
Contributor Author

CalcProgrammer1 commented Jun 26, 2020

Pushed a change to OpenRGB that gets it working with CLP as long as the 64->16 reply size change is implemented.

Tested the 16 byte reply on iCue and it seems to work just fine as well. Firmware version is received correctly and all effects work.

Added pull request:

#152

It looks to be failing one of the automated tests, but it built and ran successfully on my Pro Micro (which shows up as an Arduino Leonardo).

@Legion2 Legion2 added this to the 0.14.0 milestone Jun 26, 2020
@Legion2 Legion2 linked a pull request Jun 27, 2020 that will close this issue
@Legion2 Legion2 mentioned this issue Jun 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants