From 621b9be087fd2dc3fed50f1e1a1cbb22899e7232 Mon Sep 17 00:00:00 2001 From: Nicolas Roggeman Date: Thu, 12 Sep 2024 14:13:20 +0200 Subject: [PATCH] Use different touch contexts for App & UX --- lib_nbgl/include/nbgl_obj.h | 1 + lib_nbgl/include/nbgl_touch.h | 11 +-- lib_nbgl/src/nbgl_fonts.c | 5 +- lib_nbgl/src/nbgl_obj.c | 29 +++++++- lib_nbgl/src/nbgl_screen.c | 2 +- lib_nbgl/src/nbgl_touch.c | 109 +++++++++++++++++----------- lib_ux_nbgl/ux.c | 4 +- unit-tests/lib_nbgl/test_nbgl_obj.c | 3 +- 8 files changed, 110 insertions(+), 54 deletions(-) diff --git a/lib_nbgl/include/nbgl_obj.h b/lib_nbgl/include/nbgl_obj.h index 89b37ef3e..f678c1a70 100644 --- a/lib_nbgl/include/nbgl_obj.h +++ b/lib_nbgl/include/nbgl_obj.h @@ -578,6 +578,7 @@ void nbgl_objInit(void); void nbgl_objDraw(nbgl_obj_t *obj); void nbgl_objAllowDrawing(bool enable); uint8_t *nbgl_objGetRAMBuffer(void); +bool nbgl_objIsUx(nbgl_obj_t *obj); void nbgl_objPoolRelease(uint8_t layer); nbgl_obj_t *nbgl_objPoolGet(nbgl_obj_type_t type, uint8_t layer); diff --git a/lib_nbgl/include/nbgl_touch.h b/lib_nbgl/include/nbgl_touch.h index 03e95df84..341dbb8a2 100644 --- a/lib_nbgl/include/nbgl_touch.h +++ b/lib_nbgl/include/nbgl_touch.h @@ -23,7 +23,7 @@ extern "C" { // duration of a short touch on touch panel (in ms) #define SHORT_TOUCH_DURATION 0 // duration of a long touch on touch panel (in ms) -#define LONG_TOUCH_DURATION 1500 +#define LONG_TOUCH_DURATION 3000 /********************** * TYPEDEFS **********************/ @@ -31,10 +31,11 @@ extern "C" { /********************** * GLOBAL PROTOTYPES **********************/ -void nbgl_touchHandler(nbgl_touchStatePosition_t *touchEvent, uint32_t currentTimeMs); -bool nbgl_touchGetTouchedPosition(nbgl_obj_t *obj, - nbgl_touchStatePosition_t **firstPos, - nbgl_touchStatePosition_t **lastPos); +void nbgl_touchInit(bool fromUx); +void nbgl_touchHandler(bool fromUx, nbgl_touchStatePosition_t *touchEvent, uint32_t currentTimeMs); +bool nbgl_touchGetTouchedPosition(nbgl_obj_t *obj, + nbgl_touchStatePosition_t **firstPos, + nbgl_touchStatePosition_t **lastPos); uint32_t nbgl_touchGetTouchDuration(nbgl_obj_t *obj); nbgl_obj_t *nbgl_touchGetObjectFromId(nbgl_obj_t *obj, uint8_t id); diff --git a/lib_nbgl/src/nbgl_fonts.c b/lib_nbgl/src/nbgl_fonts.c index c354118b6..d265428ca 100644 --- a/lib_nbgl/src/nbgl_fonts.c +++ b/lib_nbgl/src/nbgl_fonts.c @@ -66,12 +66,13 @@ static const LANGUAGE_PACK *language_pack; #include "nbgl_font_open_sans_light_16.inc" #endif // SCREEN_SIZE_WALLET -const nbgl_font_t *const C_nbgl_fonts[] = { +__attribute__((section("._nbgl_fonts_"))) const nbgl_font_t *const C_nbgl_fonts[] = { #include "nbgl_font_rom_struct.inc" }; -const unsigned int C_nbgl_fonts_count = sizeof(C_nbgl_fonts) / sizeof(C_nbgl_fonts[0]); +__attribute__((section("._nbgl_fonts_"))) const unsigned int C_nbgl_fonts_count + = sizeof(C_nbgl_fonts) / sizeof(C_nbgl_fonts[0]); #if (defined(HAVE_BOLOS) && !defined(BOLOS_OS_UPGRADER_APP)) #if !defined(HAVE_LANGUAGE_PACK) diff --git a/lib_nbgl/src/nbgl_obj.c b/lib_nbgl/src/nbgl_obj.c index 717ccda2c..318aac79d 100644 --- a/lib_nbgl/src/nbgl_obj.c +++ b/lib_nbgl/src/nbgl_obj.c @@ -14,6 +14,7 @@ #include "nbgl_front.h" #include "nbgl_debug.h" #include "nbgl_screen.h" +#include "nbgl_touch.h" #include "os_print.h" #include "os_helpers.h" #include "os_pic.h" @@ -1629,12 +1630,17 @@ void nbgl_refreshReset(void) /** * @brief This functions inits all internal of nbgl objects layer + * @note it is supposed to be called only from App * */ void nbgl_objInit(void) { // init area to the smallest size nbgl_refreshReset(); + objDrawingDisabled = false; +#ifdef HAVE_SE_TOUCH + nbgl_touchInit(false); +#endif } /** @@ -1650,9 +1656,30 @@ void nbgl_objAllowDrawing(bool enable) /** * @brief This function is used to get the all purpose RAM buffer * - * @param enable if true, enables drawing/refresh, otherwise disables + * @return a pointer to the all purpose RAM buffer */ uint8_t *nbgl_objGetRAMBuffer(void) { return ramBuffer; } + +/** + * @brief This function returns true if the object belongs to a UxScreen + * + * @return true if the object belongs to a UxScreen + */ +bool nbgl_objIsUx(nbgl_obj_t *obj) +{ + nbgl_obj_t *parent = obj; + // search screen in parenthood + while (parent->parent != NULL) { + parent = parent->parent; + } + if (parent->type == SCREEN) { + return (((nbgl_screen_t *) parent)->isUxScreen); + } + else { + // should never happen + return true; + } +} diff --git a/lib_nbgl/src/nbgl_screen.c b/lib_nbgl/src/nbgl_screen.c index ba07911b4..ce6fb4f87 100644 --- a/lib_nbgl/src/nbgl_screen.c +++ b/lib_nbgl/src/nbgl_screen.c @@ -368,7 +368,7 @@ int nbgl_screenPush(nbgl_obj_t ***elements, nbgl_touchStatePosition_t touchStatePosition = {.state = RELEASED, .x = 0, .y = 0}; // make a fake touch release for the current top-of-stack to avoid issue // (for example in long-touch press) - nbgl_touchHandler(&touchStatePosition, 0); + nbgl_touchHandler(topOfStack->isUxScreen, &touchStatePosition, 0); #endif // HAVE_SE_TOUCH // new top of stack topOfStack = &screenStack[screenIndex]; diff --git a/lib_nbgl/src/nbgl_touch.c b/lib_nbgl/src/nbgl_touch.c index 1e6881f8d..b2f2c25a1 100644 --- a/lib_nbgl/src/nbgl_touch.c +++ b/lib_nbgl/src/nbgl_touch.c @@ -20,10 +20,23 @@ /********************* * DEFINES *********************/ +enum { + UX_CTX = 0, + APP_CTX, + NB_CTXS +}; /********************** * TYPEDEFS **********************/ +typedef struct nbgl_touchCtx_s { + nbgl_touchState_t lastState; + uint32_t lastPressedTime; + uint32_t lastCurrentTime; + nbgl_obj_t *lastPressedObj; + nbgl_touchStatePosition_t firstTouchedPosition; + nbgl_touchStatePosition_t lastTouchedPosition; +} nbgl_touchCtx_t; /********************** * STATIC PROTOTYPES @@ -32,10 +45,7 @@ /********************** * STATIC VARIABLES **********************/ -static uint32_t lastPressedTime = 0; -static uint32_t lastCurrentTime = 0; -static nbgl_obj_t *lastPressedObj = NULL; -static nbgl_touchStatePosition_t firstTouchedPosition, lastTouchedPosition; +static nbgl_touchCtx_t touchCtxs[NB_CTXS]; /********************** * VARIABLES @@ -255,29 +265,41 @@ static nbgl_touchType_t nbgl_detectSwipe(nbgl_touchStatePosition_t *last, /********************** * GLOBAL FUNCTIONS **********************/ +/** + * @brief Function to initialize the touch context + * @param fromUx if true, means to initialize the UX context, otherwise App one + */ +void nbgl_touchInit(bool fromUx) +{ + nbgl_touchCtx_t *ctx = fromUx ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX]; + memset(ctx, 0, sizeof(nbgl_touchCtx_t)); +} /** * @brief Function to be called periodically to check touchscreen state * and coordinates + * @param fromUx if true, means this is called from the UX, not the App * @param touchStatePosition state and position read from touch screen * @param currentTime current time in ms */ -void nbgl_touchHandler(nbgl_touchStatePosition_t *touchStatePosition, uint32_t currentTime) +void nbgl_touchHandler(bool fromUx, + nbgl_touchStatePosition_t *touchStatePosition, + uint32_t currentTime) { - static nbgl_touchState_t lastState = RELEASED; - nbgl_obj_t *foundObj; + nbgl_obj_t *foundObj; + nbgl_touchCtx_t *ctx = fromUx ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX]; // save last received currentTime - lastCurrentTime = currentTime; + ctx->lastCurrentTime = currentTime; - if (lastState == RELEASED) { + if (ctx->lastState == RELEASED) { // filter out not realistic cases (successive RELEASE events) if (RELEASED == touchStatePosition->state) { - lastState = touchStatePosition->state; + ctx->lastState = touchStatePosition->state; return; } // memorize first touched position - memcpy(&firstTouchedPosition, touchStatePosition, sizeof(nbgl_touchStatePosition_t)); + memcpy(&ctx->firstTouchedPosition, touchStatePosition, sizeof(nbgl_touchStatePosition_t)); } // LOG_DEBUG(TOUCH_LOGGER,"state = %s, x = %d, y=%d\n",(touchStatePosition->state == // RELEASED)?"RELEASED":"PRESSED",touchStatePosition->x,touchStatePosition->y); @@ -289,86 +311,88 @@ void nbgl_touchHandler(nbgl_touchStatePosition_t *touchStatePosition, uint32_t c // foundObj->type); if (foundObj == NULL) { LOG_DEBUG(TOUCH_LOGGER, "nbgl_touchHandler: no found obj\n"); - if ((touchStatePosition->state == PRESSED) && (lastState == PRESSED) - && (lastPressedObj != NULL)) { + if ((touchStatePosition->state == PRESSED) && (ctx->lastState == PRESSED) + && (ctx->lastPressedObj != NULL)) { // finger has moved out of an object // make sure lastPressedObj still belongs to current screen before warning it - if (nbgl_screenContainsObj(lastPressedObj)) { - applytouchStatePosition(lastPressedObj, OUT_OF_TOUCH); + if (nbgl_screenContainsObj(ctx->lastPressedObj)) { + applytouchStatePosition(ctx->lastPressedObj, OUT_OF_TOUCH); } } // Released event has been handled, forget lastPressedObj - lastPressedObj = NULL; + ctx->lastPressedObj = NULL; } // memorize last touched position - memcpy(&lastTouchedPosition, touchStatePosition, sizeof(nbgl_touchStatePosition_t)); + memcpy(&ctx->lastTouchedPosition, touchStatePosition, sizeof(nbgl_touchStatePosition_t)); if (touchStatePosition->state == RELEASED) { - nbgl_touchType_t swipe = nbgl_detectSwipe(touchStatePosition, &firstTouchedPosition); + nbgl_touchType_t swipe = nbgl_detectSwipe(touchStatePosition, &ctx->firstTouchedPosition); bool consumed = false; if (swipe != NB_TOUCH_TYPES) { // Swipe detected nbgl_obj_t *swipedObj = getSwipableObject( - nbgl_screenGetTop(), &firstTouchedPosition, &lastTouchedPosition, swipe); + nbgl_screenGetTop(), &ctx->firstTouchedPosition, &ctx->lastTouchedPosition, swipe); // if a swipable object has been found if (swipedObj) { applytouchStatePosition(swipedObj, swipe); consumed = true; } } - if (!consumed && (lastPressedObj != NULL) - && ((foundObj == lastPressedObj) || (nbgl_screenContainsObj(lastPressedObj)))) { + if (!consumed && (ctx->lastPressedObj != NULL) + && ((foundObj == ctx->lastPressedObj) + || (nbgl_screenContainsObj(ctx->lastPressedObj)))) { // very strange if lastPressedObj != foundObj, let's consider that it's a normal release // on lastPressedObj make sure lastPressedObj still belongs to current screen before // "releasing" it - applytouchStatePosition(lastPressedObj, TOUCH_RELEASED); - if (currentTime >= (lastPressedTime + LONG_TOUCH_DURATION)) { - applytouchStatePosition(lastPressedObj, LONG_TOUCHED); + applytouchStatePosition(ctx->lastPressedObj, TOUCH_RELEASED); + if (currentTime >= (ctx->lastPressedTime + LONG_TOUCH_DURATION)) { + applytouchStatePosition(ctx->lastPressedObj, LONG_TOUCHED); } - else if (currentTime >= (lastPressedTime + SHORT_TOUCH_DURATION)) { - applytouchStatePosition(lastPressedObj, TOUCHED); + else if (currentTime >= (ctx->lastPressedTime + SHORT_TOUCH_DURATION)) { + applytouchStatePosition(ctx->lastPressedObj, TOUCHED); } } // Released event has been handled, forget lastPressedObj - lastPressedObj = NULL; + ctx->lastPressedObj = NULL; } else { // PRESSED - if ((lastState == PRESSED) && (lastPressedObj != NULL)) { - if (foundObj != lastPressedObj) { + if ((ctx->lastState == PRESSED) && (ctx->lastPressedObj != NULL)) { + if (foundObj != ctx->lastPressedObj) { // finger has moved out of an object // make sure lastPressedObj still belongs to current screen before warning it - if (nbgl_screenContainsObj(lastPressedObj)) { - applytouchStatePosition(lastPressedObj, OUT_OF_TOUCH); + if (nbgl_screenContainsObj(ctx->lastPressedObj)) { + applytouchStatePosition(ctx->lastPressedObj, OUT_OF_TOUCH); } - lastPressedObj = NULL; + ctx->lastPressedObj = NULL; } else { // warn the concerned object that it is still touched applytouchStatePosition(foundObj, TOUCHING); } } - else if (lastState == RELEASED) { + else if (ctx->lastState == RELEASED) { // newly touched object - lastPressedObj = foundObj; - lastPressedTime = currentTime; + ctx->lastPressedObj = foundObj; + ctx->lastPressedTime = currentTime; applytouchStatePosition(foundObj, TOUCH_PRESSED); applytouchStatePosition(foundObj, TOUCHING); } } - lastState = touchStatePosition->state; + ctx->lastState = touchStatePosition->state; } bool nbgl_touchGetTouchedPosition(nbgl_obj_t *obj, nbgl_touchStatePosition_t **firstPos, nbgl_touchStatePosition_t **lastPos) { - LOG_DEBUG(TOUCH_LOGGER, "nbgl_touchGetTouchedPosition: %p %p\n", obj, lastPressedObj); - if (obj == lastPressedObj) { - *firstPos = &firstTouchedPosition; - *lastPos = &lastTouchedPosition; + nbgl_touchCtx_t *ctx = nbgl_objIsUx(obj) ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX]; + LOG_DEBUG(TOUCH_LOGGER, "nbgl_touchGetTouchedPosition: %p %p\n", obj, ctx->lastPressedObj); + if (obj == ctx->lastPressedObj) { + *firstPos = &ctx->firstTouchedPosition; + *lastPos = &ctx->lastTouchedPosition; return true; } return false; @@ -376,8 +400,9 @@ bool nbgl_touchGetTouchedPosition(nbgl_obj_t *obj, uint32_t nbgl_touchGetTouchDuration(nbgl_obj_t *obj) { - if (obj == lastPressedObj) { - return (lastCurrentTime - lastPressedTime); + nbgl_touchCtx_t *ctx = nbgl_objIsUx(obj) ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX]; + if (obj == ctx->lastPressedObj) { + return (ctx->lastCurrentTime - ctx->lastPressedTime); } return 0; } diff --git a/lib_ux_nbgl/ux.c b/lib_ux_nbgl/ux.c index d7a807e3c..9d7dbcb45 100644 --- a/lib_ux_nbgl/ux.c +++ b/lib_ux_nbgl/ux.c @@ -75,7 +75,7 @@ void ux_process_finger_event(uint8_t seph_packet[]) #ifdef HAVE_HW_TOUCH_SWIPE pos.swipe = seph_packet[10]; #endif // HAVE_HW_TOUCH_SWIPE - nbgl_touchHandler(&pos, nbTicks * 100); + nbgl_touchHandler(false, &pos, nbTicks * 100); nbgl_refresh(); } } @@ -131,7 +131,7 @@ void ux_process_ticker_event(void) pos.x = touch_info.x; pos.y = touch_info.y; // Send current touch position to nbgl - nbgl_touchHandler(&pos, nbTicks * 100); + nbgl_touchHandler(false, &pos, nbTicks * 100); } #endif // HAVE_SE_TOUCH nbgl_refresh(); diff --git a/unit-tests/lib_nbgl/test_nbgl_obj.c b/unit-tests/lib_nbgl/test_nbgl_obj.c index 54e856dc7..aeb106f9b 100644 --- a/unit-tests/lib_nbgl/test_nbgl_obj.c +++ b/unit-tests/lib_nbgl/test_nbgl_obj.c @@ -188,8 +188,9 @@ void nbgl_screen_reinit(void) { return; } - #ifdef HAVE_SE_TOUCH +void nbgl_touchInit(void) {} + static void test_draw_obj(void **state __attribute__((unused))) { nbgl_image_t *image;