Skip to content

Commit

Permalink
Added CH series and MORPHEUS
Browse files Browse the repository at this point in the history
  • Loading branch information
Nortank12 committed Aug 11, 2024
1 parent a59bcc5 commit 1bbed90
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 59 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "deepcool-digital-linux"
version = "0.2.2"
version = "0.3.0"
edition = "2021"

[dependencies]
Expand Down
89 changes: 33 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,100 +10,77 @@ If you think you can collaborate, please write an issue so we can get in touch.
Simply download the latest [release](https://github.com/Nortank12/deepcool-digital-linux/releases)
and run it in the command line. You will need root permission to send data to the device.

I built the binary for `x86_64` architecture and tested it on Arch, Debian, and Gentoo but it should
work on any other Linux distribution.

> [!TIP]
> On AMD's Zen architecture CPUs, you can install the [zenpower3](https://git.exozy.me/a/zenpower3)
> driver, to have a more accurate reading of the CPU die.
## Supported Devices
### CPU Coolers
<table>
<tr>
<th>PID</th>
<th>Model</th>
<th>Added</th>
<th>Tested</th>
<th>Name</th>
<th>Supported</th>
</tr>
<tr>
<td>1</td>
<td>AK400 DIGITAL</td>
<td>AG400 DIGITAL</td>
<td align="center">✅</td>
<td align="center"></td>
</tr>
<tr>
<td>2</td>
<td>AK620 DIGITAL</td>
<td>AG620 DIGITAL</td>
<td align="center">⚠️</td>
</tr>
<tr>
<td>AK400 DIGITAL</td>
<td align="center">✅</td>
<td align="center"></td>
</tr>
<tr>
<td>3</td>
<td>AK500 DIGITAL</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td>4</td>
<td>AK500S DIGITAL</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td>5</td>
<td>CH560 DIGITAL</td>
<td align="center"></td>
<td align="center"></td>
</tr>
<tr>
<td>6</td>
<td>LS720 SE DIGITAL</td>
<td align="center"></td>
<td align="center"></td>
<td>AK620 DIGITAL</td>
<td align="center">✅</td>
</tr>
<tr>
<td>7</td>
<td>??</td>
<td align="center"></td>
<td align="center"></td>
<td>LD240</td>
<td align="center">✅</td>
</tr>
<tr>
<td>8</td>
<td>AG400 DIGITAL</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td>LD360</td>
<td align="center">⚠️</td>
</tr>
</table>

### Cases
<table>
<tr>
<td>9</td>
<td>??</td>
<td align="center"></td>
<td align="center"></td>
<th>Name</th>
<th>Supported</th>
</tr>
<tr>
<td>10</td>
<td>LD240</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td>CH360 DIGITAL</td>
<td align="center">⚠️</td>
</tr>
<tr>
<td>...</td>
<td>...</td>
<td align="center"></td>
<td align="center"></td>
<td>CH560 DIGITAL</td>
<td align="center">⚠️</td>
</tr>
<tr>
<td>21</td>
<td>CH360 DIGITAL</td>
<td align="center"></td>
<td align="center"></td>
<td>MORPHEUS</td>
<td align="center">⚠️</td>
</tr>
</table>

- *If your device is not on the list, you can still run the program and see if it detects it.*

- *If your device is on the list but untested, please try to check all the features to see if they work as expected.*
**✅: Fully supported &nbsp; ⚠️: Not tested**

*In any case, you can create an issue or add a comment to an existing one.*
> [!IMPORTANT]
> - If your device is not on the list, you can still run the program and see if it detects it.
> - If your device is on the list but untested, please try to check all the features to see if they work as expected.
>
> In any case, you can create an issue or add a comment to an existing one.
# Usage
You can run the program with or without providing any options.
Expand Down
115 changes: 115 additions & 0 deletions src/devices/ch_series.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use crate::monitor::{cpu, gpu::nvidia::Gpu as NvGpu};
use hidapi::HidApi;
use std::{thread::sleep, time::Duration};

const VENDOR: u16 = 0x3633;
const POLLING_RATE: u64 = 750;

pub struct Display {
product_id: u16,
fahrenheit: bool,
nvidia_gpu: Option<NvGpu>,
}

impl Display {
pub fn new(product_id: u16, fahrenheit: bool, gpu: &str) -> Self {
let nv_gpu = if gpu == "nvidia" { Some(NvGpu::new()) } else { None };

Display {
product_id,
fahrenheit,
nvidia_gpu: nv_gpu,
}
}

pub fn run(&self, api: &HidApi, mode: &str, cpu_temp_sensor: &str) {
// Connect to device
let device = api.open(VENDOR, self.product_id).expect("Failed to open HID device");

// Data packet
let mut data: [u8; 64] = [0; 64];
data[0] = 16;

// Init sequence
{
let mut init_data = data.clone();
init_data[1] = 170;
device.write(&init_data).expect("Failed to write data");
}

// Display loop
if mode == "auto" {
loop {
for _ in 0..8 {
device
.write(&self.status_message(&data, "temp", &cpu_temp_sensor))
.expect("Failed to write data");
}
for _ in 0..8 {
device
.write(&self.status_message(&data, "usage", &cpu_temp_sensor))
.expect("Failed to write data");
}
}
} else {
loop {
device
.write(&self.status_message(&data, &mode, &cpu_temp_sensor))
.expect("Failed to write data");
}
}
}

/// Reads the CPU status information and returns the data packet.
fn status_message(&self, inital_data: &[u8; 64], mode: &str, cpu_temp_sensor: &str) -> [u8; 64] {
// Clone the data packet
let mut data = inital_data.clone();

// Read CPU utilization
let cpu_instant = cpu::read_instant();

// Wait
sleep(Duration::from_millis(POLLING_RATE));

// Calculate CPU & GPU usage
let cpu_usage = cpu::get_usage(cpu_instant);
let gpu_usage = self.nvidia_gpu.as_ref().unwrap().get_usage();

// Main display
match mode {
"temp" => {
let unit = if self.fahrenheit { 35 } else { 19 };
let cpu_temp = cpu::get_temp(cpu_temp_sensor, self.fahrenheit);
let gpu_temp = self.nvidia_gpu.as_ref().unwrap().get_temp(self.fahrenheit);
// CPU
data[1] = unit;
data[3] = cpu_temp / 100;
data[4] = cpu_temp % 100 / 10;
data[5] = cpu_temp % 10;
// GPU
data[6] = unit;
data[8] = gpu_temp / 100;
data[9] = gpu_temp % 100 / 10;
data[10] = gpu_temp % 10;
}
"usage" => {
// CPU
data[1] = 76;
data[3] = cpu_usage / 100;
data[4] = cpu_usage % 100 / 10;
data[5] = cpu_usage % 10;
// GPU
data[6] = 76;
data[8] = gpu_usage / 100;
data[9] = gpu_usage % 100 / 10;
data[10] = gpu_usage % 10;
}
_ => (),
}
// Status bar
data[2] = if cpu_usage < 20 { 1 } else { (cpu_usage as f32 / 10 as f32).round() as u8 };
data[7] = if gpu_usage < 20 { 1 } else { (gpu_usage as f32 / 10 as f32).round() as u8 };

data
}
}
1 change: 1 addition & 0 deletions src/devices/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod ag_series;
pub mod ak_series;
pub mod ch_series;
pub mod ld_series;
23 changes: 21 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ fn main() {

// Connect to device and send datastream
match product_id {
// AK Series
1..=4 => {
// Write info
println!("DISP. MODE: {}", args.mode);
Expand All @@ -70,13 +71,14 @@ fn main() {
}
println!("ALARM: {}", if args.alarm { "on" } else { "off" });
println!("-----");
println!("Update interval: 750ms");
println!("Update interval: 750 ms");
println!("\nPress Ctrl + C to terminate");

// Display loop
let ak_device = devices::ak_series::Display::new(product_id, args.fahrenheit, args.alarm);
ak_device.run(&api, &args.mode, &cpu_hwmon_path);
}
// AG Series
8 => {
// Write info
println!("DISP. MODE: {}", args.mode);
Expand All @@ -85,13 +87,14 @@ fn main() {
}
println!("ALARM: {}", if args.alarm { "on" } else { "off" });
println!("-----");
println!("Update interval: 750ms");
println!("Update interval: 750 ms");
println!("\nPress Ctrl + C to terminate");

// Display loop
let ag_device = devices::ag_series::Display::new(product_id, args.alarm);
ag_device.run(&api, &args.mode, &cpu_hwmon_path);
}
// LD Series
10 => {
// Write info
println!("DISP. MODE: not supported");
Expand All @@ -107,6 +110,22 @@ fn main() {
let ld_device = devices::ld_series::Display::new(product_id, args.fahrenheit);
ld_device.run(&api, &cpu_hwmon_path);
}
// CH Series & MORPHEUS
5 | 7 | 21 => {
// Write info
println!("DISP. MODE: {}", args.mode);
if args.mode != "usage" {
println!("TEMP. UNIT: {}", if args.fahrenheit { "˚F" } else { "˚C" });
}
println!("ALARM: not supported");
println!("-----");
println!("Update interval: 750 ms");
println!("\nPress Ctrl + C to terminate");

// Display loop
let ch_device = devices::ch_series::Display::new(product_id, args.fahrenheit, "nvidia");
ch_device.run(&api, &args.mode, &cpu_hwmon_path);
}
_ => {
println!("Device not yet supported!");
println!("\nPlease create an issue on GitHub providing your device name and the following information:");
Expand Down

0 comments on commit 1bbed90

Please sign in to comment.