e639d385245e33006e6be11ecee780222f09be91
[temp2RGB.git] / src / asus_aura_usb.rs
1 use std::str;
2
3 use crate::rgb::RGB;
4
5 /*
6 * Doc:
7 * - https://blog.inlart.com/post/openrgb-asus-x570/
8 * - https://openrgb-wiki.readthedocs.io/en/latest/asus/ASUS-Aura-USB/
9 */
10
11 const AURA_REQUEST_FIRMWARE_VERSION: u8 = 0x82;
12 const AURA_REQUEST_CONFIG_TABLE: u8 = 0xB0;
13
14 const VID: u16 = 0x0B05; // Vendor ID: ASUS.
15
16 const PID_650_E: u16 = 0x19AF; // Product ID: AURA LED Controller.
17 const PID_CROSSHAIR: u16 = 0x18F3; // Product ID: AURA LED Controller.
18
19 pub enum Motherboard {
20 Asus650e,
21 AsusCrosshairVIIIHero,
22 }
23
24 pub struct Device {
25 device: hidapi::HidDevice,
26 motherboard: Motherboard,
27 }
28
29 impl Device {
30 pub fn new(api: &hidapi::HidApi, motherboard: Motherboard) -> Self {
31 let device = Device {
32 device: api
33 .open(
34 VID,
35 match motherboard {
36 Motherboard::Asus650e => PID_650_E,
37 Motherboard::AsusCrosshairVIIIHero => PID_CROSSHAIR,
38 },
39 )
40 .unwrap(),
41 motherboard,
42 };
43
44 device.set_fixed_mode();
45 device
46 }
47
48 pub fn get_firmware_string(&self) -> String {
49 let mut buffer = [0u8; 65];
50 buffer[0] = 0xEC;
51 buffer[1] = AURA_REQUEST_FIRMWARE_VERSION;
52 let n_write = self.device.write(&buffer).unwrap();
53 assert_eq!(n_write, 65);
54
55 buffer.fill(0);
56 let n_read = self.device.read(&mut buffer).unwrap();
57 assert_eq!(n_read, 65);
58 assert_eq!(buffer[0], 0xEC);
59 assert_eq!(buffer[1], 0x02);
60
61 String::from(str::from_utf8(&buffer[2..17]).unwrap())
62 }
63
64 /*
65 Example of configuration table:
66 - Positions 0 and 1 always 1E and 9F.
67 - Value 02 is the number of adressable channels.
68 1E 9F 02 01 00 00
69 78 3C 00 01 00 00
70 78 3C 00 00 00 00
71 00 00 00 00 00 00
72 00 00 00 08 0A 02
73 01 F4 00 00 00 00
74 00 00 00 00 00 00
75 00 00 00 00 00 00
76 00 00 00 00 00 00
77 00 00 00 00 00 00
78 */
79 pub fn get_configuration_table(&self) -> [u8; 60] {
80 let mut buffer = [0u8; 65];
81 buffer[0] = 0xEC;
82 buffer[1] = AURA_REQUEST_CONFIG_TABLE;
83 let n_write = self.device.write(&buffer).unwrap();
84 assert_eq!(n_write, 65);
85
86 buffer.fill(0);
87 let n_read = self.device.read(&mut buffer).unwrap();
88 assert_eq!(n_read, 65);
89 assert_eq!(buffer[0], 0xEC);
90 assert_eq!(buffer[1], 0x30);
91
92 buffer[4..64]
93 .try_into()
94 .expect("slice with incorrect length")
95 }
96
97 fn set_fixed_mode(&self) {
98 let mut buffer = [0u8; 65];
99 buffer[0] = 0xEC;
100 buffer[1] = 0x35; // Control mode.
101 buffer[4] = 0x00; // Shutdown effect.
102 buffer[5] = 0x01; // Mode id: static.
103
104 for channel_effect_id in 0..2 {
105 buffer[2] = channel_effect_id; // Channel effect id: Fixed.
106 let n_write = self.device.write(&buffer).unwrap();
107 assert_eq!(n_write, 65);
108 }
109 }
110
111 pub fn set_color(&self, color: &RGB) {
112 let mut buffer = [0u8; 65];
113 buffer[0] = 0xEC;
114 buffer[1] = 0x36;
115
116 let start_led = 0u32;
117 let nb_of_leds = 16u32;
118 let mask = ((1u32 << nb_of_leds) - 1u32) << start_led;
119
120 buffer[2] = (mask >> 8) as u8; // 16 bits LED mask: first part.
121 buffer[3] = (mask & 0xFF) as u8; // 16 bits LED mask: second part.
122
123 for n in start_led as usize..(start_led + nb_of_leds) as usize {
124 buffer[5 + 3 * n] = color.red;
125 buffer[5 + 3 * n + 1] = color.green;
126 buffer[5 + 3 * n + 2] = color.blue;
127 }
128
129 let n_write = self.device.write(&buffer).unwrap();
130 assert_eq!(n_write, 65);
131 }
132
133 pub fn save_current_color(&self) {
134 let mut buffer = [0u8; 65];
135 buffer[0] = 0xEC;
136 buffer[1] = 0x3F;
137 buffer[2] = 0x55;
138
139 let n_write = self.device.write(&buffer).unwrap();
140 assert_eq!(n_write, 65);
141 }
142 }