Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add NBGL use cases (settings and choice) and NVM management #97

Merged
merged 2 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.1.0] - 2023-10-06

### Changed

- Improving the settings use case in order to be able to use app settings parameters stored in NVM
- add a NBGL use case choice when a setting switch is toggled


## [2.0.0] - 2023-07-10

### Added
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ APPNAME = "Boilerplate"

# Application version
APPVERSION_M = 2
APPVERSION_N = 0
APPVERSION_N = 1
APPVERSION_P = 0
APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"

Expand Down
11 changes: 11 additions & 0 deletions src/app_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

global_ctx_t G_context;

const internal_storage_t N_storage_real;

/**
* Handle APDU command received and send back APDU response using handlers.
*/
Expand All @@ -46,6 +48,15 @@ void app_main() {
// Reset context
explicit_bzero(&G_context, sizeof(G_context));

// Initialize the NVM data if required
if (N_storage.initialized != 0x01) {
internal_storage_t storage;
storage.dummy1_allowed = 0x00;
storage.dummy2_allowed = 0x00;
storage.initialized = 0x01;
nvm_write((void *) &N_storage, &storage, sizeof(internal_storage_t));
}

for (;;) {
// Receive command bytes in G_io_apdu_buffer
if ((input_len = io_recv_command()) < 0) {
Expand Down
12 changes: 12 additions & 0 deletions src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,15 @@ extern bolos_ux_params_t G_ux_params;
* Global context for user requests.
*/
extern global_ctx_t G_context;

/**
* Global structure for NVM data storage.
*/
typedef struct internal_storage_t {
uint8_t dummy1_allowed;
uint8_t dummy2_allowed;
uint8_t initialized;
} internal_storage_t;

extern const internal_storage_t N_storage_real;
#define N_storage (*(volatile internal_storage_t *) PIC(&N_storage_real))
5 changes: 5 additions & 0 deletions src/ui/menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
*/
void ui_menu_main(void);

/**
* Show settings menu (App version, developer name and settings).
*/
void ui_menu_settings(void);

/**
* Show about submenu (copyright, date).
*/
Expand Down
118 changes: 104 additions & 14 deletions src/ui/menu_nbgl.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,46 +25,136 @@
#include "../globals.h"
#include "menu.h"

// -----------------------------------------------------------
// ----------------------- HOME PAGE -------------------------
// -----------------------------------------------------------

void app_quit(void) {
// exit app here
os_sched_exit(-1);
}

// home page definition
void ui_menu_main(void) {
#define SETTINGS_BUTTON_DISABLED (false)
// This parameter shall be set to false if the settings page contains only information
// about the application (version , developer name, ...). It shall be set to
// true if the settings page also contains user configurable parameters related to the
// operation of the application.
#define SETTINGS_BUTTON_ENABLED (true)

nbgl_useCaseHome(APPNAME,
&C_app_boilerplate_64px,
NULL,
SETTINGS_BUTTON_DISABLED,
ui_menu_about,
SETTINGS_BUTTON_ENABLED,
ui_menu_settings,
app_quit);
}

// 'About' menu
// -----------------------------------------------------------
// --------------------- SETTINGS MENU -----------------------
// -----------------------------------------------------------

static const char* const INFO_TYPES[] = {"Version", "Developer"};
static const char* const INFO_CONTENTS[] = {APPVERSION, "Ledger"};

// settings switches definitions
enum { DUMMY_SWITCH_1_TOKEN = FIRST_USER_TOKEN, DUMMY_SWITCH_2_TOKEN };
enum { DUMMY_SWITCH_1_ID = 0, DUMMY_SWITCH_2_ID, SETTINGS_SWITCHES_NB };

static nbgl_layoutSwitch_t switches[SETTINGS_SWITCHES_NB] = {0};

static bool nav_callback(uint8_t page, nbgl_pageContent_t* content) {
UNUSED(page);
content->type = INFOS_LIST;
content->infosList.nbInfos = 2;
content->infosList.infoTypes = (const char**) INFO_TYPES;
content->infosList.infoContents = (const char**) INFO_CONTENTS;

// the first settings page contains only the version and the developer name
// of the app (shall be always on the first setting page)
if (page == 0) {
content->type = INFOS_LIST;
content->infosList.nbInfos = 2;
content->infosList.infoTypes = INFO_TYPES;
content->infosList.infoContents = INFO_CONTENTS;
}
// the second settings page contains 2 toggle setting switches
else if (page == 1) {
switches[DUMMY_SWITCH_1_ID].initState = (nbgl_state_t) N_storage.dummy1_allowed;
switches[DUMMY_SWITCH_1_ID].text = "Dummy 1";
switches[DUMMY_SWITCH_1_ID].subText = "Allow dummy 1\nin transactions";
switches[DUMMY_SWITCH_1_ID].token = DUMMY_SWITCH_1_TOKEN;
switches[DUMMY_SWITCH_1_ID].tuneId = TUNE_TAP_CASUAL;

switches[DUMMY_SWITCH_2_ID].initState = (nbgl_state_t) N_storage.dummy2_allowed;
switches[DUMMY_SWITCH_2_ID].text = "Dummy 2";
switches[DUMMY_SWITCH_2_ID].subText = "Allow dummy 2\nin transactions";
switches[DUMMY_SWITCH_2_ID].token = DUMMY_SWITCH_2_TOKEN;
switches[DUMMY_SWITCH_2_ID].tuneId = TUNE_TAP_CASUAL;

content->type = SWITCHES_LIST;
content->switchesList.nbSwitches = SETTINGS_SWITCHES_NB;
content->switchesList.switches = (nbgl_layoutSwitch_t*) switches;
} else {
return false;
}
// valid page so return true
return true;
}

void ui_menu_about() {
#define TOTAL_PAGE_NB (1)
#define INIT_PAGE_INDEX (0)
// callback for setting warning choice
static void review_warning_choice(bool confirm) {
uint8_t switch_value;
if (confirm) {
// toggle the switch value
switch_value = !N_storage.dummy2_allowed;
// store the new setting value in NVM
nvm_write((void*) &N_storage.dummy2_allowed, &switch_value, 1);
}

// return to the settings menu
ui_menu_settings();
tdejoigny-ledger marked this conversation as resolved.
Show resolved Hide resolved
}

static void controls_callback(int token, uint8_t index) {
UNUSED(index);
uint8_t switch_value;
if (token == DUMMY_SWITCH_1_TOKEN) {
// Dummy 1 switch touched
// toggle the switch value
switch_value = !N_storage.dummy1_allowed;
// store the new setting value in NVM
nvm_write((void*) &N_storage.dummy1_allowed, &switch_value, 1);
} else if (token == DUMMY_SWITCH_2_TOKEN) {
// Dummy 2 switch touched

// in this example we display a warning when the user wants
// to activate the dummy 2 setting
if (!N_storage.dummy2_allowed) {
// Display the warning message and ask the user to confirm
nbgl_useCaseChoice(&C_warning64px,
"Dummy 2",
"Are you sure to\nallow dummy 2\nin transactions?",
"I understand, confirm",
"Cancel",
review_warning_choice);
} else {
// toggle the switch value
switch_value = !N_storage.dummy2_allowed;
// store the new setting value in NVM
nvm_write((void*) &N_storage.dummy2_allowed, &switch_value, 1);
}
}
}

// settings menu definition
void ui_menu_settings() {
#define TOTAL_SETTINGS_PAGE (2)
#define INIT_SETTINGS_PAGE (0)
#define DISABLE_SUB_SETTINGS (false)
nbgl_useCaseSettings(APPNAME,
INIT_PAGE_INDEX,
TOTAL_PAGE_NB,
INIT_SETTINGS_PAGE,
TOTAL_SETTINGS_PAGE,
DISABLE_SUB_SETTINGS,
ui_menu_main,
nav_callback,
NULL);
controls_callback);
}

#endif
Binary file modified tests/snapshots/nanos/test_app_mainmenu/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/nanosp/test_app_mainmenu/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/nanox/test_app_mainmenu/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_app_mainmenu/00000.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_app_mainmenu/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_app_mainmenu/00002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/stax/test_app_mainmenu/00003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/stax/test_app_mainmenu/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/stax/test_app_mainmenu/00005.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/stax/test_app_mainmenu/00006.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/stax/test_app_mainmenu/00007.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/stax/test_app_mainmenu/00008.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/stax/test_app_mainmenu/00009.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/stax/test_app_mainmenu/00010.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_get_public_key_confirm_accepted/00005.png
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.
Binary file modified tests/snapshots/stax/test_sign_tx_long_tx/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_sign_tx_refused/part0/00003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_sign_tx_refused/part1/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_sign_tx_refused/part2/00005.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/snapshots/stax/test_sign_tx_short_tx/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 11 additions & 3 deletions tests/test_app_mainmenu.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ragger.navigator import NavInsID
from ragger.navigator import NavInsID, NavIns

from utils import ROOT_SCREENSHOT_PATH

Expand All @@ -14,8 +14,16 @@ def test_app_mainmenu(firmware, navigator, test_name):
]
else:
instructions = [
NavInsID.USE_CASE_HOME_INFO,
NavInsID.USE_CASE_SETTINGS_SINGLE_PAGE_EXIT
NavInsID.USE_CASE_HOME_SETTINGS,
NavInsID.USE_CASE_SETTINGS_NEXT,
NavIns(NavInsID.TOUCH, (200, 113)),
NavIns(NavInsID.TOUCH, (200, 261)),
NavInsID.USE_CASE_CHOICE_CONFIRM,
NavInsID.USE_CASE_SETTINGS_NEXT,
NavIns(NavInsID.TOUCH, (200, 261)),
NavIns(NavInsID.TOUCH, (200, 261)),
NavInsID.USE_CASE_CHOICE_REJECT,
NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT
]
navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, instructions,
screen_change_before_first_instruction=False)
2 changes: 1 addition & 1 deletion tests/test_name_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ def test_get_app_and_version(backend, backend_name):
app_name, version = unpack_get_app_and_version_response(response.data)

assert app_name == "Boilerplate"
assert version == "2.0.0"
assert version == "2.1.0"
2 changes: 1 addition & 1 deletion tests/test_version_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# Taken from the Makefile, to update every time the Makefile version is bumped
MAJOR = 2
MINOR = 0
MINOR = 1
PATCH = 0

# In this test we check the behavior of the device when asked to provide the app version
Expand Down
Loading