Add Mshroom machine implementation
[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) -> anyhow::Result<Self> {
36 let device = Device {
37 device: api.open(CORSAIR_VID, CORSAIR_LIGHTING_NODE_PRO_PID)?,
38 };
39
40 for channel_id in 0..CHANNEL_COUNT {
41 device.send_reset(channel_id)?;
42 device.send_begin(channel_id)?;
43 device.send_port_state(channel_id, CORSAIR_LIGHTING_NODE_PORT_STATE_HARDWARE)?;
44 device.send_effect_config(channel_id, initial_color)?;
45 device.send_commit(channel_id)?;
46 }
47
48 Ok(device)
49 }
50
51 fn send_reset(&self, channel_id: u8) -> anyhow::Result<()> {
52 let mut buffer = [0u8; 65];
53 buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_RESET;
54 buffer[0x02] = channel_id;
55
56 let n_write = self.device.write(&buffer)?;
57 // assert_eq!(n_write, 65);
58
59 let n_read = self.device.read(&mut buffer[0..16])?;
60 // assert_eq!(n_read, 16);
61 // assert_eq!(buffer[0], 0);
62
63 Ok(())
64 }
65
66 fn send_begin(&self, channel_id: u8) -> anyhow::Result<()> {
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)?;
72 // assert_eq!(n_write, 65);
73
74 let n_read = self.device.read(&mut buffer[0..16])?;
75 // assert_eq!(n_read, 16);
76 // assert_eq!(buffer[0], 0);
77
78 Ok(())
79 }
80
81 fn send_port_state(&self, channel_id: u8, state: u8) -> anyhow::Result<()> {
82 let mut buffer = [0u8; 65];
83 buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_PORT_STATE;
84 buffer[0x02] = channel_id;
85 buffer[0x03] = state;
86
87 let n_write = self.device.write(&buffer)?;
88 // assert_eq!(n_write, 65);
89
90 let n_read = self.device.read(&mut buffer[0..16])?;
91 // assert_eq!(n_read, 16);
92 // assert_eq!(buffer[0], 0);
93
94 Ok(())
95 }
96
97 fn send_effect_config(&self, channel_id: u8, color: &Rgb) -> anyhow::Result<()> {
98 println!("{color:?}");
99
100 let mut buffer = [0u8; 65];
101 buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_EFFECT_CONFIG;
102 buffer[0x02] = channel_id;
103 buffer[0x03] = 0x00; // count.
104 buffer[0x04] = NB_LEDS; // led type. (number of leds!?).
105 buffer[0x05] = CORSAIR_LIGHTING_NODE_MODE_STATIC; // mode: static.
106 buffer[0x06] = 0x00; // speed.
107 buffer[0x07] = 0x00; // direction.
108 buffer[0x08] = 0x00; // change style (random).
109 buffer[0x09] = 0x00;
110
111 let offset_color = 0x0A;
112 for i in 0..3 {
113 buffer[offset_color + 3 * i] = color.red;
114 buffer[offset_color + 3 * i + 1] = color.green;
115 buffer[offset_color + 3 * i + 2] = color.blue;
116 }
117
118 let n_write = self.device.write(&buffer)?;
119 // assert_eq!(n_write, 65);
120
121 let n_read = self.device.read(&mut buffer[0..16])?;
122 // assert_eq!(n_read, 16);
123 // assert_eq!(buffer[0], 0);
124
125 Ok(())
126 }
127
128 fn send_commit(&self, channel_id: u8) -> anyhow::Result<()> {
129 let mut buffer = [0u8; 65];
130 buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_COMMIT;
131 buffer[0x02] = 0xFF;
132
133 let n_write = self.device.write(&buffer)?;
134 // assert_eq!(n_write, 65);
135
136 let n_read = self.device.read(&mut buffer[0..16])?;
137 // assert_eq!(n_read, 16);
138 // assert_eq!(buffer[0], 0);
139
140 Ok(())
141 }
142
143 pub fn set_color(&self, color: &Rgb) -> anyhow::Result<()> {
144 // println!("set_color: {color:?}");
145 for channel_id in 0..CHANNEL_COUNT {
146 self.send_port_state(channel_id, CORSAIR_LIGHTING_NODE_PORT_STATE_SOFTWARE)?;
147
148 let mut buffer = [0u8; 65];
149
150 for color_channel in [
151 CORSAIR_LIGHTING_NODE_DIRECT_CHANNEL_RED,
152 CORSAIR_LIGHTING_NODE_DIRECT_CHANNEL_GREEN,
153 CORSAIR_LIGHTING_NODE_DIRECT_CHANNEL_BLUE,
154 ] {
155 buffer[0x01] = CORSAIR_LIGHTING_NODE_PACKET_ID_DIRECT;
156 buffer[0x02] = channel_id;
157 buffer[0x04] = NB_LEDS; // Number of color;
158 buffer[0x05] = color_channel;
159
160 let color_component = match color_channel {
161 0 => color.red,
162 1 => color.green,
163 _ => color.blue,
164 };
165
166 for n in 0..NB_LEDS {
167 buffer[0x06 + n as usize] = color_component;
168 }
169
170 let n_write = self.device.write(&buffer)?;
171 // assert_eq!(n_write, 65);
172
173 let n_read = self.device.read(&mut buffer[0..16])?;
174 // assert_eq!(n_read, 16);
175 // assert_eq!(buffer[0], 0);
176 }
177
178 self.send_commit(channel_id)?;
179 }
180
181 Ok(())
182 }
183 }