2 extern crate windows_service
;
9 atomic
::{AtomicBool
, Ordering
},
13 time
::{self, Duration
},
17 use log
::{error
, info
, trace
, warn
, debug
};
18 use windows
::Win32
::Foundation
::{ERROR_SERVICE_DOES_NOT_EXIST
, WIN32_ERROR
};
19 use windows_service
::{
21 ServiceAccess
, ServiceControl
, ServiceControlAccept
, ServiceErrorControl
, ServiceExitCode
,
22 ServiceInfo
, ServiceStartType
, ServiceState
, ServiceStatus
, ServiceType
,
24 service_control_handler
::{self, ServiceControlHandlerResult
, ServiceStatusHandle
},
26 service_manager
::{ServiceManager
, ServiceManagerAccess
},
28 use wmi
::{COMLibrary
, Variant
, WMIConnection
};
32 define_windows_service!(ffi_service_main
, service_main
);
35 #![allow(warnings, unused)]
36 include!(concat!(env!("OUT_DIR"), "/ols_api.rs"));
40 #![allow(warnings, unused)]
41 include!(concat!(env!("OUT_DIR"), "/intel_arc.rs"));
50 mod corsair_vengeance
;
53 // mod roccat; Disabled.
58 fn main() -> Result
<()> {
59 let is_debug
= cfg!(debug_assertions
);
61 flexi_logger
::Logger
::try_with_str(if is_debug
{ "debug" } else { "info" })?
63 flexi_logger
::FileSpec
::default()
64 .directory(dirs
::config_dir().unwrap().join(consts
::SERVICE_NAME
))
65 .basename(consts
::SERVICE_NAME
),
67 .duplicate_to_stdout(flexi_logger
::Duplicate
::All
)
68 .format(if is_debug
{ flexi_logger
::default_format
} else { flexi_logger
::detailed_format
})
70 flexi_logger
::Criterion
::Size(1024 * 1024),
71 flexi_logger
::Naming
::Timestamps
,
72 flexi_logger
::Cleanup
::KeepLogFiles(10),
77 let args
: Vec
<String
> = env
::args().collect();
79 info!("Temperature to RGB");
81 if args
.contains(&"--no-service".to_string()) {
82 let completed
: Arc
<AtomicBool
> = Arc
::new(AtomicBool
::new(false));
83 main_loop
::main_loop(completed
.clone());
84 } else if args
.contains(&"--tests".to_string()) {
86 } else if args
.contains(&"--install-service".to_string()) {
87 println!("Installing service...");
89 } else if args
.contains(&"--uninstall-service".to_string()) {
90 println!("Uninstalling service...");
93 service_dispatcher
::start(consts
::SERVICE_NAME
, ffi_service_main
)?
;
99 fn install_service() -> windows_service
::Result
<()> {
100 let manager_access
= ServiceManagerAccess
::CONNECT
| ServiceManagerAccess
::CREATE_SERVICE
;
101 let service_manager
= ServiceManager
::local_computer(None
::<&str>, manager_access
)?
;
103 let service_binary_path
= std
::env
::current_exe()
105 .with_file_name("temp_2_rgb.exe");
107 println!("Installing service: {service_binary_path:?}");
109 let service_info
= ServiceInfo
{
110 name
: OsString
::from(consts
::SERVICE_NAME
),
111 display_name
: OsString
::from(consts
::SERVICE_NAME
),
112 service_type
: ServiceType
::OWN_PROCESS
,
113 start_type
: ServiceStartType
::AutoStart
,
114 error_control
: ServiceErrorControl
::Normal
,
115 executable_path
: service_binary_path
,
116 launch_arguments
: vec
![],
117 dependencies
: vec
![],
118 account_name
: None
, // run as System
119 account_password
: None
,
121 let service
= service_manager
.create_service(&service_info
, ServiceAccess
::CHANGE_CONFIG
)?
;
122 service
.set_description(
123 "A service to set the color of hardware according to the temperature of GPU and CPU",
128 fn uninstall_service() -> windows_service
::Result
<()> {
129 let manager_access
= ServiceManagerAccess
::CONNECT
;
130 let service_manager
= ServiceManager
::local_computer(None
::<&str>, manager_access
)?
;
132 let service_access
= ServiceAccess
::QUERY_STATUS
| ServiceAccess
::STOP
| ServiceAccess
::DELETE
;
133 let service
= service_manager
.open_service(consts
::SERVICE_NAME
, service_access
)?
;
135 // The service will be marked for deletion as long as this function call succeeds.
136 // However, it will not be deleted from the database until it is stopped and all open handles to it are closed.
139 // Our handle to it is not closed yet. So we can still query it.
140 if service
.query_status()?
.current_state
!= ServiceState
::Stopped
{
141 // If the service cannot be stopped, it will be deleted when the system restarts.
145 // Explicitly close our open handle to the service. This is automatically called when `service` goes out of scope.
148 // Win32 API does not give us a way to wait for service deletion.
149 // To check if the service is deleted from the database, we have to poll it ourselves.
150 let start
= time
::Instant
::now();
151 let timeout
= Duration
::from_secs(5);
152 while start
.elapsed() < timeout
{
153 if let Err(windows_service
::Error
::Winapi(e
)) =
154 service_manager
.open_service(consts
::SERVICE_NAME
, ServiceAccess
::QUERY_STATUS
)
156 let WIN32_ERROR(error_num
) = ERROR_SERVICE_DOES_NOT_EXIST
;
157 if e
.raw_os_error() == Some(error_num
as i32) {
158 println!("{} is deleted.", consts
::SERVICE_NAME
);
162 sleep(Duration
::from_secs(1));
164 println!("{} is marked for deletion.", consts
::SERVICE_NAME
);
169 fn service_main(arguments
: Vec
<OsString
>) {
170 if let Err(error
) = run_service(arguments
) {
171 println!("Error: {error}");
175 fn run_service(_arguments
: Vec
<OsString
>) -> Result
<(), windows_service
::Error
> {
176 let completed
: Arc
<AtomicBool
> = Arc
::new(AtomicBool
::new(false));
178 let completed_event_handler
= Arc
::clone(&completed
);
179 let event_handler
= move |control_event
| -> ServiceControlHandlerResult
{
180 match control_event
{
181 ServiceControl
::Stop
=> {
182 completed_event_handler
.store(true, Ordering
::Relaxed
);
183 // Handle stop event and return control back to the system.
184 ServiceControlHandlerResult
::NoError
186 ServiceControl
::Shutdown
=> {
187 completed_event_handler
.store(true, Ordering
::Relaxed
);
188 // Handle stop event and return control back to the system.
189 ServiceControlHandlerResult
::NoError
191 // ServiceControl::Preshutdown => {
192 // completed_event_handler.store(true, Ordering::Relaxed);
193 // ServiceControlHandlerResult::NoError
195 // ServiceControl::PowerEvent(param) => {
196 // ServiceControlHandlerResult::NotImplemented
198 // All services must accept Interrogate even if it's a no-op.
199 ServiceControl
::Interrogate
=> ServiceControlHandlerResult
::NoError
,
200 _
=> ServiceControlHandlerResult
::NotImplemented
,
204 // Register system service event handler
205 let status_handle
= service_control_handler
::register(consts
::SERVICE_NAME
, event_handler
)?
;
207 let running_status
= ServiceStatus
{
208 // Should match the one from system service registry
209 service_type
: ServiceType
::OWN_PROCESS
,
212 current_state
: ServiceState
::Running
,
214 // Accept stop events when running
215 controls_accepted
: ServiceControlAccept
::STOP
| ServiceControlAccept
::SHUTDOWN
,
217 // Used to report an error when starting or stopping only, otherwise must be zero
218 exit_code
: ServiceExitCode
::Win32(0),
220 // Only used for pending states, otherwise must be zero
223 // Only used for pending states, otherwise must be zero
224 wait_hint
: Duration
::default(),
229 status_handle
.set_service_status(running_status
)?
;
231 main_loop
::main_loop(completed
.clone());
233 status_handle
.set_service_status(ServiceStatus
{
234 service_type
: ServiceType
::OWN_PROCESS
,
235 current_state
: ServiceState
::Stopped
,
236 controls_accepted
: ServiceControlAccept
::empty(),
237 exit_code
: ServiceExitCode
::Win32(0),
239 wait_hint
: Duration
::default(),
243 info!("Main loop stopped: Temperature to RGB will now shut down");
249 println!("Running some tests...");
252 // list_usb_devices();
259 println!("Press any key to continue...");
260 std
::io
::stdin().read_line(&mut String
::new()).unwrap();
264 let com_con
= COMLibrary
::new().unwrap();
265 let wmi_con
= WMIConnection
::new(com_con
.into()).unwrap();
267 //let results: Vec<HashMap<String, Variant>> = wmi_con.raw_query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE '%SMBUS%' OR Description LIKE '%SM BUS%'").unwrap();
268 //let results: Vec<HashMap<String, Variant>> = wmi_con.raw_query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE 'Intel(R) NF I2C Host Controller'").unwrap();
269 let results
: Vec
<HashMap
<String
, Variant
>> = wmi_con
270 .raw_query("SELECT * FROM Win32_PnPSignedDriver")
272 //let results: Vec<HashMap<String, Variant>> = wmi_con.raw_query("SELECT * FROM Win32_PnPAllocatedResource").unwrap();
275 println!("-------------------");
276 println!("{:#?}", os
);
279 fn list_usb_devices() {
280 let api
= hidapi
::HidApi
::new().unwrap();
281 for device
in api
.device_list() {
282 println!("{:?}", device
);
283 println!("name: {}", device
.product_string().unwrap());
284 println!("interface number: {}", device
.interface_number());
285 println!("page: {}", device
.usage_page());
286 println!("usage: {}", device
.usage());
291 // fn test_roccat() {
292 // let api = hidapi::HidApi::new().unwrap();
293 // let roccat_device = roccat::get_device(&api);
295 // let manufacturer = roccat_device.get_manufacturer_string().unwrap();
296 // dbg!(manufacturer);
298 // let product = roccat_device.get_product_string().unwrap();
301 // let serial = roccat_device.get_serial_number_string().unwrap();
304 // roccat::init(&roccat_device);
305 // roccat::set_color(
316 let api
= hidapi
::HidApi
::new().unwrap();
318 let b650e_device
= b650_e
::get_device(&api
);
320 println!("Firmware: {}", b650_e
::get_firmware_string(&b650e_device
));
322 let configuration
= b650_e
::get_configuration_table(&b650e_device
);
323 println!("Configuration:");
325 print!("{:02X} ", configuration
[i
]);
326 if (i
+ 1) % 6 == 0 {
331 // Only once, at start.
332 b650_e
::set_fixed_mode(&b650e_device
);
342 b650_e
::save_current_color(&b650e_device
);
346 let corsair_controllers
= [
347 corsair_vengeance
::Controller
::new(0x19),
348 corsair_vengeance
::Controller
::new(0x1B),
350 for controller
in corsair_controllers
{
351 controller
.set_color(&RGB
{
360 // a770::set_rgb(255, 0, 0);
361 let mut a770
= a770
::A770
::new();
362 a770
.set_color(255, 0, 0);
365 fn test_read_temp() {
366 let sensors
= sensors_jiji
::Sensors
::new();
367 println!("temp cpu: {}", sensors
.read_cpu_temp());
368 println!("temp gpu: {}", sensors
.read_gpu_temp());