feat(core): add rgb_led_effect_ongoing function to rgb led driver.
What changed, and why it matters
This commit adds a new function that lets the firmware ask whether an RGB LED lighting effect is currently running. It also renames some internal constants and removes unnecessary 'return' statements. There is no security-relevant change here; it is a routine feature addition to the LED driver.
No security action required. Treat as normal feature/maintenance commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces rgb_led_effect_ongoing() in the RGB LED driver, exposes it through the syscall interface, and adds it to the Rust FFI allowlist. It renames LED_SWITCHING_FREQUENCY_HZ/TIMER_PERIOD to RGB_LED_PWM_FREQ/RGB_LED_TIMER_PERIOD and cleans up redundant early returns in effect functions. The new function reads drv->ongoing_effect under an IRQ lock. No memory safety, access control, or cryptographic changes are present.
Changed components
core/embed/io/rgb_led drivercore/embed/sys/syscall RGB LED dispatchcore/embed/rust build bindingsInspect captured patch +54 / −32
diff --git a/core/embed/io/rgb_led/inc/io/rgb_led.h b/core/embed/io/rgb_led/inc/io/rgb_led.h
index 90b2ea436..5d3457551 100644
--- a/core/embed/io/rgb_led/inc/io/rgb_led.h
+++ b/core/embed/io/rgb_led/inc/io/rgb_led.h
@@ -101,3 +101,10 @@ void rgb_led_effect_start(rgb_led_effect_type_t effect_type,
* @brief Stop the currently running RGB led effect and turn off the RGB led
*/
void rgb_led_effect_stop(void);
+
+/**
+ * @brief Get the ongoing RGB led effect state
+ *
+ * @return true if an effect is currently running, false otherwise
+ */
+bool rgb_led_effect_ongoing(void);
diff --git a/core/embed/io/rgb_led/stm32u5/rgb_led_effects.c b/core/embed/io/rgb_led/stm32u5/rgb_led_effects.c
index 83b750905..11b63124b 100644
--- a/core/embed/io/rgb_led/stm32u5/rgb_led_effects.c
+++ b/core/embed/io/rgb_led/stm32u5/rgb_led_effects.c
@@ -130,34 +130,26 @@ static void rgb_led_effect_bootloader_breathe(uint32_t elapsed_ms,
// PHASE 1: linear transition to RGBLED_BLUE
rgb_led_linear_gc_effect(RGBLED_OFF, RGBLED_BLUE, ef_time, EF_BB_PHASE1_MS,
ef_color);
- return;
} else if (ef_time < EF_BB_PHASE1_MS + EF_BB_PHASE2_MS) {
// PHASE 2: hold RGBLED_BLUE color
ef_color->red = (RGB_EXTRACT_RED(RGBLED_BLUE) * TIMER_PERIOD) / 255;
ef_color->green = (RGB_EXTRACT_GREEN(RGBLED_BLUE) * TIMER_PERIOD) / 255;
ef_color->blue = (RGB_EXTRACT_BLUE(RGBLED_BLUE) * TIMER_PERIOD) / 255;
- return;
-
} else if (ef_time < EF_BB_PHASE1_MS + EF_BB_PHASE2_MS + EF_BB_PHASE3_MS) {
// PHASE 3: linear transition to RGBLED_OFF
rgb_led_linear_gc_effect(RGBLED_BLUE, RGBLED_OFF,
ef_time - EF_BB_PHASE1_MS - EF_BB_PHASE2_MS,
EF_BB_PHASE3_MS, ef_color);
- return;
-
} else if (ef_time < EF_BB_CYCLE_MS) {
// PHASE 4: hold the off state
ef_color->red = 0;
ef_color->green = 0;
ef_color->blue = 0;
- return;
-
} else {
// Should not happen
ef_color->red = 0;
ef_color->green = 0;
ef_color->blue = 0;
- return;
}
}
@@ -176,32 +168,26 @@ static void rgb_led_effect_charging_gamma(uint32_t elapsed_ms,
// PHASE 1: linear transition to RGBLED_YELLOW
rgb_led_linear_gc_effect(RGBLED_OFF, RGBLED_YELLOW, ef_time,
EF_CHG_PHASE1_MS, ef_color);
- return;
} else if (ef_time < EF_CHG_PHASE1_MS + EF_CHG_PHASE2_MS) {
// PHASE 2: hold RGBLED_YELLOW color
ef_color->red = (RGB_EXTRACT_RED(RGBLED_YELLOW) * TIMER_PERIOD) / 255;
ef_color->green = (RGB_EXTRACT_GREEN(RGBLED_YELLOW) * TIMER_PERIOD) / 255;
ef_color->blue = (RGB_EXTRACT_BLUE(RGBLED_YELLOW) * TIMER_PERIOD) / 255;
- return;
} else if (ef_time < EF_CHG_PHASE1_MS + EF_CHG_PHASE2_MS + EF_CHG_PHASE3_MS) {
// PHASE 3: linear transition to RGBLED_OFF
rgb_led_linear_gc_effect(RGBLED_YELLOW, RGBLED_OFF,
ef_time - EF_CHG_PHASE1_MS - EF_CHG_PHASE2_MS,
EF_CHG_PHASE3_MS, ef_color);
- return;
} else if (ef_time < EF_CHG_CYCLE_MS) {
// PHASE 4: hold the off state
ef_color->red = 0;
ef_color->green = 0;
ef_color->blue = 0;
- return;
-
} else {
// Should not happen
ef_color->red = 0;
ef_color->green = 0;
ef_color->blue = 0;
- return;
}
}
diff --git a/core/embed/io/rgb_led/stm32u5/rgb_led_internal.h b/core/embed/io/rgb_led/stm32u5/rgb_led_internal.h
index 4bb0406ed..37656a972 100644
--- a/core/embed/io/rgb_led/stm32u5/rgb_led_internal.h
+++ b/core/embed/io/rgb_led/stm32u5/rgb_led_internal.h
@@ -25,8 +25,8 @@
#include <io/rgb_led.h>
#include <sys/systimer.h>
-#define LED_SWITCHING_FREQUENCY_HZ 1000
-#define TIMER_PERIOD (16000000 / LED_SWITCHING_FREQUENCY_HZ)
+#define RGB_LED_PWM_FREQ 1000
+#define RGB_LED_TIMER_PERIOD (16000000 / RGB_LED_PWM_FREQ)
typedef struct {
uint32_t red;
diff --git a/core/embed/io/rgb_led/stm32u5/rgb_led_lp.c b/core/embed/io/rgb_led/stm32u5/rgb_led_lp.c
index c759f5184..3cc73d48e 100644
--- a/core/embed/io/rgb_led/stm32u5/rgb_led_lp.c
+++ b/core/embed/io/rgb_led/stm32u5/rgb_led_lp.c
@@ -24,6 +24,7 @@
#include <trezor_rtl.h>
#include <io/rgb_led.h>
+#include <sys/irq.h>
#include <sys/systimer.h>
#include "rgb_led_internal.h"
@@ -77,7 +78,7 @@ void rgb_led_init(void) {
drv->tim_1.State = HAL_LPTIM_STATE_RESET;
drv->tim_1.Instance = LPTIM1;
- drv->tim_1.Init.Period = TIMER_PERIOD;
+ drv->tim_1.Init.Period = RGB_LED_TIMER_PERIOD;
drv->tim_1.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
drv->tim_1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1;
drv->tim_1.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING;
@@ -88,7 +89,7 @@ void rgb_led_init(void) {
drv->tim_3.State = HAL_LPTIM_STATE_RESET;
drv->tim_3.Instance = LPTIM3;
- drv->tim_3.Init.Period = TIMER_PERIOD;
+ drv->tim_3.Init.Period = RGB_LED_TIMER_PERIOD;
drv->tim_3.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
drv->tim_3.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1;
drv->tim_3.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING;
@@ -109,9 +110,9 @@ void rgb_led_init(void) {
HAL_LPTIM_Counter_Start(&drv->tim_1);
HAL_LPTIM_Counter_Start(&drv->tim_3);
- __HAL_LPTIM_COMPARE_SET(&drv->tim_1, LPTIM_CHANNEL_1, TIMER_PERIOD);
- __HAL_LPTIM_COMPARE_SET(&drv->tim_3, LPTIM_CHANNEL_1, TIMER_PERIOD);
- __HAL_LPTIM_COMPARE_SET(&drv->tim_3, LPTIM_CHANNEL_2, TIMER_PERIOD);
+ __HAL_LPTIM_COMPARE_SET(&drv->tim_1, LPTIM_CHANNEL_1, RGB_LED_TIMER_PERIOD);
+ __HAL_LPTIM_COMPARE_SET(&drv->tim_3, LPTIM_CHANNEL_1, RGB_LED_TIMER_PERIOD);
+ __HAL_LPTIM_COMPARE_SET(&drv->tim_3, LPTIM_CHANNEL_2, RGB_LED_TIMER_PERIOD);
// Enable the Peripheral
__HAL_LPTIM_ENABLE(&drv->tim_1);
@@ -220,9 +221,9 @@ void rgb_led_set_color(uint32_t color) {
}
rgb_led_color_fs_t color_fs;
- color_fs.red = (RGB_EXTRACT_RED(color) * TIMER_PERIOD) / 255;
- color_fs.green = (RGB_EXTRACT_GREEN(color) * TIMER_PERIOD) / 255;
- color_fs.blue = (RGB_EXTRACT_BLUE(color) * TIMER_PERIOD) / 255;
+ color_fs.red = (RGB_EXTRACT_RED(color) * RGB_LED_TIMER_PERIOD) / 255;
+ color_fs.green = (RGB_EXTRACT_GREEN(color) * RGB_LED_TIMER_PERIOD) / 255;
+ color_fs.blue = (RGB_EXTRACT_BLUE(color) * RGB_LED_TIMER_PERIOD) / 255;
rgb_led_apply_color(drv, &color_fs);
}
@@ -271,10 +272,26 @@ void rgb_led_effect_stop(void) {
rgb_led_apply_color(drv, &color_fs);
}
+bool rgb_led_effect_ongoing(void) {
+ rgb_led_t* drv = &g_rgb_led;
+
+ if (!drv->initialized) {
+ return false;
+ }
+
+ bool ongoing;
+ irq_key_t irq_key = irq_lock();
+ ongoing = drv->ongoing_effect;
+ irq_unlock(irq_key);
+
+ return ongoing;
+}
+
static void rgb_led_apply_color(rgb_led_t* drv, rgb_led_color_fs_t* color_fs) {
// Check color settings is in range
- if (color_fs->red > TIMER_PERIOD || color_fs->green > TIMER_PERIOD ||
- color_fs->blue > TIMER_PERIOD) {
+ if (color_fs->red > RGB_LED_TIMER_PERIOD ||
+ color_fs->green > RGB_LED_TIMER_PERIOD ||
+ color_fs->blue > RGB_LED_TIMER_PERIOD) {
return;
}
@@ -297,11 +314,11 @@ static void rgb_led_apply_color(rgb_led_t* drv, rgb_led_color_fs_t* color_fs) {
}
__HAL_LPTIM_COMPARE_SET(&drv->tim_1, LPTIM_CHANNEL_1,
- TIMER_PERIOD - (color_fs->red));
+ RGB_LED_TIMER_PERIOD - (color_fs->red));
__HAL_LPTIM_COMPARE_SET(&drv->tim_3, LPTIM_CHANNEL_2,
- TIMER_PERIOD - (color_fs->green));
+ RGB_LED_TIMER_PERIOD - (color_fs->green));
__HAL_LPTIM_COMPARE_SET(&drv->tim_3, LPTIM_CHANNEL_1,
- TIMER_PERIOD - (color_fs->blue));
+ RGB_LED_TIMER_PERIOD - (color_fs->blue));
}
static void rgb_led_systimer_callback(void* context) {
diff --git a/core/embed/io/rgb_led/unix/rgb_led.c b/core/embed/io/rgb_led/unix/rgb_led.c
index a96ebb6a3..62b854c65 100644
--- a/core/embed/io/rgb_led/unix/rgb_led.c
+++ b/core/embed/io/rgb_led/unix/rgb_led.c
@@ -102,4 +102,9 @@ void rgb_led_effect_stop(void) {
return;
}
+bool rgb_led_get_effect_ongoing(void) {
+ // RGB effect not supported in unix yet
+ return false;
+}
+
#endif /* KERNEL_MODE */
diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs
index 75c60bf35..9d6bffe2e 100644
--- a/core/embed/rust/build.rs
+++ b/core/embed/rust/build.rs
@@ -403,6 +403,7 @@ fn generate_trezorhal_bindings() {
.allowlist_function("rgb_led_set_color")
.allowlist_function("rgb_led_effect_start")
.allowlist_function("rgb_led_effect_stop")
+ .allowlist_function("rgb_led_effect_ongoing")
// systick
.allowlist_function("systick_delay_ms")
.allowlist_function("systick_ms")
diff --git a/core/embed/sys/syscall/inc/sys/syscall_numbers.h b/core/embed/sys/syscall/inc/sys/syscall_numbers.h
index 340369c1c..53a0d0486 100644
--- a/core/embed/sys/syscall/inc/sys/syscall_numbers.h
+++ b/core/embed/sys/syscall/inc/sys/syscall_numbers.h
@@ -89,6 +89,7 @@ typedef enum {
SYSCALL_RGB_LED_SET_COLOR,
SYSCALL_RGB_LED_EFFECT_START,
SYSCALL_RGB_LED_EFFECT_STOP,
+ SYSCALL_RGB_LED_EFFECT_ONGOING,
SYSCALL_HAPTIC_SET_ENABLED,
SYSCALL_HAPTIC_GET_ENABLED,
diff --git a/core/embed/sys/syscall/stm32/syscall_dispatch.c b/core/embed/sys/syscall/stm32/syscall_dispatch.c
index 7de0d37b7..4e1a50725 100644
--- a/core/embed/sys/syscall/stm32/syscall_dispatch.c
+++ b/core/embed/sys/syscall/stm32/syscall_dispatch.c
@@ -347,6 +347,10 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
case SYSCALL_RGB_LED_EFFECT_STOP: {
rgb_led_effect_stop();
} break;
+
+ case SYSCALL_RGB_LED_EFFECT_ONGOING: {
+ args[0] = rgb_led_effect_ongoing();
+ } break;
#endif
#ifdef USE_HAPTIC
diff --git a/core/embed/sys/syscall/stm32/syscall_stubs.c b/core/embed/sys/syscall/stm32/syscall_stubs.c
index 5230f910a..aec86aaab 100644
--- a/core/embed/sys/syscall/stm32/syscall_stubs.c
+++ b/core/embed/sys/syscall/stm32/syscall_stubs.c
@@ -328,11 +328,12 @@ void rgb_led_effect_start(rgb_led_effect_type_t effect_type,
SYSCALL_RGB_LED_EFFECT_START);
}
-/**
- * @brief Stop the currently running RGB led effect and turn off the RGB led
- */
void rgb_led_effect_stop(void) { syscall_invoke0(SYSCALL_RGB_LED_EFFECT_STOP); }
+bool rgb_led_effect_ongoing(void) {
+ return (bool)syscall_invoke0(SYSCALL_RGB_LED_EFFECT_ONGOING);
+}
+
#endif
// =============================================================================
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.