Skip to content

Commit f18e3f0

Browse files
authored
Merge pull request #28 from hnez/backlight
backlight: dim the backlight when in screensaver mode
2 parents d398d60 + ca20e8d commit f18e3f0

File tree

6 files changed

+194
-0
lines changed

6 files changed

+194
-0
lines changed

openapi.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,30 @@ paths:
4141
schema:
4242
$ref: '#/components/schemas/Alerts'
4343

44+
/v1/tac/display/backlight/brightness:
45+
get:
46+
summary: Get the current backlight brightness (between 0.0, and 1.0)
47+
tags: [User Interface]
48+
responses:
49+
'200':
50+
content:
51+
application/json:
52+
schema:
53+
type: number
54+
put:
55+
summary: Set the current backlight brightness (between 0.0 and 1.0)
56+
tags: [User Interface]
57+
requestBody:
58+
content:
59+
application/json:
60+
schema:
61+
type: number
62+
responses:
63+
'204':
64+
description: The display brightness was set sucessfully
65+
'400':
66+
description: The value could not be parsed as a number
67+
4468
/v1/tac/display/buttons:
4569
put:
4670
summary: Simulate a button press/release on the device

src/backlight.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// This file is part of tacd, the LXA TAC system daemon
2+
// Copyright (C) 2023 Pengutronix e.K.
3+
//
4+
// This program is free software; you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation; either version 2 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License along
15+
// with this program; if not, write to the Free Software Foundation, Inc.,
16+
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17+
18+
use anyhow::Result;
19+
use async_std::prelude::*;
20+
use async_std::sync::Arc;
21+
use async_std::task::spawn;
22+
use log::warn;
23+
24+
mod demo_mode;
25+
26+
#[cfg(feature = "demo_mode")]
27+
use demo_mode::{Backlight as SysBacklight, Brightness, SysClass};
28+
29+
#[cfg(not(feature = "demo_mode"))]
30+
use sysfs_class::{Backlight as SysBacklight, Brightness, SysClass};
31+
32+
use crate::broker::{BrokerBuilder, Topic};
33+
34+
pub struct Backlight {
35+
pub brightness: Arc<Topic<f32>>,
36+
}
37+
38+
impl Backlight {
39+
pub fn new(bb: &mut BrokerBuilder) -> Result<Self> {
40+
let brightness = bb.topic_rw("/v1/tac/display/backlight/brightness", Some(1.0));
41+
42+
let (mut rx, _) = brightness.clone().subscribe_unbounded();
43+
44+
let backlight = SysBacklight::new("backlight")?;
45+
let max_brightness = backlight.max_brightness()?;
46+
47+
spawn(async move {
48+
while let Some(fraction) = rx.next().await {
49+
let brightness = (max_brightness as f32) * fraction;
50+
let mut brightness = brightness.clamp(0.0, max_brightness as f32) as u64;
51+
52+
// A brightness of 0 turns the backlight off completely.
53+
// If the user selects something low but not zero they likely
54+
// want a dim glow, not completely off.
55+
if fraction > 0.01 && brightness == 0 {
56+
brightness = 1;
57+
}
58+
59+
if let Err(e) = backlight.set_brightness(brightness) {
60+
warn!("Failed to set LED pattern: {}", e);
61+
}
62+
}
63+
});
64+
65+
Ok(Self { brightness })
66+
}
67+
}

src/backlight/demo_mode.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// This file is part of tacd, the LXA TAC system daemon
2+
// Copyright (C) 2023 Pengutronix e.K.
3+
//
4+
// This program is free software; you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation; either version 2 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License along
15+
// with this program; if not, write to the Free Software Foundation, Inc.,
16+
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17+
18+
use std::io::{Error, ErrorKind, Result};
19+
use std::path::{Path, PathBuf};
20+
use std::str::{from_utf8, FromStr};
21+
22+
use sysfs_class::{set_trait_method, trait_method};
23+
24+
pub trait SysClass: Sized {
25+
fn class() -> &'static str;
26+
unsafe fn from_path_unchecked(path: PathBuf) -> Self;
27+
fn path(&self) -> &Path;
28+
29+
fn new(id: &str) -> Result<Self> {
30+
let inst = unsafe { Self::from_path_unchecked(id.into()) };
31+
Ok(inst)
32+
}
33+
34+
fn read_file<P: AsRef<Path>>(&self, name: P) -> Result<String> {
35+
let path = self.path().join(name);
36+
let path = path.to_str().unwrap();
37+
38+
if path == "backlight/max_brightness" {
39+
Ok("8".to_string())
40+
} else {
41+
Err(Error::new(ErrorKind::NotFound, format!("{path} not found")))
42+
}
43+
}
44+
45+
fn parse_file<F: FromStr, P: AsRef<Path>>(&self, name: P) -> Result<F> {
46+
self.read_file(name)?
47+
.parse()
48+
.map_err(|_| Error::new(ErrorKind::InvalidData, "too bad"))
49+
}
50+
51+
fn write_file<P: AsRef<Path>, S: AsRef<[u8]>>(&self, name: P, data: S) -> Result<()> {
52+
let path = self.path().join(name);
53+
let path = path.to_str().unwrap();
54+
let data = from_utf8(data.as_ref()).unwrap();
55+
56+
log::info!("Backlight: Write {} to {}", data, path);
57+
58+
Ok(())
59+
}
60+
}
61+
62+
pub trait Brightness {
63+
fn brightness(&self) -> Result<u64>;
64+
fn max_brightness(&self) -> Result<u64>;
65+
fn set_brightness(&self, val: u64) -> Result<()>;
66+
}
67+
68+
pub struct Backlight {
69+
path: PathBuf,
70+
}
71+
72+
impl SysClass for Backlight {
73+
fn class() -> &'static str {
74+
"backlight"
75+
}
76+
77+
unsafe fn from_path_unchecked(path: PathBuf) -> Self {
78+
Self { path }
79+
}
80+
81+
fn path(&self) -> &Path {
82+
&self.path
83+
}
84+
}
85+
86+
impl Brightness for Backlight {
87+
trait_method!(brightness parse_file u64);
88+
trait_method!(max_brightness parse_file u64);
89+
set_trait_method!("brightness", set_brightness u64);
90+
}

src/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use futures::{select, FutureExt};
1919

2020
mod adc;
21+
mod backlight;
2122
mod broker;
2223
mod dbus;
2324
mod digital_io;
@@ -36,6 +37,7 @@ mod usb_hub;
3637
mod watchdog;
3738

3839
use adc::Adc;
40+
use backlight::Backlight;
3941
use broker::BrokerBuilder;
4042
use dbus::DbusSession;
4143
use digital_io::DigitalIo;
@@ -64,6 +66,7 @@ async fn main() -> Result<(), std::io::Error> {
6466
let mut bb = BrokerBuilder::new();
6567

6668
// Expose hardware on the TAC via the broker framework.
69+
let backlight = Backlight::new(&mut bb).unwrap();
6770
let led = Led::new(&mut bb);
6871
let adc = Adc::new(&mut bb).await.unwrap();
6972
let dut_pwr = DutPwrThread::new(
@@ -117,6 +120,7 @@ async fn main() -> Result<(), std::io::Error> {
117120
let ui = {
118121
let resources = UiResources {
119122
adc,
123+
backlight,
120124
dig_io,
121125
dut_pwr,
122126
iobus,

src/ui.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use screens::{splash, ActivatableScreen, AlertScreen, NormalScreen, Screen};
3939

4040
pub struct UiResources {
4141
pub adc: crate::adc::Adc,
42+
pub backlight: crate::backlight::Backlight,
4243
pub dig_io: crate::digital_io::DigitalIo,
4344
pub dut_pwr: crate::dut_power::DutPwrThread,
4445
pub iobus: crate::iobus::IoBus,

src/ui/screens/screensaver.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ struct Active {
119119
widgets: WidgetContainer,
120120
locator: Arc<Topic<bool>>,
121121
alerts: Arc<Topic<AlertList>>,
122+
brightness: Arc<Topic<f32>>,
122123
}
123124

124125
impl ActivatableScreen for ScreenSaverScreen {
@@ -159,11 +160,16 @@ impl ActivatableScreen for ScreenSaverScreen {
159160

160161
let locator = ui.locator.clone();
161162
let alerts = ui.alerts.clone();
163+
let brightness = ui.res.backlight.brightness.clone();
164+
165+
// Dim to 10% brightness in screensaver mode
166+
brightness.set(0.1);
162167

163168
let active = Active {
164169
widgets,
165170
locator,
166171
alerts,
172+
brightness,
167173
};
168174

169175
Box::new(active)
@@ -177,6 +183,8 @@ impl ActiveScreen for Active {
177183
}
178184

179185
async fn deactivate(mut self: Box<Self>) -> Display {
186+
// Restore full backlight brightness
187+
self.brightness.set(1.0);
180188
self.widgets.destroy().await
181189
}
182190

0 commit comments

Comments
 (0)