mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-14 03:30:02 +00:00
feat(core): added user adjustable brightness setting
This commit is contained in:
parent
6b31b8eec3
commit
6e6638773b
@ -181,6 +181,7 @@ message ApplySettings {
|
||||
optional SafetyCheckLevel safety_checks = 9; // Safety check level, set to Prompt to limit path namespace enforcement
|
||||
optional bool experimental_features = 10; // enable experimental message types
|
||||
optional bool hide_passphrase_from_host = 11; // do not show passphrase coming from host
|
||||
optional uint32 brightness = 12; // display brightness, 0 = select on device
|
||||
}
|
||||
|
||||
/**
|
||||
|
1
core/.changelog.d/3208.added
Normal file
1
core/.changelog.d/3208.added
Normal file
@ -0,0 +1 @@
|
||||
[T2T1] Added user adjustable brightness setting.
|
@ -148,10 +148,14 @@ int main(void) {
|
||||
dma2d_init();
|
||||
#endif
|
||||
|
||||
#if defined TREZOR_MODEL_T
|
||||
set_core_clock(CLOCK_180_MHZ);
|
||||
#endif
|
||||
|
||||
display_reinit();
|
||||
|
||||
#ifdef STM32U5
|
||||
check_oem_keys();
|
||||
//check_oem_keys();
|
||||
#endif
|
||||
|
||||
screen_boot_stage_2();
|
||||
|
@ -131,6 +131,7 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_buttons__try_again;
|
||||
MP_QSTR_buttons__turn_off;
|
||||
MP_QSTR_buttons__turn_on;
|
||||
MP_QSTR_callback;
|
||||
MP_QSTR_can_go_back;
|
||||
MP_QSTR_cancel_arrow;
|
||||
MP_QSTR_cancel_cross;
|
||||
@ -382,6 +383,7 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_request_bip39;
|
||||
MP_QSTR_request_complete_repaint;
|
||||
MP_QSTR_request_number;
|
||||
MP_QSTR_request_number_slider;
|
||||
MP_QSTR_request_passphrase;
|
||||
MP_QSTR_request_pin;
|
||||
MP_QSTR_request_slip39;
|
||||
|
@ -36,6 +36,7 @@ const INITIALIZED: u16 = FLAG_PUBLIC | APP_DEVICE | 0x0013;
|
||||
const SAFETY_CHECK_LEVEL: u16 = APP_DEVICE | 0x0014;
|
||||
const EXPERIMENTAL_FEATURES: u16 = APP_DEVICE | 0x0015;
|
||||
const HIDE_PASSPHRASE_FROM_HOST: u16 = APP_DEVICE | 0x0016;
|
||||
const BRIGHTNESS: u16 = FLAG_PUBLIC | APP_DEVICE | 0x0017;
|
||||
|
||||
pub fn get_avatar_len() -> StorageResult<usize> {
|
||||
get_length(HOMESCREEN)
|
||||
@ -47,3 +48,12 @@ pub fn load_avatar(dest: &mut [u8]) -> StorageResult<()> {
|
||||
ensure!(dest_len == result.len(), "Internal error in load_avatar");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_brightness() -> StorageResult<u8> {
|
||||
let mut dest: [u8; 1] = [0; 1];
|
||||
let res = get(BRIGHTNESS, &mut dest);
|
||||
match res {
|
||||
Ok(_) => Ok(dest[0]),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
41
core/embed/rust/src/ui/model_mercury/theme/backlight.rs
Normal file
41
core/embed/rust/src/ui/model_mercury/theme/backlight.rs
Normal file
@ -0,0 +1,41 @@
|
||||
#[cfg(not(feature = "bootloader"))]
|
||||
use crate::storage;
|
||||
|
||||
// Typical backlight values.
|
||||
|
||||
#[cfg(feature = "bootloader")]
|
||||
pub fn get_backlight_normal() -> u16 {
|
||||
150
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "bootloader"))]
|
||||
pub fn get_backlight_normal() -> u16 {
|
||||
storage::get_brightness().unwrap_or(150).into()
|
||||
}
|
||||
|
||||
#[cfg(feature = "bootloader")]
|
||||
pub fn get_backlight_low() -> u16 {
|
||||
150
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "bootloader"))]
|
||||
pub fn get_backlight_low() -> u16 {
|
||||
let val = storage::get_brightness();
|
||||
return if val.is_ok() && val.unwrap() < 45 {
|
||||
val.unwrap().into()
|
||||
} else {
|
||||
45
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_backlight_dim() -> u16 {
|
||||
5
|
||||
}
|
||||
|
||||
pub fn get_backlight_none() -> u16 {
|
||||
2
|
||||
}
|
||||
|
||||
pub fn get_backlight_max() -> u16 {
|
||||
255
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
pub mod bootloader;
|
||||
|
||||
pub mod backlight;
|
||||
|
||||
use crate::ui::{
|
||||
component::text::{LineBreaking, PageBreaking, TextStyle},
|
||||
display::{Color, Font, Icon},
|
||||
@ -8,10 +10,6 @@ use crate::ui::{
|
||||
|
||||
use super::component::{ButtonStyle, ButtonStyleSheet, LoaderStyle, LoaderStyleSheet};
|
||||
|
||||
// Typical backlight values.
|
||||
pub const BACKLIGHT_NORMAL: u16 = 150;
|
||||
pub const BACKLIGHT_DIM: u16 = 5;
|
||||
|
||||
// Color palette.
|
||||
pub const WHITE: Color = Color::rgb(0xFF, 0xFF, 0xFF);
|
||||
pub const BLACK: Color = Color::rgb(0, 0, 0);
|
||||
|
@ -16,6 +16,7 @@ use super::{
|
||||
bl_confirm::{Confirm, ConfirmTitle},
|
||||
Button, ResultScreen, WelcomeScreen,
|
||||
},
|
||||
theme,
|
||||
theme::{
|
||||
bootloader::{
|
||||
button_bld, button_bld_menu, button_confirm, button_wipe_cancel, button_wipe_confirm,
|
||||
@ -23,7 +24,7 @@ use super::{
|
||||
FIRE40, RESULT_FW_INSTALL, RESULT_INITIAL, RESULT_WIPE, TEXT_BOLD, TEXT_NORMAL,
|
||||
TEXT_WIPE_BOLD, TEXT_WIPE_NORMAL, WARNING40, WELCOME_COLOR, X24,
|
||||
},
|
||||
BACKLIGHT_NORMAL, BLACK, FG, WHITE,
|
||||
BLACK, FG, WHITE,
|
||||
},
|
||||
ModelTTFeatures,
|
||||
};
|
||||
@ -258,7 +259,7 @@ impl UIFeaturesBootloader for ModelTTFeatures {
|
||||
if fading {
|
||||
Self::fadein();
|
||||
} else {
|
||||
display::set_backlight(BACKLIGHT_NORMAL);
|
||||
display::set_backlight(theme::backlight::get_backlight_normal());
|
||||
}
|
||||
display::refresh();
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ where
|
||||
|
||||
if self.fade.take() {
|
||||
// Note that this is blocking and takes some time.
|
||||
display::fade_backlight(theme::BACKLIGHT_NORMAL);
|
||||
display::fade_backlight(theme::backlight::get_backlight_normal());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,7 +295,7 @@ impl Component for PassphraseKeyboard {
|
||||
}
|
||||
if self.fade.take() {
|
||||
// Note that this is blocking and takes some time.
|
||||
display::fade_backlight(theme::BACKLIGHT_NORMAL);
|
||||
display::fade_backlight(theme::backlight::get_backlight_normal());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ mod keyboard;
|
||||
mod loader;
|
||||
#[cfg(feature = "translations")]
|
||||
mod number_input;
|
||||
mod number_input_slider;
|
||||
#[cfg(feature = "translations")]
|
||||
mod page;
|
||||
mod progress;
|
||||
@ -50,6 +51,7 @@ pub use keyboard::{
|
||||
pub use loader::{Loader, LoaderMsg, LoaderStyle, LoaderStyleSheet};
|
||||
#[cfg(feature = "translations")]
|
||||
pub use number_input::{NumberInputDialog, NumberInputDialogMsg};
|
||||
pub use number_input_slider::{NumberInputSliderDialog, NumberInputSliderDialogMsg};
|
||||
#[cfg(feature = "translations")]
|
||||
pub use page::ButtonPage;
|
||||
pub use progress::Progress;
|
||||
|
202
core/embed/rust/src/ui/model_tt/component/number_input_slider.rs
Normal file
202
core/embed/rust/src/ui/model_tt/component/number_input_slider.rs
Normal file
@ -0,0 +1,202 @@
|
||||
use crate::ui::{
|
||||
component::{base::ComponentExt, Child, Component, Event, EventCtx},
|
||||
constant::screen,
|
||||
display,
|
||||
event::TouchEvent,
|
||||
geometry::{Grid, Insets, Point, Rect},
|
||||
};
|
||||
|
||||
use super::{theme, Button, ButtonMsg};
|
||||
|
||||
pub enum NumberInputSliderDialogMsg {
|
||||
Confirmed,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
pub struct NumberInputSliderDialog<F>
|
||||
where
|
||||
F: Fn(u32),
|
||||
{
|
||||
area: Rect,
|
||||
callback: F,
|
||||
input: Child<NumberInputSlider>,
|
||||
cancel_button: Child<Button>,
|
||||
confirm_button: Child<Button>,
|
||||
}
|
||||
|
||||
impl<F> NumberInputSliderDialog<F>
|
||||
where
|
||||
F: Fn(u32),
|
||||
{
|
||||
pub fn new(min: u32, max: u32, init_value: u32, callback: F) -> Self {
|
||||
Self {
|
||||
area: Rect::zero(),
|
||||
callback,
|
||||
input: NumberInputSlider::new(min, max, init_value).into_child(),
|
||||
cancel_button: Button::with_text("CANCEL".into())
|
||||
.styled(theme::button_cancel())
|
||||
.into_child(),
|
||||
confirm_button: Button::with_text("CONFIRM".into())
|
||||
.styled(theme::button_confirm())
|
||||
.into_child(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value(&self) -> u32 {
|
||||
self.input.inner().value
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Component for NumberInputSliderDialog<F>
|
||||
where
|
||||
F: Fn(u32),
|
||||
{
|
||||
type Msg = NumberInputSliderDialogMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.area = bounds;
|
||||
let button_height = theme::BUTTON_HEIGHT;
|
||||
let content_area = self.area.inset(Insets::top(2 * theme::BUTTON_SPACING));
|
||||
let (_, content_area) = content_area.split_top(30);
|
||||
let (input_area, _) = content_area.split_top(15);
|
||||
let (_, button_area) = content_area.split_bottom(button_height);
|
||||
// let (content_area, button_area) = content_area.split_bottom(button_height);
|
||||
// let content_area = content_area.inset(Insets::new(
|
||||
// theme::BUTTON_SPACING,
|
||||
// 0,
|
||||
// theme::BUTTON_SPACING,
|
||||
// theme::CONTENT_BORDER,
|
||||
// ));
|
||||
|
||||
let grid = Grid::new(button_area, 1, 2).with_spacing(theme::KEYBOARD_SPACING);
|
||||
self.input.place(input_area.inset(Insets::sides(20)));
|
||||
self.cancel_button.place(grid.row_col(0, 0));
|
||||
self.confirm_button.place(grid.row_col(0, 1));
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
if let Some(NumberInputSliderMsg::Changed(i)) = self.input.event(ctx, event) {
|
||||
(self.callback)(i);
|
||||
}
|
||||
if let Some(ButtonMsg::Clicked) = self.cancel_button.event(ctx, event) {
|
||||
return Some(Self::Msg::Cancelled);
|
||||
}
|
||||
if let Some(ButtonMsg::Clicked) = self.confirm_button.event(ctx, event) {
|
||||
return Some(Self::Msg::Confirmed);
|
||||
};
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.input.paint();
|
||||
// self.paragraphs_pad.paint();
|
||||
// self.paragraphs.paint();
|
||||
self.cancel_button.paint();
|
||||
self.confirm_button.paint();
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_bounds")]
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
sink(self.area);
|
||||
self.input.bounds(sink);
|
||||
// self.paragraphs.bounds(sink);
|
||||
self.cancel_button.bounds(sink);
|
||||
self.confirm_button.bounds(sink);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<F> crate::trace::Trace for NumberInputSliderDialog<F>
|
||||
where
|
||||
F: Fn(u32),
|
||||
{
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.component("NumberInputSliderDialog");
|
||||
t.child("input", &self.input);
|
||||
t.child("cancel_button", &self.cancel_button);
|
||||
t.child("confirm_button", &self.confirm_button);
|
||||
}
|
||||
}
|
||||
|
||||
pub enum NumberInputSliderMsg {
|
||||
Changed(u32),
|
||||
}
|
||||
|
||||
pub struct NumberInputSlider {
|
||||
area: Rect,
|
||||
touch_area: Rect,
|
||||
min: u32,
|
||||
max: u32,
|
||||
value: u32,
|
||||
}
|
||||
|
||||
impl NumberInputSlider {
|
||||
pub fn new(min: u32, max: u32, value: u32) -> Self {
|
||||
let value = value.clamp(min, max);
|
||||
Self {
|
||||
area: Rect::zero(),
|
||||
touch_area: Rect::zero(),
|
||||
min,
|
||||
max,
|
||||
value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn slider_eval(&mut self, pos: Point, ctx: &mut EventCtx) -> Option<NumberInputSliderMsg> {
|
||||
if self.touch_area.contains(pos) {
|
||||
let filled = pos.x - self.area.x0;
|
||||
let filled = filled.clamp(0, self.area.width());
|
||||
let val_pct = (filled as u32 * 100) / self.area.width() as u32;
|
||||
let val = (val_pct * (self.max - self.min)) / 100 + self.min;
|
||||
|
||||
if val != self.value {
|
||||
self.value = val;
|
||||
ctx.request_paint();
|
||||
return Some(NumberInputSliderMsg::Changed(self.value));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for NumberInputSlider {
|
||||
type Msg = NumberInputSliderMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.area = bounds;
|
||||
self.touch_area = bounds.outset(Insets::new(40, 20, 40, 20)).clamp(screen());
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
if let Event::Touch(touch_event) = event {
|
||||
return match touch_event {
|
||||
TouchEvent::TouchStart(pos) => self.slider_eval(pos, ctx),
|
||||
TouchEvent::TouchMove(pos) => self.slider_eval(pos, ctx),
|
||||
TouchEvent::TouchEnd(pos) => self.slider_eval(pos, ctx),
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
let val_pct = (100 * (self.value - self.min)) / (self.max - self.min);
|
||||
let fill_to = (val_pct as i16 * self.area.width()) / 100;
|
||||
|
||||
display::bar_with_text_and_fill(self.area, None, theme::FG, theme::BG, 0, fill_to as _);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_bounds")]
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
sink(self.area)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for NumberInputSlider {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.component("NumberInput");
|
||||
t.int("value", self.value as i64);
|
||||
}
|
||||
}
|
@ -159,7 +159,7 @@ where
|
||||
|
||||
// Swipe has dimmed the screen, so fade back to normal backlight after the next
|
||||
// paint.
|
||||
self.fade = Some(theme::BACKLIGHT_NORMAL);
|
||||
self.fade = Some(theme::backlight::get_backlight_normal());
|
||||
}
|
||||
|
||||
fn is_cancel_visible(&self) -> bool {
|
||||
|
@ -80,7 +80,8 @@ where
|
||||
|
||||
// Swipe has dimmed the screen, so fade back to normal backlight after the next
|
||||
// paint.
|
||||
self.fade.set(Some(theme::BACKLIGHT_NORMAL));
|
||||
self.fade
|
||||
.set(Some(theme::backlight::get_backlight_normal()));
|
||||
}
|
||||
|
||||
fn is_horizontal(&self) -> bool {
|
||||
|
@ -3,10 +3,9 @@ use crate::ui::{
|
||||
display,
|
||||
event::TouchEvent,
|
||||
geometry::{Point, Rect},
|
||||
model_tt::theme::backlight,
|
||||
};
|
||||
|
||||
use super::theme;
|
||||
|
||||
pub enum SwipeDirection {
|
||||
Up,
|
||||
Down,
|
||||
@ -36,8 +35,8 @@ impl Swipe {
|
||||
allow_down: false,
|
||||
allow_left: false,
|
||||
allow_right: false,
|
||||
backlight_start: theme::BACKLIGHT_NORMAL,
|
||||
backlight_end: theme::BACKLIGHT_NONE,
|
||||
backlight_start: backlight::get_backlight_normal(),
|
||||
backlight_end: backlight::get_backlight_none(),
|
||||
origin: None,
|
||||
}
|
||||
}
|
||||
|
@ -44,8 +44,9 @@ use super::{
|
||||
CancelConfirmMsg, CancelInfoConfirmMsg, CoinJoinProgress, Dialog, DialogMsg, FidoConfirm,
|
||||
FidoMsg, Frame, FrameMsg, Homescreen, HomescreenMsg, IconDialog, Lockscreen, MnemonicInput,
|
||||
MnemonicKeyboard, MnemonicKeyboardMsg, NumberInputDialog, NumberInputDialogMsg,
|
||||
PassphraseKeyboard, PassphraseKeyboardMsg, PinKeyboard, PinKeyboardMsg, Progress,
|
||||
SelectWordCount, SelectWordCountMsg, SelectWordMsg, SimplePage, Slip39Input,
|
||||
NumberInputSliderDialog, NumberInputSliderDialogMsg, PassphraseKeyboard,
|
||||
PassphraseKeyboardMsg, PinKeyboard, PinKeyboardMsg, Progress, SelectWordCount,
|
||||
SelectWordCountMsg, SelectWordMsg, SimplePage, Slip39Input,
|
||||
},
|
||||
theme,
|
||||
};
|
||||
@ -245,6 +246,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> ComponentMsgObj for NumberInputSliderDialog<F>
|
||||
where
|
||||
F: Fn(u32),
|
||||
{
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
let value = self.value().try_into()?;
|
||||
match msg {
|
||||
NumberInputSliderDialogMsg::Confirmed => Ok((CONFIRMED.as_obj(), value).try_into()?),
|
||||
NumberInputSliderDialogMsg::Cancelled => Ok((CANCELLED.as_obj(), value).try_into()?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ComponentMsgObj for Border<T>
|
||||
where
|
||||
T: ComponentMsgObj,
|
||||
@ -1341,6 +1355,31 @@ extern "C" fn new_request_number(n_args: usize, args: *const Obj, kwargs: *mut M
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_request_number_slider(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let min_count: u32 = kwargs.get(Qstr::MP_QSTR_min_count)?.try_into()?;
|
||||
let max_count: u32 = kwargs.get(Qstr::MP_QSTR_max_count)?.try_into()?;
|
||||
let count: u32 = kwargs.get(Qstr::MP_QSTR_count)?.try_into()?;
|
||||
let value_callback: Obj = kwargs.get(Qstr::MP_QSTR_callback)?;
|
||||
assert!(value_callback != Obj::const_none());
|
||||
|
||||
let callback = move |i: u32| {
|
||||
value_callback
|
||||
.call_with_n_args(&[i.try_into().unwrap()])
|
||||
.unwrap();
|
||||
};
|
||||
|
||||
let obj = LayoutObj::new(Frame::centered(
|
||||
theme::label_title(),
|
||||
title,
|
||||
NumberInputSliderDialog::new(min_count, max_count, count, callback),
|
||||
))?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_show_checklist(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
@ -2036,6 +2075,18 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// """Number input with + and - buttons, description, and info button."""
|
||||
Qstr::MP_QSTR_request_number => obj_fn_kw!(0, new_request_number).as_obj(),
|
||||
|
||||
|
||||
/// def request_number_slider(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// count: int,
|
||||
/// min_count: int,
|
||||
/// max_count: int,
|
||||
/// callback: Callable[[int], None] | None = None,
|
||||
/// ) -> object:
|
||||
/// """Number input with slider."""
|
||||
Qstr::MP_QSTR_request_number_slider => obj_fn_kw!(0, new_request_number_slider).as_obj(),
|
||||
|
||||
/// def show_checklist(
|
||||
/// *,
|
||||
/// title: str,
|
||||
|
@ -6,6 +6,9 @@ pub mod component;
|
||||
pub mod constant;
|
||||
pub mod theme;
|
||||
|
||||
#[cfg(feature = "backlight")]
|
||||
use crate::ui::model_tt::theme::backlight;
|
||||
|
||||
#[cfg(feature = "micropython")]
|
||||
pub mod layout;
|
||||
mod screens;
|
||||
@ -15,17 +18,17 @@ pub struct ModelTTFeatures;
|
||||
impl UIFeaturesCommon for ModelTTFeatures {
|
||||
fn fadein() {
|
||||
#[cfg(feature = "backlight")]
|
||||
crate::ui::display::fade_backlight_duration(theme::BACKLIGHT_NORMAL, 150);
|
||||
crate::ui::display::fade_backlight_duration(backlight::get_backlight_normal(), 150);
|
||||
}
|
||||
|
||||
fn fadeout() {
|
||||
#[cfg(feature = "backlight")]
|
||||
crate::ui::display::fade_backlight_duration(theme::BACKLIGHT_DIM, 150);
|
||||
crate::ui::display::fade_backlight_duration(backlight::get_backlight_normal(), 150);
|
||||
}
|
||||
|
||||
fn backlight_on() {
|
||||
#[cfg(feature = "backlight")]
|
||||
crate::ui::display::set_backlight(theme::BACKLIGHT_NORMAL);
|
||||
crate::ui::display::set_backlight(backlight::get_backlight_normal());
|
||||
}
|
||||
|
||||
const SCREEN: Rect = constant::SCREEN;
|
||||
|
30
core/embed/rust/src/ui/model_tt/theme/backlight.rs
Normal file
30
core/embed/rust/src/ui/model_tt/theme/backlight.rs
Normal file
@ -0,0 +1,30 @@
|
||||
#[cfg(not(feature = "bootloader"))]
|
||||
use crate::storage;
|
||||
|
||||
// Typical backlight values.
|
||||
|
||||
#[cfg(feature = "bootloader")]
|
||||
pub fn get_backlight_normal() -> u16 {
|
||||
150
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "bootloader"))]
|
||||
pub fn get_backlight_normal() -> u16 {
|
||||
storage::get_brightness().unwrap_or(150).into()
|
||||
}
|
||||
|
||||
pub fn get_backlight_low() -> u16 {
|
||||
45
|
||||
}
|
||||
|
||||
pub fn get_backlight_dim() -> u16 {
|
||||
5
|
||||
}
|
||||
|
||||
pub fn get_backlight_none() -> u16 {
|
||||
2
|
||||
}
|
||||
|
||||
pub fn get_backlight_max() -> u16 {
|
||||
255
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
pub mod backlight;
|
||||
pub mod bootloader;
|
||||
|
||||
use crate::{
|
||||
@ -18,13 +19,6 @@ use num_traits::FromPrimitive;
|
||||
|
||||
pub const ERASE_HOLD_DURATION: Duration = Duration::from_millis(1500);
|
||||
|
||||
// Typical backlight values.
|
||||
pub const BACKLIGHT_NORMAL: u16 = 150;
|
||||
pub const BACKLIGHT_LOW: u16 = 45;
|
||||
pub const BACKLIGHT_DIM: u16 = 5;
|
||||
pub const BACKLIGHT_NONE: u16 = 2;
|
||||
pub const BACKLIGHT_MAX: u16 = 255;
|
||||
|
||||
// Color palette.
|
||||
pub const WHITE: Color = Color::rgb(0xFF, 0xFF, 0xFF);
|
||||
pub const BLACK: Color = Color::rgb(0, 0, 0);
|
||||
|
@ -4,9 +4,11 @@
|
||||
#include STM32_HAL_H
|
||||
#include TREZOR_BOARD
|
||||
|
||||
#define TIM_FREQ 1000000
|
||||
#define TIM_FREQ 10000000
|
||||
|
||||
#define LED_PWM_PRESCALER (SystemCoreClock / TIM_FREQ - 1) // 1 MHz
|
||||
#define LED_PWM_PRESCALER (SystemCoreClock / TIM_FREQ - 1)
|
||||
|
||||
#define LED_PWM_PRESCALER_SLOW (SystemCoreClock / 1000000 - 1) // 1 MHz
|
||||
|
||||
#define LED_PWM_TIM_PERIOD (TIM_FREQ / BACKLIGHT_PWM_FREQ)
|
||||
|
||||
@ -16,6 +18,35 @@ static int pwm_period = 0;
|
||||
|
||||
int backlight_pwm_set(int val) {
|
||||
if (BACKLIGHT != val && val >= 0 && val <= 255) {
|
||||
// TPS61043: min 1% duty cycle
|
||||
if (val < BACKLIGHT_PWM_TIM->ARR / 100) {
|
||||
val = 0;
|
||||
}
|
||||
|
||||
// TPS61043 goes to shutdown when duty cycle is 0 (after 32ms),
|
||||
// so we need to set GPIO to high for at least 500us
|
||||
// to wake it up.
|
||||
if (BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR == 0) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
||||
|
||||
HAL_GPIO_WritePin(BACKLIGHT_PWM_PORT, BACKLIGHT_PWM_PIN, GPIO_PIN_SET);
|
||||
// LCD_PWM/PA7 (backlight control)
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStructure.Pin = BACKLIGHT_PWM_PIN;
|
||||
HAL_GPIO_Init(BACKLIGHT_PWM_PORT, &GPIO_InitStructure);
|
||||
|
||||
hal_delay_us(500);
|
||||
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStructure.Alternate = BACKLIGHT_PWM_TIM_AF;
|
||||
GPIO_InitStructure.Pin = BACKLIGHT_PWM_PIN;
|
||||
HAL_GPIO_Init(BACKLIGHT_PWM_PORT, &GPIO_InitStructure);
|
||||
}
|
||||
|
||||
BACKLIGHT = val;
|
||||
BACKLIGHT_PWM_TIM->CCR1 = (pwm_period * val) / 255;
|
||||
}
|
||||
@ -157,6 +188,7 @@ void backlight_pwm_reinit(void) {
|
||||
BACKLIGHT = prev_val;
|
||||
|
||||
pwm_period = LED_PWM_TIM_PERIOD;
|
||||
BACKLIGHT_PWM_TIM->PSC = LED_PWM_PRESCALER;
|
||||
BACKLIGHT_PWM_TIM->CR1 |= TIM_CR1_ARPE;
|
||||
BACKLIGHT_PWM_TIM->CR2 |= TIM_CR2_CCPC;
|
||||
BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = (pwm_period * prev_val) / 255;
|
||||
@ -176,6 +208,7 @@ void backlight_pwm_set_slow(void) {
|
||||
prev_val = prev_val > 255 ? 255 : prev_val;
|
||||
|
||||
pwm_period = LED_PWM_SLOW_TIM_PERIOD;
|
||||
BACKLIGHT_PWM_TIM->PSC = LED_PWM_PRESCALER_SLOW;
|
||||
BACKLIGHT_PWM_TIM->CR1 |= TIM_CR1_ARPE;
|
||||
BACKLIGHT_PWM_TIM->CR2 |= TIM_CR2_CCPC;
|
||||
BACKLIGHT_PWM_TIM->ARR = LED_PWM_SLOW_TIM_PERIOD - 1;
|
||||
|
@ -866,6 +866,18 @@ def request_number(
|
||||
"""Number input with + and - buttons, description, and info button."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def request_number_slider(
|
||||
*,
|
||||
title: str,
|
||||
count: int,
|
||||
min_count: int,
|
||||
max_count: int,
|
||||
callback: Callable[[int], None] | None = None,
|
||||
) -> object:
|
||||
"""Number input with slider."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def show_checklist(
|
||||
*,
|
||||
|
2
core/src/all_modules.py
generated
2
core/src/all_modules.py
generated
@ -179,6 +179,8 @@ trezor.ui.layouts.tt.fido
|
||||
import trezor.ui.layouts.tt.fido
|
||||
trezor.ui.layouts.tt.homescreen
|
||||
import trezor.ui.layouts.tt.homescreen
|
||||
trezor.ui.layouts.tt.progress
|
||||
import trezor.ui.layouts.tt.progress
|
||||
trezor.ui.layouts.tt.recovery
|
||||
import trezor.ui.layouts.tt.recovery
|
||||
trezor.ui.layouts.tt.reset
|
||||
|
@ -434,7 +434,7 @@ def reload_settings_from_storage() -> None:
|
||||
)
|
||||
wire.EXPERIMENTAL_ENABLED = storage_device.get_experimental_features()
|
||||
if ui.display.orientation() != storage_device.get_rotation():
|
||||
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
||||
ui.backlight_fade(ui.style.get_backlight_dim())
|
||||
ui.display.orientation(storage_device.get_rotation())
|
||||
|
||||
|
||||
|
@ -2,9 +2,10 @@ from typing import TYPE_CHECKING
|
||||
|
||||
import storage.device as storage_device
|
||||
import trezorui2
|
||||
from trezor import TR
|
||||
from trezor import TR, utils
|
||||
from trezor.enums import ButtonRequestType
|
||||
from trezor.ui.layouts import confirm_action
|
||||
from trezor.ui import display, style
|
||||
from trezor.ui.layouts import confirm_action, request_number_slider
|
||||
from trezor.wire import DataError
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -50,6 +51,7 @@ async def apply_settings(msg: ApplySettings) -> Success:
|
||||
msg_safety_checks = msg.safety_checks # local_cache_attribute
|
||||
experimental_features = msg.experimental_features # local_cache_attribute
|
||||
hide_passphrase_from_host = msg.hide_passphrase_from_host # local_cache_attribute
|
||||
brightness = msg.brightness
|
||||
|
||||
if (
|
||||
homescreen is None
|
||||
@ -61,6 +63,7 @@ async def apply_settings(msg: ApplySettings) -> Success:
|
||||
and msg_safety_checks is None
|
||||
and experimental_features is None
|
||||
and hide_passphrase_from_host is None
|
||||
and (brightness is None or not utils.USE_BACKLIGHT)
|
||||
):
|
||||
raise ProcessError("No setting provided")
|
||||
|
||||
@ -114,6 +117,10 @@ async def apply_settings(msg: ApplySettings) -> Success:
|
||||
await _require_confirm_hide_passphrase_from_host(hide_passphrase_from_host)
|
||||
storage_device.set_hide_passphrase_from_host(hide_passphrase_from_host)
|
||||
|
||||
if brightness is not None and utils.USE_BACKLIGHT:
|
||||
new_brightness = await _require_set_brightness()
|
||||
storage_device.set_brightness(new_brightness)
|
||||
|
||||
reload_settings_from_storage()
|
||||
|
||||
return Success(message="Settings applied")
|
||||
@ -255,3 +262,19 @@ async def _require_confirm_hide_passphrase_from_host(enable: bool) -> None:
|
||||
description=TR.passphrase__hide,
|
||||
br_code=BRT_PROTECT_CALL,
|
||||
)
|
||||
|
||||
|
||||
if utils.USE_BACKLIGHT:
|
||||
|
||||
async def _require_set_brightness() -> int:
|
||||
def callback(val: int) -> None:
|
||||
display.backlight(val)
|
||||
|
||||
return await request_number_slider(
|
||||
"Set brightness",
|
||||
callback,
|
||||
min_count=style.get_backlight_min(),
|
||||
max_count=style.get_backlight_max(),
|
||||
count=style.get_backlight_normal(),
|
||||
br_name="set_brightness",
|
||||
)
|
||||
|
@ -49,7 +49,7 @@ async def bootscreen() -> None:
|
||||
|
||||
if can_lock_device():
|
||||
enforce_welcome_screen_duration()
|
||||
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
||||
ui.backlight_fade(ui.style.get_backlight_dim())
|
||||
ui.display.orientation(storage.device.get_rotation())
|
||||
await lockscreen
|
||||
await verify_user_pin()
|
||||
@ -64,7 +64,7 @@ async def bootscreen() -> None:
|
||||
if rotation != ui.display.orientation():
|
||||
# there is a slight delay before next screen is shown,
|
||||
# so we don't fade unless there is a change of orientation
|
||||
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
||||
ui.backlight_fade(ui.style.get_backlight_dim())
|
||||
ui.display.orientation(rotation)
|
||||
allow_all_loader_messages()
|
||||
return
|
||||
|
@ -49,12 +49,12 @@ def get_bool(app: int, key: int, public: bool = False) -> bool:
|
||||
return get(app, key, public) == _TRUE_BYTE
|
||||
|
||||
|
||||
def set_uint8(app: int, key: int, val: int) -> None:
|
||||
set(app, key, val.to_bytes(1, "big"))
|
||||
def set_uint8(app: int, key: int, val: int, public: bool = False) -> None:
|
||||
set(app, key, val.to_bytes(1, "big"), public)
|
||||
|
||||
|
||||
def get_uint8(app: int, key: int) -> int | None:
|
||||
val = get(app, key)
|
||||
def get_uint8(app: int, key: int, public: bool = False) -> int | None:
|
||||
val = get(app, key, public)
|
||||
if not val:
|
||||
return None
|
||||
return int.from_bytes(val, "big")
|
||||
|
@ -35,6 +35,7 @@ INITIALIZED = const(0x13) # bool (0x01 or empty)
|
||||
_SAFETY_CHECK_LEVEL = const(0x14) # int
|
||||
_EXPERIMENTAL_FEATURES = const(0x15) # bool (0x01 or empty)
|
||||
_HIDE_PASSPHRASE_FROM_HOST = const(0x16) # bool (0x01 or empty)
|
||||
_BRIGHTNESS = const(0x17) # int
|
||||
|
||||
SAFETY_CHECK_LEVEL_STRICT : Literal[0] = const(0)
|
||||
SAFETY_CHECK_LEVEL_PROMPT : Literal[1] = const(1)
|
||||
@ -344,3 +345,17 @@ def get_hide_passphrase_from_host() -> bool:
|
||||
Whether we should hide the passphrase from the host.
|
||||
"""
|
||||
return common.get_bool(_NAMESPACE, _HIDE_PASSPHRASE_FROM_HOST)
|
||||
|
||||
|
||||
def set_brightness(brightness: int) -> None:
|
||||
"""
|
||||
Set the display brightness setting.
|
||||
"""
|
||||
common.set_uint8(_NAMESPACE, _BRIGHTNESS, brightness, True)
|
||||
|
||||
|
||||
def get_brightness() -> int | None:
|
||||
"""
|
||||
Get the display brightness setting.
|
||||
"""
|
||||
return common.get_uint8(_NAMESPACE, _BRIGHTNESS, True)
|
||||
|
2
core/src/trezor/messages.py
generated
2
core/src/trezor/messages.py
generated
@ -2233,6 +2233,7 @@ if TYPE_CHECKING:
|
||||
safety_checks: "SafetyCheckLevel | None"
|
||||
experimental_features: "bool | None"
|
||||
hide_passphrase_from_host: "bool | None"
|
||||
brightness: "int | None"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -2246,6 +2247,7 @@ if TYPE_CHECKING:
|
||||
safety_checks: "SafetyCheckLevel | None" = None,
|
||||
experimental_features: "bool | None" = None,
|
||||
hide_passphrase_from_host: "bool | None" = None,
|
||||
brightness: "int | None" = None,
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
@ -62,12 +62,12 @@ async def _alert(count: int) -> None:
|
||||
long_sleep = loop.sleep(80)
|
||||
for i in range(count * 2):
|
||||
if i % 2 == 0:
|
||||
display.backlight(style.BACKLIGHT_MAX)
|
||||
display.backlight(style.get_backlight_max())
|
||||
await short_sleep
|
||||
else:
|
||||
display.backlight(style.BACKLIGHT_DIM)
|
||||
display.backlight(style.get_backlight_dim())
|
||||
await long_sleep
|
||||
display.backlight(style.BACKLIGHT_NORMAL)
|
||||
display.backlight(style.get_backlight_normal())
|
||||
global _alert_in_progress
|
||||
_alert_in_progress = False
|
||||
|
||||
|
@ -34,11 +34,11 @@ class RustProgress:
|
||||
layout: Any,
|
||||
):
|
||||
self.layout = layout
|
||||
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
||||
ui.backlight_fade(ui.style.get_backlight_dim())
|
||||
self.layout.attach_timer_fn(self.set_timer)
|
||||
self.layout.paint()
|
||||
ui.refresh()
|
||||
ui.backlight_fade(ui.style.BACKLIGHT_NORMAL)
|
||||
ui.backlight_fade(ui.style.get_backlight_normal())
|
||||
|
||||
def set_timer(self, token: int, deadline: int) -> None:
|
||||
raise RuntimeError # progress layouts should not set timers
|
||||
|
@ -9,7 +9,7 @@ from trezor.wire.context import wait as ctx_wait
|
||||
from ..common import button_request, interact
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Awaitable, Iterable, NoReturn, Sequence, TypeVar
|
||||
from typing import Any, Awaitable, Callable, Iterable, NoReturn, Sequence, TypeVar
|
||||
|
||||
from ..common import ExceptionType, PropertyType
|
||||
|
||||
@ -36,13 +36,13 @@ if __debug__:
|
||||
|
||||
|
||||
class RustLayout(LayoutParentType[T]):
|
||||
BACKLIGHT_LEVEL = ui.style.BACKLIGHT_NORMAL
|
||||
|
||||
# pylint: disable=super-init-not-called
|
||||
def __init__(self, layout: trezorui2.LayoutObj[T]):
|
||||
self.layout = layout
|
||||
self.timer = loop.Timer()
|
||||
self.layout.attach_timer_fn(self.set_timer)
|
||||
self.backlight_level = ui.style.get_backlight_normal()
|
||||
|
||||
def set_timer(self, token: int, deadline: int) -> None:
|
||||
self.timer.schedule(deadline, token)
|
||||
@ -168,7 +168,7 @@ class RustLayout(LayoutParentType[T]):
|
||||
return self.handle_timers(), self.handle_input_and_rendering()
|
||||
|
||||
def _first_paint(self) -> None:
|
||||
ui.backlight_fade(ui.style.BACKLIGHT_NONE)
|
||||
ui.backlight_fade(ui.style.get_backlight_none())
|
||||
self._paint()
|
||||
|
||||
if __debug__ and self.should_notify_layout_change:
|
||||
@ -191,7 +191,7 @@ class RustLayout(LayoutParentType[T]):
|
||||
notify_layout_change(self, event_id)
|
||||
|
||||
# Turn the brightness on again.
|
||||
ui.backlight_fade(self.BACKLIGHT_LEVEL)
|
||||
ui.backlight_fade(self.backlight_level)
|
||||
|
||||
def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator]
|
||||
from trezor import workflow
|
||||
@ -228,10 +228,10 @@ def draw_simple(layout: trezorui2.LayoutObj[Any]) -> None:
|
||||
raise RuntimeError
|
||||
|
||||
layout.attach_timer_fn(dummy_set_timer)
|
||||
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
||||
ui.backlight_fade(ui.style.get_backlight_dim())
|
||||
layout.paint()
|
||||
ui.refresh()
|
||||
ui.backlight_fade(ui.style.BACKLIGHT_NORMAL)
|
||||
ui.backlight_fade(ui.style.get_backlight_normal())
|
||||
|
||||
|
||||
async def raise_if_not_confirmed(
|
||||
@ -1525,3 +1525,40 @@ def confirm_firmware_update(description: str, fingerprint: str) -> Awaitable[Non
|
||||
BR_TYPE_OTHER,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def request_number_slider(
|
||||
title: str,
|
||||
callback: Callable[[int], None],
|
||||
count: int,
|
||||
min_count: int,
|
||||
max_count: int,
|
||||
br_name: str,
|
||||
) -> int:
|
||||
num_input = RustLayout(
|
||||
trezorui2.request_number_slider(
|
||||
title=title.upper(),
|
||||
callback=callback,
|
||||
count=count,
|
||||
min_count=min_count,
|
||||
max_count=max_count,
|
||||
)
|
||||
)
|
||||
while True:
|
||||
result = await interact(
|
||||
num_input,
|
||||
br_name,
|
||||
BR_TYPE_OTHER,
|
||||
)
|
||||
# if __debug__:
|
||||
# if not isinstance(result, tuple):
|
||||
# # DebugLink currently can't send number of shares and it doesn't
|
||||
# # change the counter either so just use the initial value.
|
||||
# result = (result, count)
|
||||
status, value = result
|
||||
|
||||
if status == CONFIRMED:
|
||||
assert isinstance(value, int)
|
||||
return value
|
||||
|
||||
raise ActionCancelled
|
||||
|
@ -85,7 +85,6 @@ class Homescreen(HomescreenBase):
|
||||
|
||||
class Lockscreen(HomescreenBase):
|
||||
RENDER_INDICATOR = storage_cache.LOCKSCREEN_ON
|
||||
BACKLIGHT_LEVEL = ui.style.BACKLIGHT_LOW
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -94,8 +93,9 @@ class Lockscreen(HomescreenBase):
|
||||
coinjoin_authorized: bool = False,
|
||||
) -> None:
|
||||
self.bootscreen = bootscreen
|
||||
self.backlight_level = ui.style.get_backlight_low()
|
||||
if bootscreen:
|
||||
self.BACKLIGHT_LEVEL = ui.style.BACKLIGHT_NORMAL
|
||||
self.backlight_level = ui.style.get_backlight_normal()
|
||||
|
||||
skip = (
|
||||
not bootscreen and storage_cache.homescreen_shown is self.RENDER_INDICATOR
|
||||
|
0
core/src/trezor/ui/layouts/tt/progress.py
Normal file
0
core/src/trezor/ui/layouts/tt/progress.py
Normal file
@ -1,8 +1,41 @@
|
||||
from micropython import const
|
||||
|
||||
import storage.device
|
||||
|
||||
# backlight brightness
|
||||
BACKLIGHT_NORMAL = const(150)
|
||||
BACKLIGHT_LOW = const(45)
|
||||
BACKLIGHT_DIM = const(5)
|
||||
BACKLIGHT_NONE = const(0)
|
||||
BACKLIGHT_MAX = const(255)
|
||||
_BACKLIGHT_NORMAL = const(150)
|
||||
_BACKLIGHT_LOW = const(45)
|
||||
_BACKLIGHT_DIM = const(5)
|
||||
_BACKLIGHT_NONE = const(0)
|
||||
_BACKLIGHT_MIN = const(10)
|
||||
_BACKLIGHT_MAX = const(255)
|
||||
|
||||
|
||||
def get_backlight_normal() -> int:
|
||||
val = storage.device.get_brightness()
|
||||
if val is None:
|
||||
return _BACKLIGHT_NORMAL
|
||||
return val
|
||||
|
||||
|
||||
def get_backlight_low() -> int:
|
||||
val = storage.device.get_brightness()
|
||||
if val is None or val > _BACKLIGHT_LOW:
|
||||
return _BACKLIGHT_LOW
|
||||
return val
|
||||
|
||||
|
||||
def get_backlight_dim() -> int:
|
||||
return _BACKLIGHT_DIM
|
||||
|
||||
|
||||
def get_backlight_none() -> int:
|
||||
return _BACKLIGHT_NONE
|
||||
|
||||
|
||||
def get_backlight_min() -> int:
|
||||
return _BACKLIGHT_MIN
|
||||
|
||||
|
||||
def get_backlight_max() -> int:
|
||||
return _BACKLIGHT_MAX
|
||||
|
1
python/.changelog.d/3208.added
Normal file
1
python/.changelog.d/3208.added
Normal file
@ -0,0 +1 @@
|
||||
Added user adjustable brightness setting.
|
@ -206,6 +206,13 @@ def label(client: "TrezorClient", label: str) -> str:
|
||||
return device.apply_settings(client, label=label)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@with_client
|
||||
def brightness(client: "TrezorClient") -> str:
|
||||
"""Set display brightness."""
|
||||
return device.apply_settings(client, brightness=0)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.argument("path_or_url", required=False)
|
||||
@click.option(
|
||||
|
@ -47,6 +47,7 @@ def apply_settings(
|
||||
safety_checks: Optional[messages.SafetyCheckLevel] = None,
|
||||
experimental_features: Optional[bool] = None,
|
||||
hide_passphrase_from_host: Optional[bool] = None,
|
||||
brightness: Optional[int] = None,
|
||||
) -> "MessageType":
|
||||
if language is not None:
|
||||
warnings.warn(
|
||||
@ -63,6 +64,7 @@ def apply_settings(
|
||||
safety_checks=safety_checks,
|
||||
experimental_features=experimental_features,
|
||||
hide_passphrase_from_host=hide_passphrase_from_host,
|
||||
brightness=brightness,
|
||||
)
|
||||
|
||||
out = client.call(settings)
|
||||
|
3
python/src/trezorlib/messages.py
generated
3
python/src/trezorlib/messages.py
generated
@ -3361,6 +3361,7 @@ class ApplySettings(protobuf.MessageType):
|
||||
9: protobuf.Field("safety_checks", "SafetyCheckLevel", repeated=False, required=False, default=None),
|
||||
10: protobuf.Field("experimental_features", "bool", repeated=False, required=False, default=None),
|
||||
11: protobuf.Field("hide_passphrase_from_host", "bool", repeated=False, required=False, default=None),
|
||||
12: protobuf.Field("brightness", "uint32", repeated=False, required=False, default=None),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
@ -3377,6 +3378,7 @@ class ApplySettings(protobuf.MessageType):
|
||||
safety_checks: Optional["SafetyCheckLevel"] = None,
|
||||
experimental_features: Optional["bool"] = None,
|
||||
hide_passphrase_from_host: Optional["bool"] = None,
|
||||
brightness: Optional["int"] = None,
|
||||
) -> None:
|
||||
self.language = language
|
||||
self.label = label
|
||||
@ -3389,6 +3391,7 @@ class ApplySettings(protobuf.MessageType):
|
||||
self.safety_checks = safety_checks
|
||||
self.experimental_features = experimental_features
|
||||
self.hide_passphrase_from_host = hide_passphrase_from_host
|
||||
self.brightness = brightness
|
||||
|
||||
|
||||
class ChangeLanguage(protobuf.MessageType):
|
||||
|
@ -2993,6 +2993,8 @@ pub struct ApplySettings {
|
||||
pub experimental_features: ::std::option::Option<bool>,
|
||||
// @@protoc_insertion_point(field:hw.trezor.messages.management.ApplySettings.hide_passphrase_from_host)
|
||||
pub hide_passphrase_from_host: ::std::option::Option<bool>,
|
||||
// @@protoc_insertion_point(field:hw.trezor.messages.management.ApplySettings.brightness)
|
||||
pub brightness: ::std::option::Option<u32>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:hw.trezor.messages.management.ApplySettings.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
@ -3272,8 +3274,27 @@ impl ApplySettings {
|
||||
self.hide_passphrase_from_host = ::std::option::Option::Some(v);
|
||||
}
|
||||
|
||||
// optional uint32 brightness = 12;
|
||||
|
||||
pub fn brightness(&self) -> u32 {
|
||||
self.brightness.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn clear_brightness(&mut self) {
|
||||
self.brightness = ::std::option::Option::None;
|
||||
}
|
||||
|
||||
pub fn has_brightness(&self) -> bool {
|
||||
self.brightness.is_some()
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_brightness(&mut self, v: u32) {
|
||||
self.brightness = ::std::option::Option::Some(v);
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(11);
|
||||
let mut fields = ::std::vec::Vec::with_capacity(12);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
|
||||
"language",
|
||||
@ -3330,6 +3351,11 @@ impl ApplySettings {
|
||||
|m: &ApplySettings| { &m.hide_passphrase_from_host },
|
||||
|m: &mut ApplySettings| { &mut m.hide_passphrase_from_host },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
|
||||
"brightness",
|
||||
|m: &ApplySettings| { &m.brightness },
|
||||
|m: &mut ApplySettings| { &mut m.brightness },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<ApplySettings>(
|
||||
"ApplySettings",
|
||||
fields,
|
||||
@ -3381,6 +3407,9 @@ impl ::protobuf::Message for ApplySettings {
|
||||
88 => {
|
||||
self.hide_passphrase_from_host = ::std::option::Option::Some(is.read_bool()?);
|
||||
},
|
||||
96 => {
|
||||
self.brightness = ::std::option::Option::Some(is.read_uint32()?);
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
@ -3426,6 +3455,9 @@ impl ::protobuf::Message for ApplySettings {
|
||||
if let Some(v) = self.hide_passphrase_from_host {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
if let Some(v) = self.brightness {
|
||||
my_size += ::protobuf::rt::uint32_size(12, v);
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
@ -3465,6 +3497,9 @@ impl ::protobuf::Message for ApplySettings {
|
||||
if let Some(v) = self.hide_passphrase_from_host {
|
||||
os.write_bool(11, v)?;
|
||||
}
|
||||
if let Some(v) = self.brightness {
|
||||
os.write_uint32(12, v)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
@ -3493,6 +3528,7 @@ impl ::protobuf::Message for ApplySettings {
|
||||
self.safety_checks = ::std::option::Option::None;
|
||||
self.experimental_features = ::std::option::Option::None;
|
||||
self.hide_passphrase_from_host = ::std::option::Option::None;
|
||||
self.brightness = ::std::option::Option::None;
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
@ -3509,6 +3545,7 @@ impl ::protobuf::Message for ApplySettings {
|
||||
safety_checks: ::std::option::Option::None,
|
||||
experimental_features: ::std::option::Option::None,
|
||||
hide_passphrase_from_host: ::std::option::Option::None,
|
||||
brightness: ::std::option::Option::None,
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
|
Loading…
Reference in New Issue
Block a user