+use crate::rgb::RGB;
+
+const CORSAIR_VID: u16 = 0x1B1C;
+const CORSAIR_LIGHTING_NODE_PRO_PID: u16 = 0x0C0B;
+
+const CORSAIR_LIGHTING_NODE_PACKET_ID_FIRMWARE: u8 = 0x02; // Get firmware version
+const CORSAIR_LIGHTING_NODE_PACKET_ID_DIRECT: u8 = 0x32; // Direct mode LED update packet
+const CORSAIR_LIGHTING_NODE_PACKET_ID_COMMIT: u8 = 0x33; // Commit changes packet
+const CORSAIR_LIGHTING_NODE_PACKET_ID_BEGIN: u8 = 0x34; // Begin effect packet
+const CORSAIR_LIGHTING_NODE_PACKET_ID_EFFECT_CONFIG: u8 = 0x35; // Effect mode configuration packet
+const CORSAIR_LIGHTING_NODE_PACKET_ID_TEMPERATURE: u8 = 0x36; // Update temperature value packet
+const CORSAIR_LIGHTING_NODE_PACKET_ID_RESET: u8 = 0x37; // Reset channel packet
+const CORSAIR_LIGHTING_NODE_PACKET_ID_PORT_STATE: u8 = 0x38; // Set port state packet
+const CORSAIR_LIGHTING_NODE_PACKET_ID_BRIGHTNESS: u8 = 0x39; // Set brightness packet
+const CORSAIR_LIGHTING_NODE_PACKET_ID_LED_COUNT: u8 = 0x3A; // Set LED count packet
+const CORSAIR_LIGHTING_NODE_PACKET_ID_PROTOCOL: u8 = 0x3B; // Set protocol packet
+
+const CORSAIR_LIGHTING_NODE_PORT_STATE_HARDWARE: u8 = 0x01; // Effect hardware control of channel
+const CORSAIR_LIGHTING_NODE_PORT_STATE_SOFTWARE: u8 = 0x02; // Direct software control of channel
+
+const CORSAIR_LIGHTING_NODE_MODE_STATIC: u8 = 0x04; // Static mode
+
+const CHANNEL_COUNT: u8 = 2;
+
+pub struct Device {
+ device: hidapi::HidDevice,
+}
+
+impl Device {
+ pub fn new(api: &hidapi::HidApi) -> Self {
+ let device = Device {
+ device: api
+ .open(CORSAIR_VID, CORSAIR_LIGHTING_NODE_PRO_PID)
+ .unwrap(),
+ };
+
+ for channel_id in 0..CHANNEL_COUNT {
+ device.send_reset(channel_id);
+ device.send_begin(channel_id);
+ device.send_port_state(channel_id, CORSAIR_LIGHTING_NODE_PORT_STATE_HARDWARE);
+ device.send_effect_config(
+ channel_id,
+ &RGB {
+ red: 0x00,
+ green: 0x00,
+ blue: 0x00,
+ },
+ );
+ device.send_commit(channel_id);
+ }
+
+ device
+ }
+
+ pub fn set_color(&self, color: &RGB) {
+ for channel_id in 0..CHANNEL_COUNT {
+ self.send_effect_config(channel_id, color);
+ }
+ }
+
+ fn send_reset(&self, channel_id: u8) {
+ let mut buffer = [0u8; 65];
+ buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_RESET;
+ buffer[0x02] = channel_id;
+
+ let n_write = self.device.write(&buffer).unwrap();
+ assert_eq!(n_write, 65);
+
+ let n_read = self.device.read(&mut buffer[0..16]).unwrap();
+ assert_eq!(n_read, 16);
+ }
+
+ fn send_begin(&self, channel_id: u8) {
+ let mut buffer = [0u8; 65];
+ buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_BEGIN;
+ buffer[0x02] = channel_id;
+
+ let n_write = self.device.write(&buffer).unwrap();
+ assert_eq!(n_write, 65);
+
+ let n_read = self.device.read(&mut buffer[0..16]).unwrap();
+ assert_eq!(n_read, 16);
+ }
+
+ fn send_port_state(&self, channel_id: u8, state: u8) {
+ let mut buffer = [0u8; 65];
+ buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_PORT_STATE;
+ buffer[0x02] = channel_id;
+ buffer[0x03] = state;
+
+ let n_write = self.device.write(&buffer).unwrap();
+ assert_eq!(n_write, 65);
+
+ let n_read = self.device.read(&mut buffer[0..16]).unwrap();
+ assert_eq!(n_read, 16);
+ }
+
+ fn send_effect_config(&self, channel_id: u8, color: &RGB) {
+ let mut buffer = [0u8; 65];
+ buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_EFFECT_CONFIG;
+ buffer[0x02] = channel_id;
+ buffer[0x03] = 0x00; // count.
+ buffer[0x04] = 0x1E; // led type.
+ buffer[0x05] = CORSAIR_LIGHTING_NODE_MODE_STATIC; // mode: static.
+ buffer[0x06] = 0x00; // speed.
+ buffer[0x07] = 0x00; // direction.
+ buffer[0x08] = 0x00; // change style (random).
+ buffer[0x09] = 0x00;
+
+ let offset_color = 0x0A;
+ for i in 0..3 {
+ buffer[offset_color + 3 * i] = color.red;
+ buffer[offset_color + 3 * i + 1] = color.green;
+ buffer[offset_color + 3 * i + 2] = color.blue;
+ }
+
+ let n_write = self.device.write(&buffer).unwrap();
+ assert_eq!(n_write, 65);
+
+ let n_read = self.device.read(&mut buffer[0..16]).unwrap();
+ assert_eq!(n_read, 16);
+ }
+
+ fn send_commit(&self, channel_id: u8) {
+ let mut buffer = [0u8; 65];
+ buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_COMMIT;
+ buffer[0x02] = 0xFF;
+
+ let n_write = self.device.write(&buffer).unwrap();
+ assert_eq!(n_write, 65);
+
+ let n_read = self.device.read(&mut buffer[0..16]).unwrap();
+ assert_eq!(n_read, 16);
+ }
+}