Skip to content

WIP eckhart menu actions #5547

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

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions core/.changelog.d/3735.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[T3T1,T3W1] Haptic support in emulator.
1 change: 1 addition & 0 deletions core/SConscript.unix
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ FEATURES_WANTED = [
"ble",
"display",
"dma2d",
"haptic",
"input",
"kernel_mode",
"optiga",
Expand Down
9 changes: 9 additions & 0 deletions core/embed/io/display/inc/io/unix/sdl_display.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
#pragma once

#ifdef USE_HAPTIC
#include <io/haptic.h>
#endif /* USE_HAPTIC */
#include <trezor_types.h>

#ifdef USE_RGB_LED
// Update the RGB LED color in the emulator
void display_rgb_led(uint32_t color);
#endif

#ifdef USE_HAPTIC
// Update the haptic color in the emulator
void display_haptic_effect(haptic_effect_t effect);
void display_custom_effect(uint32_t duration_ms);
#endif /* USE_HAPTIC */
134 changes: 134 additions & 0 deletions core/embed/io/display/unix/display_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ typedef struct {
// Color of the RGB LED
uint32_t led_color;
#endif

#ifdef USE_HAPTIC
uint32_t haptic_color;
uint32_t haptic_expire_time;
#endif /* USE_HAPTIC */

} display_driver_t;

static display_driver_t g_display_driver = {
Expand All @@ -91,6 +97,7 @@ static display_driver_t g_display_driver = {
//!@# TODO get rid of this...
int sdl_display_res_x = DISPLAY_RESX, sdl_display_res_y = DISPLAY_RESY;
int sdl_touch_offset_x, sdl_touch_offset_y;
int sdl_touch_x = -1, sdl_touch_y = -1;

static void display_exit_handler(void) {
display_deinit(DISPLAY_RESET_CONTENT);
Expand Down Expand Up @@ -189,6 +196,11 @@ bool display_init(display_content_mode_t mode) {
drv->led_color = 0;
#endif

#ifdef USE_HAPTIC
drv->haptic_color = 0;
drv->haptic_expire_time = 0;
#endif /* USE_HAPTIC */

gfx_bitblt_init();

drv->initialized = true;
Expand Down Expand Up @@ -386,6 +398,102 @@ void draw_rgb_led() {
}
#endif // USE_RGB_LED

#ifdef USE_HAPTIC

void display_haptic_effect(haptic_effect_t effect) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return;
}

switch (effect) {
case HAPTIC_BUTTON_PRESS:
drv->haptic_color = 0xFF0000; // Red
drv->haptic_expire_time = SDL_GetTicks() + 200; // 200 ms duration
break;
case HAPTIC_HOLD_TO_CONFIRM:
drv->haptic_color = 0xFF00; // Green
drv->haptic_expire_time = SDL_GetTicks() + 500; // 500 ms duration
break;
case HAPTIC_BOOTLOADER_ENTRY:
drv->haptic_color = 0x0000FF; // Blue
drv->haptic_expire_time = SDL_GetTicks() + 500; // 500 ms duration
break;
default:
drv->haptic_color = 0x0;
break;
}

display_refresh();
}

void display_custom_effect(uint32_t duration_ms) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return;
}

drv->haptic_color = 0xFFA500; // Orange
drv->haptic_expire_time = SDL_GetTicks() + duration_ms;
display_refresh();
}

void draw_haptic() {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return;
}

if (SDL_GetTicks() > drv->haptic_expire_time) {
drv->haptic_color = 0; // Clear
return;
}

const uint32_t color = drv->haptic_color;

if (color == 0) {
return; // No LED color set
}

// Extract RGB components
uint32_t r = (color >> 16) & 0xFF;
uint32_t g = (color >> 8) & 0xFF;
uint32_t b = color & 0xFF;

// Define touch circle properties
const int radius = 5;

#ifdef USE_TOUCH
int center_x = sdl_touch_x;
int center_y = sdl_touch_y;
#else
int center_x = DISPLAY_RESX / 2;
int center_y = DISPLAY_RESY + 20;
#endif /* USE_TOUCH */

// Position based on background
if (drv->background) {
center_x += TOUCH_OFFSET_X;
center_y += TOUCH_OFFSET_Y;
} else {
center_x += EMULATOR_BORDER;
center_y += EMULATOR_BORDER;
}

// // Draw the touch circle
SDL_SetRenderDrawColor(drv->renderer, r, g, b, 255);

for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) {
if (x * x + y * y <= radius * radius) {
SDL_RenderDrawPoint(drv->renderer, center_x + x, center_y + y);
}
}
}
SDL_SetRenderDrawColor(drv->renderer, 0, 0, 0, 255);
}
#endif /* USE_HAPTIC */

void display_refresh(void) {
display_driver_t *drv = &g_display_driver;

Expand Down Expand Up @@ -424,6 +532,10 @@ void display_refresh(void) {
draw_rgb_led();
#endif

#ifdef USE_HAPTIC
draw_haptic();
#endif

SDL_RenderPresent(drv->renderer);
}

Expand Down Expand Up @@ -538,6 +650,28 @@ void display_save(const char *prefix) {
drv->buffer->format->Rmask, drv->buffer->format->Gmask,
drv->buffer->format->Bmask, drv->buffer->format->Amask);
SDL_BlitSurface(drv->buffer, &rect, crop, NULL);

#ifdef USE_HAPTIC
// === Static haptic dots ===
if (SDL_GetTicks() < drv->haptic_expire_time) {
uint32_t color = drv->haptic_color;

if (color != 0) {
// Extract RGB components
uint32_t r = (color >> 16) & 0xFF;
uint32_t g = (color >> 8) & 0xFF;
uint32_t b = color & 0xFF;
// Draw a one-pixel dot
if (sdl_touch_x >= 0 && sdl_touch_x < rect.w && sdl_touch_y >= 0 &&
sdl_touch_y < rect.h) {
Uint8 *pixel_ptr = (Uint8 *)crop->pixels + (sdl_touch_y * crop->pitch) +
(sdl_touch_x * crop->format->BytesPerPixel);
*(Uint32 *)pixel_ptr = SDL_MapRGBA(crop->format, r, g, b, 255);
}
}
}
#endif // USE_HAPTIC

// compare with previous screen, skip if equal
if (drv->prev_saved != NULL) {
if (memcmp(drv->prev_saved->pixels, crop->pixels, crop->pitch * crop->h) ==
Expand Down
136 changes: 136 additions & 0 deletions core/embed/io/haptic/unix/haptic_driver.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <trezor_bsp.h>
#include <trezor_rtl.h>

#include <io/haptic.h>
#include <io/unix/sdl_display.h>

#ifdef KERNEL_MODE

// Driver state
typedef struct {
bool initialized;
bool enabled;
} haptic_driver_t;

// Haptic driver instance
static haptic_driver_t g_haptic_driver = {
.initialized = true,
.enabled = false,
};

bool haptic_init(void) {
haptic_driver_t *driver = &g_haptic_driver;

if (driver->initialized) {
return true;
}

memset(driver, 0, sizeof(haptic_driver_t));

driver->initialized = true;
driver->enabled = true;

return true;
}

void haptic_deinit(void) {
haptic_driver_t *driver = &g_haptic_driver;
memset(driver, 0, sizeof(haptic_driver_t));
}

void haptic_set_enabled(bool enabled) {
haptic_driver_t *driver = &g_haptic_driver;

if (!driver->initialized) {
return;
}

driver->enabled = enabled;
}

bool haptic_get_enabled(void) {
haptic_driver_t *driver = &g_haptic_driver;

if (!driver->initialized) {
return false;
}

return driver->enabled;
}

bool haptic_test(uint16_t duration_ms) {
haptic_driver_t *driver = &g_haptic_driver;

if (!driver->initialized) {
return false;
}

if (!driver->enabled) {
return true;
}

// display_effect(0xff, duration_ms);
return true;
}

bool haptic_play(haptic_effect_t effect) {
haptic_driver_t *driver = &g_haptic_driver;

if (!driver->initialized) {
return false;
}

if (!driver->enabled) {
return true;
}

switch (effect) {
case HAPTIC_BUTTON_PRESS:
display_haptic_effect(HAPTIC_BUTTON_PRESS);
return true;
case HAPTIC_HOLD_TO_CONFIRM:
display_haptic_effect(HAPTIC_HOLD_TO_CONFIRM);
return true;
case HAPTIC_BOOTLOADER_ENTRY:
display_haptic_effect(HAPTIC_BOOTLOADER_ENTRY);
return true;
default:
return false;
}
}

bool haptic_play_custom(int8_t amplitude_pct, uint16_t duration_ms) {
haptic_driver_t *driver = &g_haptic_driver;

if (!driver->initialized) {
return false;
}

if (!driver->enabled) {
return true;
}

display_custom_effect(duration_ms);
return true;
}

#endif // KERNEL_MODE
17 changes: 12 additions & 5 deletions core/embed/io/rgb_led/inc/io/rgb_led.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,22 @@ void rgb_led_init(void);
// Deinitialize RGB LED driver
void rgb_led_deinit(void);

#endif
#endif // KERNEL_MODE

#define RGBLED_GREEN 0x00FF00
#define RGBLED_RED 0xFF0000
#define RGBLED_BLUE 0x0000FF
#define RGBLED_YELLOW 0xFFFF00
// Set RGB LED enabled state
// enabled: true to enable, false to disable
void rgb_led_set_enabled(bool enabled);

// Get RGB LED enabled state
bool rgb_led_get_enabled(void);

// Set RGB LED color
// color: 24-bit RGB color, 0x00RRGGBB
void rgb_led_set_color(uint32_t color);

#define RGBLED_GREEN 0x040D04
#define RGBLED_RED 0x640603
#define RGBLED_BLUE 0x050532
#define RGBLED_YELLOW 0x161000

#endif // TREZORHAL_RGB_LED_H
Loading
Loading