Implement 'set_color' for corsair lighting pro
[temp2RGB.git] / src / corsair_lighting_pro.rs
1 use crate::rgb::RGB;
2
3 const CORSAIR_VID: u16 = 0x1B1C;
4 const CORSAIR_LIGHTING_NODE_PRO_PID: u16 = 0x0C0B;
5
6 const CORSAIR_LIGHTING_NODE_PACKET_ID_FIRMWARE: u8 = 0x02; // Get firmware version
7 const CORSAIR_LIGHTING_NODE_PACKET_ID_DIRECT: u8 = 0x32; // Direct mode LED update packet
8 const CORSAIR_LIGHTING_NODE_PACKET_ID_COMMIT: u8 = 0x33; // Commit changes packet
9 const CORSAIR_LIGHTING_NODE_PACKET_ID_BEGIN: u8 = 0x34; // Begin effect packet
10 const CORSAIR_LIGHTING_NODE_PACKET_ID_EFFECT_CONFIG: u8 = 0x35; // Effect mode configuration packet
11 const CORSAIR_LIGHTING_NODE_PACKET_ID_TEMPERATURE: u8 = 0x36; // Update temperature value packet
12 const CORSAIR_LIGHTING_NODE_PACKET_ID_RESET: u8 = 0x37; // Reset channel packet
13 const CORSAIR_LIGHTING_NODE_PACKET_ID_PORT_STATE: u8 = 0x38; // Set port state packet
14 const CORSAIR_LIGHTING_NODE_PACKET_ID_BRIGHTNESS: u8 = 0x39; // Set brightness packet
15 const CORSAIR_LIGHTING_NODE_PACKET_ID_LED_COUNT: u8 = 0x3A; // Set LED count packet
16 const CORSAIR_LIGHTING_NODE_PACKET_ID_PROTOCOL: u8 = 0x3B; // Set protocol packet
17
18 const CORSAIR_LIGHTING_NODE_PORT_STATE_HARDWARE: u8 = 0x01; // Effect hardware control of channel
19 const CORSAIR_LIGHTING_NODE_PORT_STATE_SOFTWARE: u8 = 0x02; // Direct software control of channel
20
21 const CORSAIR_LIGHTING_NODE_MODE_STATIC: u8 = 0x04; // Static mode
22
23 const CORSAIR_LIGHTING_NODE_DIRECT_CHANNEL_RED: u8 = 0x00;
24 const CORSAIR_LIGHTING_NODE_DIRECT_CHANNEL_GREEN: u8 = 0x01;
25 const CORSAIR_LIGHTING_NODE_DIRECT_CHANNEL_BLUE: u8 = 0x02;
26
27 const CHANNEL_COUNT: u8 = 2;
28 const NB_LEDS: u8 = 20;
29
30 pub struct Device {
31 device: hidapi::HidDevice,
32 }
33
34 impl Device {
35 pub fn new(api: &hidapi::HidApi, initial_color: &RGB) -> Self {
36 let device = Device {
37 device: api
38 .open(CORSAIR_VID, CORSAIR_LIGHTING_NODE_PRO_PID)
39 .unwrap(),
40 };
41
42 for channel_id in 0..CHANNEL_COUNT {
43 device.send_reset(channel_id);
44 device.send_begin(channel_id);
45 device.send_port_state(channel_id, CORSAIR_LIGHTING_NODE_PORT_STATE_HARDWARE);
46 device.send_effect_config(channel_id, initial_color);
47 device.send_commit(channel_id);
48 }
49
50 device
51 }
52
53 fn send_reset(&self, channel_id: u8) {
54 let mut buffer = [0u8; 65];
55 buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_RESET;
56 buffer[0x02] = channel_id;
57
58 let n_write = self.device.write(&buffer).unwrap();
59 assert_eq!(n_write, 65);
60
61 let n_read = self.device.read(&mut buffer[0..16]).unwrap();
62 assert_eq!(n_read, 16);
63 assert_eq!(buffer[0], 0);
64 }
65
66 fn send_begin(&self, channel_id: u8) {
67 let mut buffer = [0u8; 65];
68 buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_BEGIN;
69 buffer[0x02] = channel_id;
70
71 let n_write = self.device.write(&buffer).unwrap();
72 assert_eq!(n_write, 65);
73
74 let n_read = self.device.read(&mut buffer[0..16]).unwrap();
75 assert_eq!(n_read, 16);
76 assert_eq!(buffer[0], 0);
77 }
78
79 fn send_port_state(&self, channel_id: u8, state: u8) {
80 let mut buffer = [0u8; 65];
81 buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_PORT_STATE;
82 buffer[0x02] = channel_id;
83 buffer[0x03] = state;
84
85 let n_write = self.device.write(&buffer).unwrap();
86 assert_eq!(n_write, 65);
87
88 let n_read = self.device.read(&mut buffer[0..16]).unwrap();
89 assert_eq!(n_read, 16);
90 assert_eq!(buffer[0], 0);
91 }
92
93 fn send_effect_config(&self, channel_id: u8, color: &RGB) {
94 println!("{color:?}");
95
96 let mut buffer = [0u8; 65];
97 buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_EFFECT_CONFIG;
98 buffer[0x02] = channel_id;
99 buffer[0x03] = 0x00; // count.
100 buffer[0x04] = NB_LEDS; // led type. (number of leds!?).
101 buffer[0x05] = CORSAIR_LIGHTING_NODE_MODE_STATIC; // mode: static.
102 buffer[0x06] = 0x00; // speed.
103 buffer[0x07] = 0x00; // direction.
104 buffer[0x08] = 0x00; // change style (random).
105 buffer[0x09] = 0x00;
106
107 let offset_color = 0x0A;
108 for i in 0..3 {
109 buffer[offset_color + 3 * i] = color.red;
110 buffer[offset_color + 3 * i + 1] = color.green;
111 buffer[offset_color + 3 * i + 2] = color.blue;
112 }
113
114 let n_write = self.device.write(&buffer).unwrap();
115 assert_eq!(n_write, 65);
116
117 let n_read = self.device.read(&mut buffer[0..16]).unwrap();
118 assert_eq!(n_read, 16);
119 assert_eq!(buffer[0], 0);
120 }
121
122 fn send_commit(&self, channel_id: u8) {
123 let mut buffer = [0u8; 65];
124 buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_COMMIT;
125 buffer[0x02] = 0xFF;
126
127 let n_write = self.device.write(&buffer).unwrap();
128 assert_eq!(n_write, 65);
129
130 let n_read = self.device.read(&mut buffer[0..16]).unwrap();
131 assert_eq!(n_read, 16);
132 assert_eq!(buffer[0], 0);
133 }
134
135 pub fn set_color(&self, color: &RGB) {
136 // println!("set_color: {color:?}");
137 for channel_id in 0..CHANNEL_COUNT {
138 self.send_port_state(channel_id, CORSAIR_LIGHTING_NODE_PORT_STATE_SOFTWARE);
139
140 let mut buffer = [0u8; 65];
141
142 for color_channel in [
143 CORSAIR_LIGHTING_NODE_DIRECT_CHANNEL_RED,
144 CORSAIR_LIGHTING_NODE_DIRECT_CHANNEL_GREEN,
145 CORSAIR_LIGHTING_NODE_DIRECT_CHANNEL_BLUE,
146 ] {
147 buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_DIRECT;
148 buffer[0x02] = channel_id;
149 buffer[0x04] = NB_LEDS; // Number of color;
150 buffer[0x05] = color_channel;
151
152 let color_component = match color_channel {
153 0 => color.red,
154 1 => color.green,
155 _ => color.blue,
156 };
157
158 for n in 0..NB_LEDS {
159 buffer[0x06 + n as usize] = color_component;
160 }
161
162 let n_write = self.device.write(&buffer).unwrap();
163 assert_eq!(n_write, 65);
164
165 let n_read = self.device.read(&mut buffer[0..16]).unwrap();
166 assert_eq!(n_read, 16);
167 assert_eq!(buffer[0], 0);
168 }
169
170 self.send_commit(channel_id);
171 }
172 }
173 }