mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-29 18:08:19 +00:00
feat(core/bootloader): bootloader button power off logic
[no changelog]
This commit is contained in:
parent
0e6052dc25
commit
c1bfd5a8b3
@ -27,8 +27,6 @@
|
|||||||
#include "rust_ui_bootloader.h"
|
#include "rust_ui_bootloader.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
#define BACKLIGHT_NORMAL 150
|
|
||||||
|
|
||||||
#define TOIF_LENGTH(ptr) ((*(uint32_t *)((ptr) + 8)) + 12)
|
#define TOIF_LENGTH(ptr) ((*(uint32_t *)((ptr) + 8)) + 12)
|
||||||
|
|
||||||
// common shared functions
|
// common shared functions
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#include "rust_ui_bootloader.h"
|
#include "rust_ui_bootloader.h"
|
||||||
|
|
||||||
|
#define BACKLIGHT_NORMAL 150
|
||||||
|
|
||||||
// Displays a warning screen before jumping to the untrusted firmware
|
// Displays a warning screen before jumping to the untrusted firmware
|
||||||
//
|
//
|
||||||
// Shows vendor image, vendor string and firmware version
|
// Shows vendor image, vendor string and firmware version
|
||||||
|
@ -31,10 +31,18 @@
|
|||||||
#include "wire/wire_iface_usb.h"
|
#include "wire/wire_iface_usb.h"
|
||||||
#include "workflow.h"
|
#include "workflow.h"
|
||||||
|
|
||||||
|
#ifdef USE_HAPTIC
|
||||||
|
#include <io/haptic.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_BLE
|
#ifdef USE_BLE
|
||||||
#include <wire/wire_iface_ble.h>
|
#include <wire/wire_iface_ble.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_BUTTON
|
||||||
|
#include <io/button.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_POWER_MANAGER
|
#ifdef USE_POWER_MANAGER
|
||||||
#include <io/display.h>
|
#include <io/display.h>
|
||||||
#include <io/display_utils.h>
|
#include <io/display_utils.h>
|
||||||
@ -53,6 +61,10 @@ workflow_result_t workflow_host_control(const vendor_header *const vhdr,
|
|||||||
workflow_result_t result = WF_ERROR_FATAL;
|
workflow_result_t result = WF_ERROR_FATAL;
|
||||||
|
|
||||||
#ifdef USE_POWER_MANAGER
|
#ifdef USE_POWER_MANAGER
|
||||||
|
uint32_t button_deadline = 0;
|
||||||
|
#ifdef USE_HAPTIC
|
||||||
|
bool button_haptic_played = false;
|
||||||
|
#endif
|
||||||
uint32_t fade_deadline = ticks_timeout(FADE_TIME_MS);
|
uint32_t fade_deadline = ticks_timeout(FADE_TIME_MS);
|
||||||
uint32_t suspend_deadline = ticks_timeout(SUSPEND_TIME_MS);
|
uint32_t suspend_deadline = ticks_timeout(SUSPEND_TIME_MS);
|
||||||
bool faded = false;
|
bool faded = false;
|
||||||
@ -86,6 +98,16 @@ workflow_result_t workflow_host_control(const vendor_header *const vhdr,
|
|||||||
sysevents_poll(&awaited, &signalled, ticks_timeout(100));
|
sysevents_poll(&awaited, &signalled, ticks_timeout(100));
|
||||||
|
|
||||||
#ifdef USE_POWER_MANAGER
|
#ifdef USE_POWER_MANAGER
|
||||||
|
|
||||||
|
#ifdef USE_HAPTIC
|
||||||
|
if (button_deadline != 0 && !button_haptic_played &&
|
||||||
|
ticks_expired(button_deadline)) {
|
||||||
|
// we reached hibernation time
|
||||||
|
haptic_play(HAPTIC_BOOTLOADER_ENTRY);
|
||||||
|
button_haptic_played = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (signalled.read_ready == 0) {
|
if (signalled.read_ready == 0) {
|
||||||
pm_state_t pm_state = {0};
|
pm_state_t pm_state = {0};
|
||||||
|
|
||||||
@ -106,7 +128,9 @@ workflow_result_t workflow_host_control(const vendor_header *const vhdr,
|
|||||||
|
|
||||||
if (ticks_expired(suspend_deadline)) {
|
if (ticks_expired(suspend_deadline)) {
|
||||||
pm_suspend(NULL);
|
pm_suspend(NULL);
|
||||||
|
screen_render(wait_layout);
|
||||||
display_fade(display_get_backlight(), fade_value, 200);
|
display_fade(display_get_backlight(), fade_value, 200);
|
||||||
|
button_deadline = 0;
|
||||||
faded = false;
|
faded = false;
|
||||||
fade_deadline = ticks_timeout(FADE_TIME_MS);
|
fade_deadline = ticks_timeout(FADE_TIME_MS);
|
||||||
suspend_deadline = ticks_timeout(SUSPEND_TIME_MS);
|
suspend_deadline = ticks_timeout(SUSPEND_TIME_MS);
|
||||||
@ -120,6 +144,44 @@ workflow_result_t workflow_host_control(const vendor_header *const vhdr,
|
|||||||
display_fade(display_get_backlight(), fade_value, 200);
|
display_fade(display_get_backlight(), fade_value, 200);
|
||||||
faded = false;
|
faded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// in case of battery powered device, power button is handled by eventloop
|
||||||
|
if (signalled.read_ready & (1 << SYSHANDLE_BUTTON)) {
|
||||||
|
button_event_t btn_event = {0};
|
||||||
|
// todo this eats all button events, not only power button, so it needs to
|
||||||
|
// be handled differently for button-based battery powered devices.
|
||||||
|
if (button_get_event(&btn_event) && btn_event.button == BTN_POWER) {
|
||||||
|
if (btn_event.event_type == BTN_EVENT_DOWN) {
|
||||||
|
button_deadline = ticks_timeout(3000);
|
||||||
|
#ifdef USE_HAPTIC
|
||||||
|
button_haptic_played = false;
|
||||||
|
#endif
|
||||||
|
} else if (btn_event.event_type == BTN_EVENT_UP &&
|
||||||
|
button_deadline != 0) {
|
||||||
|
display_fade(display_get_backlight(), 0, 200);
|
||||||
|
if (ticks_expired(button_deadline)) {
|
||||||
|
// power button pressed for 3 seconds, we hibernate
|
||||||
|
|
||||||
|
#ifdef USE_HAPTIC
|
||||||
|
if (!button_haptic_played) {
|
||||||
|
haptic_play(HAPTIC_BOOTLOADER_ENTRY);
|
||||||
|
button_haptic_played = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
pm_hibernate();
|
||||||
|
} else {
|
||||||
|
pm_suspend(NULL);
|
||||||
|
button_deadline = 0;
|
||||||
|
screen_render(wait_layout);
|
||||||
|
display_fade(display_get_backlight(), BACKLIGHT_NORMAL, 200);
|
||||||
|
faded = false;
|
||||||
|
fade_deadline = ticks_timeout(FADE_TIME_MS);
|
||||||
|
suspend_deadline = ticks_timeout(SUSPEND_TIME_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
if (signalled.read_ready == 0) {
|
if (signalled.read_ready == 0) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -456,6 +456,7 @@ fn generate_trezorhal_bindings() {
|
|||||||
.allowlist_function("pm_get_events")
|
.allowlist_function("pm_get_events")
|
||||||
.allowlist_function("pm_get_state")
|
.allowlist_function("pm_get_state")
|
||||||
.allowlist_function("pm_suspend")
|
.allowlist_function("pm_suspend")
|
||||||
|
.allowlist_function("pm_hibernate")
|
||||||
// irq
|
// irq
|
||||||
.allowlist_function("irq_lock_fn")
|
.allowlist_function("irq_lock_fn")
|
||||||
.allowlist_function("irq_unlock_fn")
|
.allowlist_function("irq_unlock_fn")
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
// common event function for screens that need UI + communication
|
// common event function for screens that need UI + communication
|
||||||
uint32_t screen_event(c_layout_t* layout, sysevents_t* signalled);
|
uint32_t screen_event(c_layout_t* layout, sysevents_t* signalled);
|
||||||
|
|
||||||
|
// common render event
|
||||||
|
void screen_render(c_layout_t* layout);
|
||||||
|
|
||||||
// result screens
|
// result screens
|
||||||
void screen_wipe_success(void);
|
void screen_wipe_success(void);
|
||||||
void screen_wipe_fail(void);
|
void screen_wipe_fail(void);
|
||||||
|
@ -4,6 +4,7 @@ use super::ffi;
|
|||||||
pub enum HapticEffect {
|
pub enum HapticEffect {
|
||||||
ButtonPress = ffi::haptic_effect_t_HAPTIC_BUTTON_PRESS as _,
|
ButtonPress = ffi::haptic_effect_t_HAPTIC_BUTTON_PRESS as _,
|
||||||
HoldToConfirm = ffi::haptic_effect_t_HAPTIC_HOLD_TO_CONFIRM as _,
|
HoldToConfirm = ffi::haptic_effect_t_HAPTIC_HOLD_TO_CONFIRM as _,
|
||||||
|
BootloaderEntry = ffi::haptic_effect_t_HAPTIC_BOOTLOADER_ENTRY as _,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn play(effect: HapticEffect) {
|
pub fn play(effect: HapticEffect) {
|
||||||
|
@ -51,3 +51,7 @@ pub fn is_usb_connected() -> bool {
|
|||||||
pub fn suspend() {
|
pub fn suspend() {
|
||||||
unsafe { ffi::pm_suspend(null_mut()) };
|
unsafe { ffi::pm_suspend(null_mut()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hibernate() {
|
||||||
|
unsafe { ffi::pm_hibernate() };
|
||||||
|
}
|
||||||
|
@ -23,6 +23,15 @@ extern "C" fn screen_event(layout: *mut c_layout_t, signalled: &sysevents_t) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn screen_render(layout: *mut c_layout_t) {
|
||||||
|
unsafe {
|
||||||
|
let mut layout = LayoutBuffer::<<ModelUI as BootloaderUI>::CLayoutType>::new(layout);
|
||||||
|
let layout = layout.get_mut();
|
||||||
|
layout.render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn screen_welcome(layout: *mut c_layout_t) {
|
extern "C" fn screen_welcome(layout: *mut c_layout_t) {
|
||||||
let mut screen = <ModelUI as BootloaderUI>::CLayoutType::init_welcome();
|
let mut screen = <ModelUI as BootloaderUI>::CLayoutType::init_welcome();
|
||||||
|
@ -16,10 +16,14 @@ use crate::trezorhal::sysevent::{sysevents_poll, Syshandle};
|
|||||||
#[cfg(feature = "power_manager")]
|
#[cfg(feature = "power_manager")]
|
||||||
use crate::{
|
use crate::{
|
||||||
time::Instant,
|
time::Instant,
|
||||||
trezorhal::power_manager::{is_usb_connected, suspend},
|
trezorhal::power_manager::{hibernate, is_usb_connected, suspend},
|
||||||
ui::display::fade_backlight_duration,
|
ui::display::fade_backlight_duration,
|
||||||
|
ui::event::PhysicalButton,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "haptic", feature = "power_manager"))]
|
||||||
|
use crate::trezorhal::haptic::{play, HapticEffect};
|
||||||
|
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
|
||||||
@ -98,6 +102,10 @@ pub fn run(frame: &mut impl Component<Msg = impl ReturnToC>) -> u32 {
|
|||||||
render(frame);
|
render(frame);
|
||||||
ModelUI::fadein();
|
ModelUI::fadein();
|
||||||
|
|
||||||
|
#[cfg(all(feature = "power_manager", feature = "haptic"))]
|
||||||
|
let mut haptic_played = false;
|
||||||
|
#[cfg(feature = "power_manager")]
|
||||||
|
let mut button_pressed_time = None;
|
||||||
#[cfg(feature = "power_manager")]
|
#[cfg(feature = "power_manager")]
|
||||||
let mut start = Instant::now();
|
let mut start = Instant::now();
|
||||||
let mut faded = false;
|
let mut faded = false;
|
||||||
@ -132,6 +140,39 @@ pub fn run(frame: &mut impl Component<Msg = impl ReturnToC>) -> u32 {
|
|||||||
#[cfg(feature = "power_manager")]
|
#[cfg(feature = "power_manager")]
|
||||||
{
|
{
|
||||||
start = Instant::now();
|
start = Instant::now();
|
||||||
|
|
||||||
|
if e == Event::Button(ButtonEvent::ButtonPressed(PhysicalButton::Power)) {
|
||||||
|
button_pressed_time = Some(Instant::now());
|
||||||
|
|
||||||
|
#[cfg(feature = "haptic")]
|
||||||
|
{
|
||||||
|
haptic_played = false;
|
||||||
|
}
|
||||||
|
} else if e == Event::Button(ButtonEvent::ButtonReleased(PhysicalButton::Power)) {
|
||||||
|
if let Some(t) = button_pressed_time {
|
||||||
|
if let Some(elapsed) = Instant::now().checked_duration_since(t) {
|
||||||
|
ModelUI::fadeout();
|
||||||
|
if elapsed.to_secs() >= 3 {
|
||||||
|
#[cfg(feature = "haptic")]
|
||||||
|
{
|
||||||
|
if !haptic_played {
|
||||||
|
play(HapticEffect::BootloaderEntry);
|
||||||
|
haptic_played = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hibernate();
|
||||||
|
} else {
|
||||||
|
suspend();
|
||||||
|
render(frame);
|
||||||
|
ModelUI::fadein();
|
||||||
|
|
||||||
|
faded = false;
|
||||||
|
button_pressed_time = None;
|
||||||
|
start = Instant::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ctx = EventCtx::new();
|
let mut ctx = EventCtx::new();
|
||||||
@ -145,6 +186,18 @@ pub fn run(frame: &mut impl Component<Msg = impl ReturnToC>) -> u32 {
|
|||||||
} else {
|
} else {
|
||||||
#[cfg(feature = "power_manager")]
|
#[cfg(feature = "power_manager")]
|
||||||
{
|
{
|
||||||
|
#[cfg(feature = "haptic")]
|
||||||
|
{
|
||||||
|
if let Some(t) = button_pressed_time {
|
||||||
|
if let Some(elapsed) = Instant::now().checked_duration_since(t) {
|
||||||
|
if elapsed.to_secs() >= 3 && !haptic_played {
|
||||||
|
play(HapticEffect::BootloaderEntry);
|
||||||
|
haptic_played = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if is_usb_connected() {
|
if is_usb_connected() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -164,6 +217,7 @@ pub fn run(frame: &mut impl Component<Msg = impl ReturnToC>) -> u32 {
|
|||||||
faded = false;
|
faded = false;
|
||||||
}
|
}
|
||||||
start = Instant::now();
|
start = Instant::now();
|
||||||
|
button_pressed_time = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use crate::ui::{
|
|||||||
component::{Event, Label},
|
component::{Event, Label},
|
||||||
display::{self, toif::Toif, Color},
|
display::{self, toif::Toif, Color},
|
||||||
geometry::{Alignment, Alignment2D, Offset, Point, Rect},
|
geometry::{Alignment, Alignment2D, Offset, Point, Rect},
|
||||||
layout::simplified::{process_frame_event, run, show},
|
layout::simplified::{process_frame_event, render, run, show},
|
||||||
shape::{self, render_on_display},
|
shape::{self, render_on_display},
|
||||||
ui_bootloader::{BootloaderLayoutType, BootloaderUI},
|
ui_bootloader::{BootloaderLayoutType, BootloaderUI},
|
||||||
CommonUI,
|
CommonUI,
|
||||||
@ -109,6 +109,18 @@ impl BootloaderLayoutType for BootloaderLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render(&mut self) {
|
||||||
|
match self {
|
||||||
|
BootloaderLayout::Welcome(f) => render(f),
|
||||||
|
BootloaderLayout::Menu(f) => render(f),
|
||||||
|
BootloaderLayout::Connect(f) => render(f),
|
||||||
|
#[cfg(feature = "ble")]
|
||||||
|
BootloaderLayout::PairingMode(f) => render(f),
|
||||||
|
#[cfg(feature = "ble")]
|
||||||
|
BootloaderLayout::WirelessSetup(f) => render(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn show(&mut self) {
|
fn show(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
BootloaderLayout::Welcome(f) => show(f, true),
|
BootloaderLayout::Welcome(f) => show(f, true),
|
||||||
|
@ -2,6 +2,11 @@ use crate::ui::component::Event;
|
|||||||
|
|
||||||
pub trait BootloaderLayoutType {
|
pub trait BootloaderLayoutType {
|
||||||
fn event(&mut self, event: Option<Event>) -> u32;
|
fn event(&mut self, event: Option<Event>) -> u32;
|
||||||
|
|
||||||
|
fn render(&mut self) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
fn show(&mut self);
|
fn show(&mut self);
|
||||||
fn init_welcome() -> Self;
|
fn init_welcome() -> Self;
|
||||||
fn init_menu(initial_setup: bool) -> Self;
|
fn init_menu(initial_setup: bool) -> Self;
|
||||||
|
Loading…
Reference in New Issue
Block a user