diff --git a/Makefile b/Makefile index 5b445a34..ca5f5510 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ show-app: ############ DEFINES += OS_IO_SEPROXYHAL -DEFINES += HAVE_BAGL HAVE_SPRINTF +DEFINES += HAVE_BAGL HAVE_SPRINTF HAVE_UX_FLOW DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=6 IO_HID_EP_LENGTH=64 HAVE_USB_APDU DEFINES += HAVE_LEGACY_PID DEFINES += VERSION=\"$(APPVERSION)\" APPVERSION_M=$(APPVERSION_M) @@ -73,7 +73,7 @@ DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300 DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 DEFINES += HAVE_BLE_APDU # basic ledger apdu transport over BLE -DEFINES += HAVE_GLO096 HAVE_UX_FLOW +DEFINES += HAVE_GLO096 DEFINES += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64 DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX @@ -81,7 +81,6 @@ DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl -SDK_SOURCE_PATH += lib_ux else DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128 endif @@ -144,7 +143,7 @@ include $(BOLOS_SDK)/Makefile.glyphs ### computed variables APP_SOURCE_PATH += src -SDK_SOURCE_PATH += lib_stusb lib_stusb_impl +SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_ux ### U2F support (wallet app only) ifeq ($(APP), tezos_wallet) diff --git a/src/apdu.c b/src/apdu.c index 88491705..e4b5e9fa 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -42,6 +42,7 @@ void main_loop(apdu_handler const *const handlers, size_t const handlers_size) { while (true) { BEGIN_TRY { TRY { + PRINTF("New APDU received:\n%.*H\n", rx, G_io_apdu_buffer); // Process APDU of size rx if (rx == 0) { diff --git a/src/globals.c b/src/globals.c index 8115caef..88839a68 100644 --- a/src/globals.c +++ b/src/globals.c @@ -3,9 +3,7 @@ #include "exception.h" #include "to_string.h" -#ifdef TARGET_NANOX #include "ux.h" -#endif #include @@ -21,12 +19,8 @@ globals_t global; // These are strange variables that the SDK relies on us to define but uses directly itself. -#ifdef TARGET_NANOX - ux_state_t G_ux; - bolos_ux_params_t G_ux_params; -#else - ux_state_t ux; -#endif +ux_state_t G_ux; +bolos_ux_params_t G_ux_params; unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; @@ -37,12 +31,8 @@ void clear_apdu_globals(void) { void init_globals(void) { memset(&global, 0, sizeof(global)); -#ifdef TARGET_NANOX memset(&G_ux, 0, sizeof(G_ux)); memset(&G_ux_params, 0, sizeof(G_ux_params)); -#else - memset(&ux, 0, sizeof(ux)); -#endif memset(G_io_seproxyhal_spi_buffer, 0, sizeof(G_io_seproxyhal_spi_buffer)); } @@ -51,11 +41,8 @@ void init_globals(void) { // DO NOT TRY TO INIT THIS. This can only be written via an system call. // The "N_" is *significant*. It tells the linker to put this in NVRAM. -# ifdef TARGET_NANOX - nvram_data const N_data_real; -# else - nvram_data N_data_real; -# endif +nvram_data const N_data_real; + high_watermark_t volatile *select_hwm_by_chain(chain_id_t const chain_id, nvram_data volatile *const ram) { check_null(ram); @@ -65,14 +52,10 @@ high_watermark_t volatile *select_hwm_by_chain(chain_id_t const chain_id, nvram_ } void calculate_baking_idle_screens_data(void) { -# ifdef TARGET_NANOX memset(global.ui.baking_idle_screens.hwm, 0, sizeof(global.ui.baking_idle_screens.hwm)); static char const HWM_PREFIX[] = "HWM: "; strcpy(global.ui.baking_idle_screens.hwm, HWM_PREFIX); number_to_string(&global.ui.baking_idle_screens.hwm[sizeof(HWM_PREFIX) - 1], (level_t const)N_data.hwm.main.highest_level); -# else - number_to_string(global.ui.baking_idle_screens.hwm, N_data.hwm.main.highest_level); -# endif if (N_data.baking_key.bip32_path.length == 0) { STRCPY(global.ui.baking_idle_screens.pkh, "No Key Authorized"); @@ -85,19 +68,15 @@ void calculate_baking_idle_screens_data(void) { (derivation_type_t const)N_data.baking_key.derivation_type, pubkey); } -# ifdef TARGET_NANOX if (N_data.main_chain_id.v == 0) { strcpy(global.ui.baking_idle_screens.chain, "Chain: any"); } else { -# endif chain_id_to_string_with_aliases( global.ui.baking_idle_screens.chain, sizeof(global.ui.baking_idle_screens.chain), (chain_id_t const *const)&N_data.main_chain_id); -# ifdef TARGET_NANOX } -# endif } void update_baking_idle_screens(void) { diff --git a/src/globals.h b/src/globals.h index e2c1ab81..e9470f88 100644 --- a/src/globals.h +++ b/src/globals.h @@ -75,12 +75,10 @@ typedef struct { ui_callback_t ok_callback; ui_callback_t cxl_callback; -# ifndef TARGET_NANOX uint32_t ux_step; uint32_t ux_step_count; uint32_t timeout_cycle_count; -# endif # ifdef BAKING_APP struct { @@ -94,18 +92,10 @@ typedef struct { string_generation_callback callbacks[MAX_SCREEN_COUNT]; const void *callback_data[MAX_SCREEN_COUNT]; -# ifdef TARGET_NANOX - struct { + struct { char prompt[PROMPT_WIDTH + 1]; char value[VALUE_WIDTH + 1]; - } screen[MAX_SCREEN_COUNT]; -# else - char active_prompt[PROMPT_WIDTH + 1]; - char active_value[VALUE_WIDTH + 1]; - - // This will and must always be static memory full of constants - const char *const *prompts; -# endif + } screen[MAX_SCREEN_COUNT]; } prompt; } ui; @@ -159,12 +149,8 @@ extern globals_t global; extern unsigned int app_stack_canary; // From SDK // Used by macros that we don't control. -#ifdef TARGET_NANOX - extern ux_state_t G_ux; - extern bolos_ux_params_t G_ux_params; -#else - extern ux_state_t ux; -#endif +// extern ux_state_t G_ux; +// extern bolos_ux_params_t G_ux_params; extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; static inline void throw_stack_size() { @@ -175,13 +161,9 @@ static inline void throw_stack_size() { } #ifdef BAKING_APP -# ifdef TARGET_NANOX - extern nvram_data const N_data_real; -# define N_data (*(volatile nvram_data *)PIC(&N_data_real)) -# else - extern nvram_data N_data_real; -# define N_data (*(nvram_data*)PIC(&N_data_real)) -# endif +extern nvram_data const N_data_real; +#define N_data (*(volatile nvram_data *)PIC(&N_data_real)) + void calculate_baking_idle_screens_data(void); void update_baking_idle_screens(void); diff --git a/src/ui_common.c b/src/ui_common.c index c4f016b7..b0c54945 100644 --- a/src/ui_common.c +++ b/src/ui_common.c @@ -28,11 +28,6 @@ void require_pin(void) { __attribute__((noreturn)) bool exit_app(void) { -# ifdef BAKING_APP -# ifndef TARGET_NANOX - require_pin(); -# endif -# endif BEGIN_TRY_L(exit) { TRY_L(exit) { os_sched_exit(-1); diff --git a/src/ui_nano_s.c b/src/ui_nano_s.c deleted file mode 100644 index 7e4e01cb..00000000 --- a/src/ui_nano_s.c +++ /dev/null @@ -1,354 +0,0 @@ -#include "bolos_target.h" - -#ifndef TARGET_NANOX - -#include "ui.h" - -#include "baking_auth.h" -#include "exception.h" -#include "globals.h" -#include "glyphs.h" // ui-menu -#include "keys.h" -#include "memory.h" -#include "os_cx.h" // ui-menu -#include "to_string.h" - -#include -#include - - -#define G global.ui - -void ui_refresh(void) { - // DO NOTHING -} - -// CALLED BY THE SDK -unsigned char io_event(unsigned char channel); -void io_seproxyhal_display(const bagl_element_t *element); - - -static void ui_display(const bagl_element_t *elems, size_t sz, ui_callback_t ok_c, ui_callback_t cxl_c, - uint32_t step_count); - - -// ----------------------------- ui_prompt -// This is called by internal UI code to implement buffering -static void switch_screen(uint32_t which); -// This is called by internal UI code to prevent callbacks from sticking around -static void clear_ui_callbacks(void); - -#ifndef BAKING_APP -// ------------------------------- ui_meno -static void main_menu(void); -#endif - -static unsigned button_handler(unsigned button_mask, unsigned button_mask_counter); - -#define PROMPT_CYCLES 3 - -#ifdef BAKING_APP -static const bagl_element_t ui_idle_screen[] = { - // type userid x y w h str rad - // fill fg bg fid iid txt touchparams... ] - {{BAGL_RECTANGLE, 0x00, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0x000000, 0xFFFFFF, - 0, 0}, - NULL }, - - {{BAGL_ICON, 0x00, 3, 12, 7, 7, 0, 0, 0, 0xFFFFFF, 0x000000, 0, - BAGL_GLYPH_ICON_CROSS}, - NULL }, - - //{{BAGL_ICON , 0x01, 21, 9, 14, 14, 0, 0, 0 - //, 0xFFFFFF, 0x000000, 0, BAGL_GLYPH_ICON_TRANSACTION_BADGE }, NULL, 0, 0, - //0, NULL, NULL, NULL }, - {{BAGL_LABELINE, 0x01, 0, 12, 128, 12, 0, 0, 0, 0xFFFFFF, 0x000000, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 0}, - "Last Block Level" }, - - {{BAGL_LABELINE, 0x01, 0, 26, 128, 12, 0, 0, 0, 0xFFFFFF, 0x000000, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 0}, - G.baking_idle_screens.hwm }, - - {{BAGL_LABELINE, 0x02, 0, 12, 128, 12, 0, 0, 0, 0xFFFFFF, 0x000000, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 0}, - "Baking Key" }, - - {{BAGL_LABELINE, 0x02, 23, 26, 82, 12, 0x80 | 10, 0, 0, 0xFFFFFF, 0x000000, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 26}, - G.baking_idle_screens.pkh }, - - {{BAGL_LABELINE, 0x03, 0, 12, 128, 12, 0, 0, 0, 0xFFFFFF, 0x000000, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 0}, - "Chain" }, - - {{BAGL_LABELINE, 0x03, 23, 26, 82, 12, 0x80 | 10, 0, 0, 0xFFFFFF, 0x000000, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 26}, - G.baking_idle_screens.chain }, - -}; - -static bool do_nothing(void) { - return false; -} -#endif - -static void ui_idle(void) { -# ifdef BAKING_APP - update_baking_idle_screens(); - ui_display( - ui_idle_screen, NUM_ELEMENTS(ui_idle_screen), - do_nothing, exit_app, 3); -# else - G.cxl_callback = exit_app; - main_menu(); -# endif -} - -void ui_initial_screen(void) { -# ifdef BAKING_APP - update_baking_idle_screens(); -# endif - clear_ui_callbacks(); - ui_idle(); -} - -static bool is_idling(void) { - return G.cxl_callback == exit_app; -} - -static void timeout(void) { - if (is_idling()) { - // Idle app timeout -# ifdef BAKING_APP - update_baking_idle_screens(); -# endif - G.timeout_cycle_count = 0; - UX_REDISPLAY(); - } else { - // Prompt timeout -- simulate cancel button - (void) button_handler(BUTTON_EVT_RELEASED | BUTTON_LEFT, 0); - } -} - -static unsigned button_handler(unsigned button_mask, __attribute__((unused)) unsigned button_mask_counter) { - ui_callback_t callback; - switch (button_mask) { - case BUTTON_EVT_RELEASED | BUTTON_LEFT: - callback = G.cxl_callback; - break; - case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - callback = G.ok_callback; - break; - default: - return 0; - } - if (callback()) { - clear_ui_callbacks(); - ui_idle(); - } - return 0; -} - -const bagl_element_t *prepro(const bagl_element_t *element) { - if (element->component.userid == BAGL_STATIC_ELEMENT) return element; - - static const uint32_t pause_millis = 1500; - uint32_t min = 2000; - static const uint32_t div = 2; - - if (is_idling()) { - min = 4000; - } - - if (G.ux_step == element->component.userid - 1 || element->component.userid == BAGL_SCROLLING_ELEMENT) { - // timeouts are in millis - UX_CALLBACK_SET_INTERVAL(MAX(min, - (pause_millis + bagl_label_roundtrip_duration_ms(element, 7)) / div)); - return element; - } else { - return NULL; - } -} - -void ui_display(const bagl_element_t *elems, size_t sz, ui_callback_t ok_c, ui_callback_t cxl_c, - uint32_t step_count) { - // Adapted from definition of UX_DISPLAY in header file - G.timeout_cycle_count = 0; - G.ux_step = 0; - G.ux_step_count = step_count; - G.ok_callback = ok_c; - G.cxl_callback = cxl_c; - if (!is_idling()) { - switch_screen(0); - } -// TODO: Upgrade the nano-sdk to the master branch, and upgrade legacy ui functions -/* #if CX_APILEVEL < 10 */ - ux.elements = elems; - ux.elements_count = sz; - ux.button_push_handler = button_handler; - ux.elements_preprocessor = prepro; -/* #else */ -/* ux.stack[0].element_arrays[0].element_array = elems; */ -/* ux.stack[0].element_arrays[0].element_array_count = sz; */ -/* ux.stack[0].element_arrays_count=1; */ -/* ux.stack[0].button_push_callback = button_handler; */ -/* G_ux.stack[0].screen_before_element_display_callback = prepro; */ -/* #endif */ - UX_WAKE_UP(); - UX_REDISPLAY(); -} - -unsigned char io_event(__attribute__((unused)) unsigned char channel) { - // nothing done with the event, throw an error on the transport layer if - // needed - - // can't have more than one tag in the reply, not supported yet. - switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; - - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); - break; - - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: - UX_DISPLAYED_EVENT({}); - break; - - case SEPROXYHAL_TAG_TICKER_EVENT: - if (ux.callback_interval_ms != 0) { - ux.callback_interval_ms -= MIN(ux.callback_interval_ms, 100u); - if (ux.callback_interval_ms == 0) { - // prepare next screen - G.ux_step = (G.ux_step + 1) % G.ux_step_count; - if (!is_idling()) { - switch_screen(G.ux_step); - } - - // check if we've timed out - if (G.ux_step == 0) { - G.timeout_cycle_count++; - if (G.timeout_cycle_count == PROMPT_CYCLES) { - timeout(); - break; // timeout() will often display a new screen - } - } - - // redisplay screen - UX_REDISPLAY(); - } - } - break; - default: - // unknown events are acknowledged - break; - } - - // close the event if not done previously (by a display or whatever) - if (!io_seproxyhal_spi_is_status_sent()) { - io_seproxyhal_general_status(); - } - // command has been processed, DO NOT reset the current APDU transport - // TODO: I don't understand that comment or what this return value means - return 1; -} - - -#pragma mark uiprompt - -static const bagl_element_t ui_multi_screen[] = { - {{BAGL_RECTANGLE, BAGL_STATIC_ELEMENT, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0x000000, 0xFFFFFF, - 0, 0}, - NULL }, - - {{BAGL_ICON, BAGL_STATIC_ELEMENT, 3, 12, 7, 7, 0, 0, 0, 0xFFFFFF, 0x000000, 0, - BAGL_GLYPH_ICON_CROSS}, - NULL }, - - {{BAGL_ICON, BAGL_STATIC_ELEMENT, 117, 13, 8, 6, 0, 0, 0, 0xFFFFFF, 0x000000, 0, - BAGL_GLYPH_ICON_CHECK}, - NULL }, - - {{BAGL_LABELINE, BAGL_STATIC_ELEMENT, 0, 12, 128, 12, 0, 0, 0, 0xFFFFFF, 0x000000, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 0}, - global.ui.prompt.active_prompt }, - - {{BAGL_LABELINE, BAGL_SCROLLING_ELEMENT, 23, 26, 82, 12, 0x80 | 10, 0, 0, 0xFFFFFF, 0x000000, - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 26}, - global.ui.prompt.active_value }, -}; - -void switch_screen(uint32_t which) { - if (which >= MAX_SCREEN_COUNT) THROW(EXC_MEMORY_ERROR); - const char *label = (const char*)PIC(global.ui.prompt.prompts[which]); - - strncpy(global.ui.prompt.active_prompt, label, sizeof(global.ui.prompt.active_prompt)); - if (global.ui.prompt.callbacks[which] == NULL) THROW(EXC_MEMORY_ERROR); - global.ui.prompt.callbacks[which]( - global.ui.prompt.active_value, sizeof(global.ui.prompt.active_value), - global.ui.prompt.callback_data[which]); -} - -void clear_ui_callbacks(void) { - for (int i = 0; i < MAX_SCREEN_COUNT; ++i) { - global.ui.prompt.callbacks[i] = NULL; - } -} - -__attribute__((noreturn)) -void ui_prompt(const char *const *labels, ui_callback_t ok_c, ui_callback_t cxl_c) { - check_null(labels); - global.ui.prompt.prompts = labels; - - size_t i; - for (i = 0; labels[i] != NULL; i++) { - const char *label = (const char *)PIC(labels[i]); - if (i >= MAX_SCREEN_COUNT || strlen(label) > PROMPT_WIDTH) THROW(EXC_MEMORY_ERROR); - } - size_t screen_count = i; - - ui_display(ui_multi_screen, NUM_ELEMENTS(ui_multi_screen), - ok_c, cxl_c, screen_count); -#ifdef DEBUG - // In debug mode, the THROW below produces a PRINTF statement in an invalid position and causes the screen to blank, so instead we just directly call the equivalent longjmp for debug only. - longjmp(try_context_get()->jmp_buf, ASYNC_EXCEPTION); -#else - THROW(ASYNC_EXCEPTION); -#endif -} - - -#pragma mark ui_menu - - -#ifndef BAKING_APP - -void exit_app_cb(__attribute__((unused)) unsigned int cb) { - exit_app(); -} - -// Mutually recursive static variables require forward declarations -static const ux_menu_entry_t main_menu_data[]; -static const ux_menu_entry_t about_menu_data[]; - -static const ux_menu_entry_t about_menu_data[] = { - {NULL, NULL, 0, NULL, "Tezos Wallet", "Version " VERSION, 0, 0}, - {main_menu_data, NULL, 1, &C_icon_back, "Back", NULL, 61, 40}, // TODO: Put icon for "back" in - UX_MENU_END -}; - -static const ux_menu_entry_t main_menu_data[] = { - {NULL, NULL, 0, NULL, "Use wallet to", "view accounts", 0, 0}, - {about_menu_data, NULL, 0, NULL, "About", NULL, 0, 0}, - {NULL, exit_app_cb, 0, &C_icon_dashboard, "Quit app", NULL, 50, 29}, // TODO: Put icon for "dashboard" in - UX_MENU_END -}; - -void main_menu() { - UX_MENU_DISPLAY(0, main_menu_data, NULL); -} -#endif // #ifdef BAKING_APP - -#endif // #ifndef TARGET_NANOX diff --git a/src/ui_nano_x.c b/src/ui_nano_x.c index 079efb49..92cc8a1a 100644 --- a/src/ui_nano_x.c +++ b/src/ui_nano_x.c @@ -1,7 +1,5 @@ #include "bolos_target.h" -#ifdef TARGET_NANOX - #include "ui.h" #include "baking_auth.h" @@ -132,7 +130,7 @@ UX_FLOW(ux_idle_flow, #define PROMPT_SCREEN_NAME(idx) ux_prompt_flow_ ## idx ## _step #define PROMPT_SCREEN_TPL(idx) \ UX_STEP_NOCB( \ - PROMPT_SCREEN_NAME(idx), \ + ux_prompt_flow_## idx ## _step, \ bnnn_paging, \ { \ .title = G.prompt.screen[idx].prompt, \ @@ -226,5 +224,3 @@ void ui_prompt(const char *const *labels, ui_callback_t ok_c, ui_callback_t cxl_ ux_flow_init(0, &ux_prompts_flow[offset], NULL); THROW(ASYNC_EXCEPTION); } - -#endif // #ifdef TARGET_NANOX