Skip to content

Commit

Permalink
Merge pull request #100 from trilitech/palmer@functori@reintroduce-th…
Browse files Browse the repository at this point in the history
…e-custom-screensaver

Reintroduce the custom screensaver
  • Loading branch information
ajinkyaraj-23 authored Apr 11, 2024
2 parents a92013c + 6b93eb5 commit 886946c
Show file tree
Hide file tree
Showing 12 changed files with 390 additions and 5 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,14 @@ $ octez-client list connected ledgers

## How the app works

### Screen saver

The screen saver is the one provided by Ledger ([Configure screen saver timeout](https://support.ledger.com/hc/en-us/articles/360017152034-Configure-PIN-lock-and-screen-saver?docs=true)).

On Nanos devices, the Ledger screensaver can slow down the baking app. This is why it is deactivated during signings.
After a signature, a low-cost screensaver will take over. It will switch the screen off after 20 seconds of inactivity.
Press any button to exit sleep mode. When the sleep mode is exited, the Ledger screen saver will take over again if there are no more signatures.

### High water mark (HWM)

To avoid double baking, double attestation and double pre-attestation, the application maintains a high water mark (HWM) corresponding to the last level/round encountered during signature requests. The HWMs are displayed on the home screen and are updated after each signature.
Expand Down
4 changes: 4 additions & 0 deletions src/apdu_sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ static int baking_sign_complete(bool const send_hash) {
case MAGIC_BYTE_PREATTESTATION:
case MAGIC_BYTE_ATTESTATION:
TZ_CHECK(guard_baking_authorized(&G.parsed_baking_data, &global.path_with_curve));
#ifdef TARGET_NANOS
// To be efficient, the signing needs a low-cost display
ux_set_low_cost_display_mode(true);
#endif
result = perform_signature(send_hash);
#ifdef HAVE_BAGL
// Ignore calculation errors
Expand Down
9 changes: 7 additions & 2 deletions src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "operations.h"
#include "ui.h"
#include "ui_screensaver.h"

/**
* @brief Zeros out all globals that can keep track of APDU instruction state
Expand Down Expand Up @@ -118,8 +119,12 @@ typedef struct {
ui_callback_t ok_callback;
/// Callback function if user rejected prompt.
ui_callback_t cxl_callback;
/// Screensaver is on/off.
bool is_blank_screen;
#ifdef HAVE_BAGL
/// If the low-cost display mode is enabled
bool low_cost_display_mode;
/// Screensaver context
ux_screensaver_state_t screensaver_state;
#endif // TARGET_NANOS
} dynamic_display;

bip32_path_with_curve_t path_with_curve; ///< holds the bip32 path and curve of the current key
Expand Down
11 changes: 11 additions & 0 deletions src/ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ void __attribute__((noreturn)) app_exit(void);

#ifdef HAVE_BAGL

#ifdef TARGET_NANOS
/**
* @brief Sets low-cost display mode
*
* Low-cost display stop handling `TICKER_EVENT`
*
* @param enable: if enable the mode or not
*/
void ux_set_low_cost_display_mode(bool enable);
#endif // HAVE_BAGL

/**
* @brief Calculates the chain id for the idle screens
*
Expand Down
80 changes: 80 additions & 0 deletions src/ui_bagl.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,88 @@
#include "memory.h"
#include "os_cx.h" // ui-menu
#include "to_string.h"
#include "ui_screensaver.h"

#include <stdbool.h>
#include <string.h>

#define G_display global.dynamic_display

#ifdef TARGET_NANOS
#include "io.h"

void ux_set_low_cost_display_mode(bool enable) {
if (G_display.low_cost_display_mode != enable) {
G_display.low_cost_display_mode = enable;
if (G_display.low_cost_display_mode) {
ux_screensaver_start_clock();
} else {
ux_screensaver_stop_clock();
}
}
}

uint8_t io_event(uint8_t channel);

/**
* Function similar to the one in `lib_standard_app/` except that the
* `TICKER_EVENT` handling is not enabled on low-cost display mode.
*
* Low-cost display mode is deactivated when the button is pressed and
* activated during signing because `TICKER_EVENT` handling slows down
* the application.
*
*/
uint8_t io_event(uint8_t channel) {
(void) channel;

switch (G_io_seproxyhal_spi_buffer[0]) {
case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT:
ux_set_low_cost_display_mode(false);
UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer);
break;
case SEPROXYHAL_TAG_STATUS_EVENT:
if ((G_io_apdu_media == IO_APDU_MEDIA_USB_HID) &&
!(U4BE(G_io_seproxyhal_spi_buffer, 3) &
SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) {
THROW(EXCEPTION_IO_RESET);
}
__attribute__((fallthrough));
case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
#ifdef HAVE_BAGL
UX_DISPLAYED_EVENT({});
#endif // HAVE_BAGL
#ifdef HAVE_NBGL
UX_DEFAULT_EVENT();
#endif // HAVE_NBGL
break;
#ifdef HAVE_NBGL
case SEPROXYHAL_TAG_FINGER_EVENT:
UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer);
break;
#endif // HAVE_NBGL
case SEPROXYHAL_TAG_TICKER_EVENT:
if (!G_display.low_cost_display_mode) {
app_ticker_event_callback();
UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {});
} else {
ux_screensaver_apply_tick();
}
break;
default:
UX_DEFAULT_EVENT();
break;
}

if (!io_seproxyhal_spi_is_status_sent()) {
io_seproxyhal_general_status();
}

return 1;
}

#endif // TARGET_NANOS

static void ui_refresh_idle_hwm_screen(void);

/**
Expand Down Expand Up @@ -68,7 +144,11 @@ void ui_menu_init(void); ///> Load main menu page
* - Exit screen
*
*/
#ifdef TARGET_NANOS
UX_STEP_CB(ux_app_is_ready_step, nn, ui_start_screensaver(), {"Application", "is ready"});
#else // TARGET_NANOS
UX_STEP_NOCB(ux_app_is_ready_step, nn, {"Application", "is ready"});
#endif // TARGET_NANOS
UX_STEP_NOCB(ux_version_step, bnnn_paging, {"Tezos Baking", APPVERSION});
UX_STEP_NOCB(ux_chain_id_step, bnnn_paging, {"Chain", home_context.chain_id});
UX_STEP_NOCB(ux_authorized_key_step, bnnn_paging, {"Public Key Hash", home_context.authorized_key});
Expand Down
121 changes: 121 additions & 0 deletions src/ui_screensaver.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/* Tezos Ledger application - Screen-saver UI functions
Copyright 2024 TriliTech <[email protected]>
Copyright 2024 Functori <[email protected]>
Copyright 2023 Ledger
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifdef HAVE_BAGL
#include "ui_screensaver.h"

#include "bolos_target.h"
#include "globals.h"

#define G_screensaver_state global.dynamic_display.screensaver_state

/**
* @brief Blank screen element
*
*/
static const bagl_element_t blank_screen_elements[] = {{{BAGL_RECTANGLE,
BAGL_NONE,
0,
0,
BAGL_WIDTH,
BAGL_HEIGHT,
0,
0,
BAGL_FILL,
0x000000,
0xFFFFFF,
0,
0},
.text = NULL},
{}};

/**
* @brief This structure represents the parameters needed for the blank layout
*
* No parameters required
*
*/
typedef struct ux_layout_blank_params_s {
} ux_layout_blank_params_t;

/**
* @brief Initializes the blank layout
*
* @param stack_slot: index stack_slot
*/
static void ux_layout_blank_init(unsigned int stack_slot) {
ux_stack_init(stack_slot);
G_ux.stack[stack_slot].element_arrays[0].element_array = blank_screen_elements;
G_ux.stack[stack_slot].element_arrays[0].element_array_count = ARRAYLEN(blank_screen_elements);
G_ux.stack[stack_slot].element_arrays_count = 1;
G_ux.stack[stack_slot].button_push_callback = ux_flow_button_callback;
ux_stack_display(stack_slot);
}

/**
* @brief Exits the blank screen to home screen
*
*/
static void return_to_idle(void) {
G_screensaver_state.on = false;
ui_initial_screen();
}

/**
* @brief Blank screen flow
*
* On any click: return_to_idle
*
*/
UX_STEP_CB(blank_screen_step, blank, return_to_idle(), {});
UX_STEP_INIT(blank_screen_border, NULL, NULL, { return_to_idle(); });
UX_FLOW(ux_blank_flow, &blank_screen_step, &blank_screen_border, FLOW_LOOP);

void ui_start_screensaver(void) {
if (!G_screensaver_state.on) {
G_screensaver_state.on = true;
ux_flow_init(0, ux_blank_flow, NULL);
}
}

#define MS 100u
#define SCREENSAVER_TIMEOUT 20000u // 20u * 10u * MS

void ux_screensaver_start_clock(void) {
G_screensaver_state.clock.on = true;
G_screensaver_state.clock.timeout = SCREENSAVER_TIMEOUT;
}

void ux_screensaver_stop_clock(void) {
G_screensaver_state.clock.on = false;
}

void ux_screensaver_apply_tick(void) {
if (G_screensaver_state.clock.on) {
if (G_screensaver_state.clock.timeout < MS) {
ui_start_screensaver();
ux_screensaver_stop_clock();
} else {
G_screensaver_state.clock.timeout -= MS;
}
}
}

#endif
70 changes: 70 additions & 0 deletions src/ui_screensaver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/* Tezos Ledger application - Screen-saver UI functions
Copyright 2024 TriliTech <[email protected]>
Copyright 2024 Functori <[email protected]>
Copyright 2023 Ledger
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once

#include <stdbool.h>

#ifdef HAVE_BAGL

typedef struct {
/// Clock has started
bool on;
/// Timeout out before saving screen
unsigned int timeout;
} ux_screensaver_clock_t;

typedef struct {
/// Screensaver is on/off.
bool on;
/// Timeout out before saving screen
ux_screensaver_clock_t clock;
} ux_screensaver_state_t;

/**
* @brief Empties the screen
*
* Waits a click to return to home screen
*
* Applies only for Nanos devices
*
*/
void ui_start_screensaver(void);

/**
* @brief Start a timeout before saving screen
*
*/
void ux_screensaver_start_clock(void);

/**
* @brief Stop the clock
*
*/
void ux_screensaver_stop_clock(void);

/**
* @brief Apply one tick to the clock
*
* The tick is assumed to be 100 ms
*
*/
void ux_screensaver_apply_tick(void);

#endif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 886946c

Please sign in to comment.