First commit.
[temp2RGB.git] / src / main.rs
1 #[macro_use]
2 extern crate windows_service;
3
4 use std::{
5 collections::HashMap,
6 env,
7 ffi::OsString,
8 sync::{
9 atomic::{AtomicBool, Ordering},
10 Arc,
11 },
12 thread::sleep,
13 time::{self, Duration},
14 };
15
16 use windows::Win32::Foundation::{ERROR_SERVICE_DOES_NOT_EXIST, WIN32_ERROR};
17 use windows_service::{
18 service::{
19 ServiceAccess, ServiceControl, ServiceControlAccept, ServiceErrorControl, ServiceExitCode,
20 ServiceInfo, ServiceStartType, ServiceState, ServiceStatus, ServiceType,
21 },
22 service_control_handler::{self, ServiceControlHandlerResult, ServiceStatusHandle},
23 service_dispatcher,
24 service_manager::{ServiceManager, ServiceManagerAccess},
25 };
26 use wmi::{COMLibrary, Variant, WMIConnection};
27
28 use crate::rgb::RGB;
29
30 define_windows_service!(ffi_service_main, service_main);
31
32 mod winring0 {
33 #![allow(warnings, unused)]
34 include!(concat!(env!("OUT_DIR"), "/ols_api.rs"));
35 }
36
37 mod intel_arc {
38 #![allow(warnings, unused)]
39 include!(concat!(env!("OUT_DIR"), "/intel_arc.rs"));
40 }
41
42 mod a770;
43 mod b650_e;
44 mod machine;
45 mod main_loop;
46 // mod common;
47 mod consts;
48 mod corsair_vengeance;
49 mod piix4_i2c;
50 mod rgb;
51 // mod roccat; Disabled.
52 mod sensors_jiji;
53 mod settings;
54 mod timer;
55
56 fn main() -> Result<(), windows_service::Error> {
57 let args: Vec<String> = env::args().collect();
58
59 println!("Temperature to RGB");
60
61 if args.contains(&"--no-service".to_string()) {
62 let completed: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
63 main_loop::main_loop(completed.clone());
64 } else if args.contains(&"--tests".to_string()) {
65 tests();
66 } else if args.contains(&"--install-service".to_string()) {
67 println!("Installing service...");
68 install_service()?;
69 } else if args.contains(&"--uninstall-service".to_string()) {
70 println!("Uninstalling service...");
71 uninstall_service()?;
72 } else {
73 service_dispatcher::start(consts::SERVICE_NAME, ffi_service_main)?;
74 }
75
76 Ok(())
77 }
78
79 fn install_service() -> windows_service::Result<()> {
80 let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE;
81 let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
82
83 let service_binary_path = std::env::current_exe()
84 .unwrap()
85 .with_file_name("temp_2_rgb.exe");
86
87 println!("Installing service: {service_binary_path:?}");
88
89 let service_info = ServiceInfo {
90 name: OsString::from(consts::SERVICE_NAME),
91 display_name: OsString::from(consts::SERVICE_NAME),
92 service_type: ServiceType::OWN_PROCESS,
93 start_type: ServiceStartType::AutoStart,
94 error_control: ServiceErrorControl::Normal,
95 executable_path: service_binary_path,
96 launch_arguments: vec![],
97 dependencies: vec![],
98 account_name: None, // run as System
99 account_password: None,
100 };
101 let service = service_manager.create_service(&service_info, ServiceAccess::CHANGE_CONFIG)?;
102 service.set_description(
103 "A service to set the color of hardware according to the temperatur of GPU and CPU",
104 )?;
105 Ok(())
106 }
107
108 fn uninstall_service() -> windows_service::Result<()> {
109 let manager_access = ServiceManagerAccess::CONNECT;
110 let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
111
112 let service_access = ServiceAccess::QUERY_STATUS | ServiceAccess::STOP | ServiceAccess::DELETE;
113 let service = service_manager.open_service(consts::SERVICE_NAME, service_access)?;
114
115 // The service will be marked for deletion as long as this function call succeeds.
116 // However, it will not be deleted from the database until it is stopped and all open handles to it are closed.
117 service.delete()?;
118
119 // Our handle to it is not closed yet. So we can still query it.
120 if service.query_status()?.current_state != ServiceState::Stopped {
121 // If the service cannot be stopped, it will be deleted when the system restarts.
122 service.stop()?;
123 }
124
125 // Explicitly close our open handle to the service. This is automatically called when `service` goes out of scope.
126 drop(service);
127
128 // Win32 API does not give us a way to wait for service deletion.
129 // To check if the service is deleted from the database, we have to poll it ourselves.
130 let start = time::Instant::now();
131 let timeout = Duration::from_secs(5);
132 while start.elapsed() < timeout {
133 if let Err(windows_service::Error::Winapi(e)) =
134 service_manager.open_service(consts::SERVICE_NAME, ServiceAccess::QUERY_STATUS)
135 {
136 let WIN32_ERROR(error_num) = ERROR_SERVICE_DOES_NOT_EXIST;
137 if e.raw_os_error() == Some(error_num as i32) {
138 println!("{} is deleted.", consts::SERVICE_NAME);
139 return Ok(());
140 }
141 }
142 sleep(Duration::from_secs(1));
143 }
144 println!("{} is marked for deletion.", consts::SERVICE_NAME);
145
146 Ok(())
147 }
148
149 fn service_main(arguments: Vec<OsString>) {
150 if let Err(error) = run_service(arguments) {
151 println!("Error: {error}");
152 }
153 }
154
155 fn run_service(arguments: Vec<OsString>) -> Result<(), windows_service::Error> {
156 let completed: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
157
158 let completed_event_handler = Arc::clone(&completed);
159 let event_handler = move |control_event| -> ServiceControlHandlerResult {
160 match control_event {
161 ServiceControl::Stop => {
162 completed_event_handler.store(true, Ordering::Relaxed);
163 // Handle stop event and return control back to the system.
164 ServiceControlHandlerResult::NoError
165 }
166 // ServiceControl::Shutdown => {
167 // completed_event_handler.store(true, Ordering::Relaxed);
168 // // Handle stop event and return control back to the system.
169 // ServiceControlHandlerResult::NoError
170 // }
171 // ServiceControl::Preshutdown => {
172 // completed_event_handler.store(true, Ordering::Relaxed);
173 // ServiceControlHandlerResult::NoError
174 // }
175 // ServiceControl::PowerEvent(param) => {
176 // ServiceControlHandlerResult::NotImplemented
177 // }
178 // All services must accept Interrogate even if it's a no-op.
179 ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
180 _ => ServiceControlHandlerResult::NotImplemented,
181 }
182 };
183
184 // Register system service event handler
185 let status_handle = service_control_handler::register(consts::SERVICE_NAME, event_handler)?;
186
187 let running_status = ServiceStatus {
188 // Should match the one from system service registry
189 service_type: ServiceType::OWN_PROCESS,
190
191 // The new state
192 current_state: ServiceState::Running,
193
194 // Accept stop events when running
195 controls_accepted: ServiceControlAccept::STOP, // | ServiceControlAccept::SHUTDOWN,
196
197 // Used to report an error when starting or stopping only, otherwise must be zero
198 exit_code: ServiceExitCode::Win32(0),
199
200 // Only used for pending states, otherwise must be zero
201 checkpoint: 0,
202
203 // Only used for pending states, otherwise must be zero
204 wait_hint: Duration::default(),
205
206 process_id: None,
207 };
208
209 status_handle.set_service_status(running_status)?;
210
211 main_loop::main_loop(completed.clone());
212
213 status_handle.set_service_status(ServiceStatus {
214 service_type: ServiceType::OWN_PROCESS,
215 current_state: ServiceState::Stopped,
216 controls_accepted: ServiceControlAccept::empty(),
217 exit_code: ServiceExitCode::Win32(0),
218 checkpoint: 0,
219 wait_hint: Duration::default(),
220 process_id: None,
221 })?;
222
223 Ok(())
224 }
225
226 fn tests() {
227 println!("Running some tests...");
228
229 // test_b650_e();
230 // list_usb_devices();
231 // test_roccat();
232 // test_wmi();
233 // test_corsair();
234 test_a770();
235 // test_read_temp();
236
237 println!("Press any key to continue...");
238 std::io::stdin().read_line(&mut String::new()).unwrap();
239 }
240
241 fn test_wmi() {
242 let com_con = COMLibrary::new().unwrap();
243 let wmi_con = WMIConnection::new(com_con.into()).unwrap();
244
245 //let results: Vec<HashMap<String, Variant>> = wmi_con.raw_query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE '%SMBUS%' OR Description LIKE '%SM BUS%'").unwrap();
246 //let results: Vec<HashMap<String, Variant>> = wmi_con.raw_query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE 'Intel(R) NF I2C Host Controller'").unwrap();
247 let results: Vec<HashMap<String, Variant>> = wmi_con
248 .raw_query("SELECT * FROM Win32_PnPSignedDriver")
249 .unwrap();
250 //let results: Vec<HashMap<String, Variant>> = wmi_con.raw_query("SELECT * FROM Win32_PnPAllocatedResource").unwrap();
251
252 for os in results {
253 println!("-------------------");
254 println!("{:#?}", os);
255 }
256 }
257 fn list_usb_devices() {
258 let api = hidapi::HidApi::new().unwrap();
259 for device in api.device_list() {
260 println!("{:?}", device);
261 println!("name: {}", device.product_string().unwrap());
262 println!("interface number: {}", device.interface_number());
263 println!("page: {}", device.usage_page());
264 println!("usage: {}", device.usage());
265 println!("----");
266 }
267 }
268
269 // fn test_roccat() {
270 // let api = hidapi::HidApi::new().unwrap();
271 // let roccat_device = roccat::get_device(&api);
272
273 // let manufacturer = roccat_device.get_manufacturer_string().unwrap();
274 // dbg!(manufacturer);
275
276 // let product = roccat_device.get_product_string().unwrap();
277 // dbg!(product);
278
279 // let serial = roccat_device.get_serial_number_string().unwrap();
280 // dbg!(serial);
281
282 // roccat::init(&roccat_device);
283 // roccat::set_color(
284 // &roccat_device,
285 // &RGB {
286 // red: 0,
287 // green: 255,
288 // blue: 40,
289 // },
290 // );
291 // }
292
293 fn test_b650_e() {
294 let api = hidapi::HidApi::new().unwrap();
295
296 let b650e_device = b650_e::get_device(&api);
297
298 println!("Firmware: {}", b650_e::get_firmware_string(&b650e_device));
299
300 let configuration = b650_e::get_configuration_table(&b650e_device);
301 println!("Configuration:");
302 for i in 0..60 {
303 print!("{:02X} ", configuration[i]);
304 if (i + 1) % 6 == 0 {
305 println!("");
306 }
307 }
308
309 // Only once, at start.
310 b650_e::set_fixed_mode(&b650e_device);
311
312 b650_e::set_color(
313 &b650e_device,
314 &RGB {
315 red: 255,
316 green: 0,
317 blue: 0,
318 },
319 );
320 b650_e::save_current_color(&b650e_device);
321 }
322
323 fn test_corsair() {
324 let corsair_controllers = [
325 corsair_vengeance::Controller::new(0x19),
326 corsair_vengeance::Controller::new(0x1B),
327 ];
328 for controller in corsair_controllers {
329 controller.set_color(&RGB {
330 red: 255,
331 green: 0,
332 blue: 0,
333 });
334 }
335 }
336
337 fn test_a770() {
338 // a770::set_rgb(255, 0, 0);
339 let mut a770 = a770::A770::new();
340 a770.set_color(255, 0, 0);
341 }
342
343 fn test_read_temp() {
344 let sensors = sensors_jiji::Sensors::new();
345 println!("temp cpu: {}", sensors.read_cpu_temp());
346 println!("temp gpu: {}", sensors.read_gpu_temp());
347 }