Skip to content

Commit 5c843ea

Browse files
Merge pull request #84 from FrameworkComputer/rgbkbd
Add support for RGB command
2 parents 6590d5b + 0424c81 commit 5c843ea

File tree

9 files changed

+146
-9
lines changed

9 files changed

+146
-9
lines changed

Cargo.lock

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

framework_lib/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ cross_freebsd = ["unix", "freebsd_pio"]
1818
# Windows does not have the cros_ec driver nor raw port I/O access to userspace
1919
windows = ["std", "smbios", "dep:windows", "win_driver", "raw_pio", "hidapi", "rusb", "dep:wmi"]
2020
smbios = ["dep:smbios-lib"]
21-
std = ["dep:clap", "dep:clap-verbosity-flag", "dep:env_logger", "smbios-lib?/std"]
21+
std = ["dep:clap", "dep:clap-num", "dep:clap-verbosity-flag", "dep:env_logger", "smbios-lib?/std"]
2222
rusb = ["dep:rusb"]
2323
hidapi = ["dep:hidapi"]
2424
uefi = [
@@ -51,6 +51,7 @@ regex = { version = "1.11.1", default-features = false }
5151
redox_hwio = { git = "https://github.com/FrameworkComputer/rust-hwio", branch = "freebsd", default-features = false }
5252
libc = { version = "0.2.155", optional = true }
5353
clap = { version = "4.5", features = ["derive"], optional = true }
54+
clap-num = { version = "1.2.0", optional = true }
5455
clap-verbosity-flag = { version = "2.2.1", optional = true }
5556
nix = { version = "0.29.0", features = ["ioctl", "user"], optional = true }
5657
num = { version = "0.4", default-features = false }

framework_lib/src/chromium_ec/command.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,20 @@ pub enum EcCommands {
3434
PwmSetDuty = 0x0025,
3535
PwmGetDuty = 0x0026,
3636
SetTabletMode = 0x0031,
37-
GpioGet = 0x93,
38-
I2cPassthrough = 0x9e,
39-
ConsoleSnapshot = 0x97,
40-
ConsoleRead = 0x98,
37+
GpioGet = 0x0093,
38+
I2cPassthrough = 0x009e,
39+
ConsoleSnapshot = 0x0097,
40+
ConsoleRead = 0x0098,
4141
/// List the features supported by the firmware
42-
GetFeatures = 0x0D,
42+
GetFeatures = 0x000D,
4343
/// Force reboot, causes host reboot as well
44-
Reboot = 0xD1,
44+
Reboot = 0x00D1,
4545
/// Control EC boot
46-
RebootEc = 0xD2,
46+
RebootEc = 0x00D2,
4747
/// Get information about PD controller power
48-
UsbPdPowerInfo = 0x103,
48+
UsbPdPowerInfo = 0x0103,
49+
RgbKbdSetColor = 0x013A,
50+
RgbKbd = 0x013B,
4951

5052
// Framework specific commands
5153
/// Configure the behavior of the flash notify

framework_lib/src/chromium_ec/commands.rs

+31
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,37 @@ impl EcRequest<EcResponseUsbPdPowerInfo> for EcRequestUsbPdPowerInfo {
518518
}
519519
}
520520

521+
// TODO: Actually 128, but if we go above ~80 EC returns REQUEST_TRUNCATED
522+
// At least when I use the portio driver
523+
pub const EC_RGBKBD_MAX_KEY_COUNT: usize = 64;
524+
525+
#[repr(C, packed)]
526+
#[derive(Default, Clone, Copy, Debug)]
527+
pub struct RgbS {
528+
pub r: u8,
529+
pub g: u8,
530+
pub b: u8,
531+
}
532+
533+
#[repr(C, packed)]
534+
pub struct EcRequestRgbKbdSetColor {
535+
/// Specifies the starting key ID whose color is being changed
536+
pub start_key: u8,
537+
/// Specifies # of elements in color
538+
pub length: u8,
539+
/// RGB color data array of length up to MAX_KEY_COUNT
540+
pub color: [RgbS; EC_RGBKBD_MAX_KEY_COUNT],
541+
}
542+
543+
#[repr(C, packed)]
544+
pub struct EcResponseRgbKbdSetColor {}
545+
546+
impl EcRequest<EcResponseRgbKbdSetColor> for EcRequestRgbKbdSetColor {
547+
fn command_id() -> EcCommands {
548+
EcCommands::RgbKbdSetColor
549+
}
550+
}
551+
521552
// --- Framework Specific commands ---
522553

523554
#[repr(C, packed)]

framework_lib/src/chromium_ec/mod.rs

+17
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,23 @@ impl CrosEc {
921921
let res = request.send_command(self)?;
922922
Ok(res.val == 1)
923923
}
924+
925+
pub fn rgbkbd_set_color(&self, start_key: u8, colors: Vec<RgbS>) -> EcResult<()> {
926+
for (chunk, colors) in colors.chunks(EC_RGBKBD_MAX_KEY_COUNT).enumerate() {
927+
let mut request = EcRequestRgbKbdSetColor {
928+
start_key: start_key + ((chunk * EC_RGBKBD_MAX_KEY_COUNT) as u8),
929+
length: colors.len() as u8,
930+
color: [(); EC_RGBKBD_MAX_KEY_COUNT].map(|()| Default::default()),
931+
};
932+
933+
for (i, color) in colors.iter().enumerate() {
934+
request.color[i] = *color;
935+
}
936+
937+
let _res = request.send_command(self)?;
938+
}
939+
Ok(())
940+
}
924941
}
925942

926943
#[cfg_attr(not(feature = "uefi"), derive(clap::ValueEnum))]

framework_lib/src/commandline/clap_std.rs

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! This way we can use it in the regular OS commandline tool on Linux and Windows,
33
//! as well as on the UEFI shell tool.
44
use clap::Parser;
5+
use clap_num::maybe_hex;
56

67
use crate::chromium_ec::CrosEcDriverType;
78
use crate::commandline::{
@@ -149,6 +150,13 @@ struct ClapCli {
149150
#[arg(long)]
150151
kblight: Option<Option<u8>>,
151152

153+
/// Set the color of <key> to <RGB>. Multiple colors for adjacent keys can be set at once.
154+
/// <key> <RGB> [<RGB> ...]
155+
/// Example: 0 0xFF000 0x00FF00 0x0000FF
156+
#[clap(num_args = 2..)]
157+
#[arg(long, value_parser=maybe_hex::<u64>)]
158+
rgbkbd: Vec<u64>,
159+
152160
/// Set tablet mode override
153161
#[clap(value_enum)]
154162
#[arg(long)]
@@ -274,6 +282,7 @@ pub fn parse(args: &[String]) -> Cli {
274282
fp_led_level: args.fp_led_level,
275283
fp_brightness: args.fp_brightness,
276284
kblight: args.kblight,
285+
rgbkbd: args.rgbkbd,
277286
tablet_mode: args.tablet_mode,
278287
console: args.console,
279288
reboot_ec: args.reboot_ec,

framework_lib/src/commandline/mod.rs

+17
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use crate::chromium_ec;
3535
use crate::chromium_ec::commands::DeckStateMode;
3636
use crate::chromium_ec::commands::FpLedBrightnessLevel;
3737
use crate::chromium_ec::commands::RebootEcCmd;
38+
use crate::chromium_ec::commands::RgbS;
3839
use crate::chromium_ec::commands::TabletModeOverride;
3940
use crate::chromium_ec::EcResponseStatus;
4041
use crate::chromium_ec::{print_err, EcFlashType};
@@ -166,6 +167,7 @@ pub struct Cli {
166167
pub fp_led_level: Option<Option<FpBrightnessArg>>,
167168
pub fp_brightness: Option<Option<u8>>,
168169
pub kblight: Option<Option<u8>>,
170+
pub rgbkbd: Vec<u64>,
169171
pub tablet_mode: Option<TabletModeArg>,
170172
pub console: Option<ConsoleArg>,
171173
pub reboot_ec: Option<RebootEcArg>,
@@ -753,6 +755,21 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
753755
} else if let Some(Some(kblight)) = args.kblight {
754756
assert!(kblight <= 100);
755757
ec.set_keyboard_backlight(kblight);
758+
} else if !args.rgbkbd.is_empty() {
759+
if args.rgbkbd.len() < 2 {
760+
println!(
761+
"Must provide at least 2 arguments. Provided only: {}",
762+
args.rgbkbd.len()
763+
);
764+
} else {
765+
let start_key = args.rgbkbd[0] as u8;
766+
let colors = args.rgbkbd[1..].iter().map(|color| RgbS {
767+
r: ((color & 0x00FF0000) >> 16) as u8,
768+
g: ((color & 0x0000FF00) >> 8) as u8,
769+
b: (color & 0x000000FF) as u8,
770+
});
771+
ec.rgbkbd_set_color(start_key, colors.collect()).unwrap();
772+
}
756773
} else if let Some(None) = args.kblight {
757774
print!("Keyboard backlight: ");
758775
if let Some(percentage) = print_err(ec.get_keyboard_backlight()) {

framework_lib/src/commandline/uefi.rs

+13
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ pub fn parse(args: &[String]) -> Cli {
8787
fp_led_level: None,
8888
fp_brightness: None,
8989
kblight: None,
90+
rgbkbd: vec![],
9091
tablet_mode: None,
9192
console: None,
9293
reboot_ec: None,
@@ -216,6 +217,18 @@ pub fn parse(args: &[String]) -> Cli {
216217
Some(None)
217218
};
218219
found_an_option = true;
220+
} else if arg == "--rgbkbd" {
221+
cli.rgbkbd = if args.len() > i + 2 {
222+
let mut colors = Vec::<u64>::new();
223+
for color_i in i + 1..args.len() {
224+
// TODO: Fail parsing instead of unwrap()
225+
colors.push(args[color_i].parse::<u64>().unwrap());
226+
}
227+
colors
228+
} else {
229+
println!("--rgbkbd requires at least 2 arguments, the start key and an RGB value");
230+
vec![]
231+
}
219232
} else if arg == "--tablet-mode" {
220233
cli.tablet_mode = if args.len() > i + 1 {
221234
let tablet_mode_arg = &args[i + 1];

rgbkbd.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/usr/bin/env python3
2+
# Example invocation in fish shell
3+
# cargo build && sudo ./target/debug/framework_tool \
4+
# --driver portio --has-mec false --pd-ports 1 1 --pd-addrs 64 64 \
5+
# (./rgbkbd.py | string split ' ')
6+
7+
BRIGHTNESS = 1
8+
RED = int(0xFF * BRIGHTNESS) << 16
9+
GREEN = int(0xFF * BRIGHTNESS) << 8
10+
BLUE = int(0xFF * BRIGHTNESS)
11+
CYAN = GREEN + BLUE
12+
YELLOW = RED + GREEN
13+
PURPLE = BLUE + RED
14+
WHITE = RED + GREEN + BLUE
15+
16+
grid_4x4 = [
17+
[ YELLOW, RED, RED, RED, YELLOW ],
18+
[ RED, WHITE, GREEN, WHITE, RED ],
19+
[ RED, GREEN, BLUE, GREEN, RED ],
20+
[ RED, WHITE, GREEN, WHITE, RED ],
21+
[ YELLOW, RED, RED, RED, YELLOW ],
22+
]
23+
24+
fan_8leds = [[
25+
# WHITE, CYAN, BLUE, GREEN, PURPLE, RED, YELLOW, WHITE
26+
RED, RED, RED, RED,
27+
GREEN, GREEN, GREEN, GREEN
28+
]]
29+
30+
# colors = grid_4x4
31+
colors = fan_8leds
32+
33+
print('--rgbkbd 0', end='')
34+
for row in colors:
35+
for col in row:
36+
print(' ', end='')
37+
print(col, end='')

0 commit comments

Comments
 (0)