diff --git a/components/micropython/usermodule/mp_leds.c b/components/micropython/usermodule/mp_leds.c index 68880e7f5672152a54842f5c62623e54b1f5b371..f98e8cfb3445e1cd5194b1267261582d3e80243d 100644 --- a/components/micropython/usermodule/mp_leds.c +++ b/components/micropython/usermodule/mp_leds.c @@ -70,6 +70,19 @@ STATIC mp_obj_t mp_led_set_rgb(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_led_set_rgb_obj, 4, 4, mp_led_set_rgb); +STATIC mp_obj_t mp_led_set_rgba(size_t n_args, const mp_obj_t *args) { + uint8_t index = mp_obj_get_int(args[0]); + float red = mp_obj_get_float(args[1]); + float green = mp_obj_get_float(args[2]); + float blue = mp_obj_get_float(args[3]); + float alpha = mp_obj_get_float(args[4]); + + st3m_leds_set_single_rgba(index, red, green, blue, alpha); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_led_set_rgba_obj, 5, 5, + mp_led_set_rgba); + STATIC mp_obj_t mp_led_set_hsv(size_t n_args, const mp_obj_t *args) { uint8_t index = mp_obj_get_int(args[0]); float hue = mp_obj_get_float(args[1]); @@ -90,6 +103,17 @@ STATIC mp_obj_t mp_led_set_all_rgb(mp_obj_t r, mp_obj_t g, mp_obj_t b) { } STATIC MP_DEFINE_CONST_FUN_OBJ_3(mp_led_set_all_rgb_obj, mp_led_set_all_rgb); +STATIC mp_obj_t mp_led_set_all_rgba(size_t n_args, const mp_obj_t *args) { + float red = mp_obj_get_float(args[0]); + float green = mp_obj_get_float(args[1]); + float blue = mp_obj_get_float(args[2]); + float alpha = mp_obj_get_float(args[3]); + st3m_leds_set_all_rgba(red, green, blue, alpha); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_led_set_all_rgba_obj, 4, 4, + mp_led_set_all_rgba); + STATIC mp_obj_t mp_led_set_all_hsv(mp_obj_t h, mp_obj_t s, mp_obj_t v) { float hue = mp_obj_get_float(h); float sat = mp_obj_get_float(s); @@ -99,6 +123,19 @@ STATIC mp_obj_t mp_led_set_all_hsv(mp_obj_t h, mp_obj_t s, mp_obj_t v) { } STATIC MP_DEFINE_CONST_FUN_OBJ_3(mp_led_set_all_hsv_obj, mp_led_set_all_hsv); +STATIC mp_obj_t mp_led_get_rgb(mp_obj_t led_index) { + uint8_t index = mp_obj_get_int(led_index); + float red; + float green; + float blue; + + st3m_leds_get_single_rgb(index, &red, &green, &blue); + mp_obj_t items[] = { mp_obj_new_float(red), mp_obj_new_float(green), + mp_obj_new_float(blue) }; + return mp_obj_new_tuple(3, items); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_led_get_rgb_obj, mp_led_get_rgb); + STATIC mp_obj_t mp_leds_update() { st3m_leds_update(); return mp_const_none; @@ -108,9 +145,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_leds_update_obj, mp_leds_update); STATIC const mp_rom_map_elem_t mp_module_leds_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_leds) }, { MP_ROM_QSTR(MP_QSTR_set_rgb), MP_ROM_PTR(&mp_led_set_rgb_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_rgba), MP_ROM_PTR(&mp_led_set_rgba_obj) }, { MP_ROM_QSTR(MP_QSTR_set_hsv), MP_ROM_PTR(&mp_led_set_hsv_obj) }, { MP_ROM_QSTR(MP_QSTR_set_all_rgb), MP_ROM_PTR(&mp_led_set_all_rgb_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_all_rgba), MP_ROM_PTR(&mp_led_set_all_rgba_obj) }, { MP_ROM_QSTR(MP_QSTR_set_all_hsv), MP_ROM_PTR(&mp_led_set_all_hsv_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_rgb), MP_ROM_PTR(&mp_led_get_rgb_obj) }, { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&mp_leds_update_obj) }, { MP_ROM_QSTR(MP_QSTR_get_brightness), MP_ROM_PTR(&mp_leds_get_brightness_obj) }, diff --git a/components/st3m/st3m_leds.c b/components/st3m/st3m_leds.c index a9b314549f5a09612e2734b09d6279b7cde5b760..7bc911d4a5e32e445179ba34316822596848b9c9 100644 --- a/components/st3m/st3m_leds.c +++ b/components/st3m/st3m_leds.c @@ -20,6 +20,12 @@ typedef struct { uint8_t lut[256]; } st3m_leds_gamma_table_t; +typedef struct { + uint16_t r; + uint16_t g; + uint16_t b; +} st3m_leds_rgb_t; + typedef struct { uint8_t brightness; uint8_t slew_rate; @@ -31,7 +37,7 @@ typedef struct { st3m_rgb_t target[40]; st3m_rgb_t target_buffer[40]; - st3m_rgb_t hardware_value[40]; + st3m_leds_rgb_t slew_output[40]; } st3m_leds_state_t; static st3m_leds_state_t state; @@ -49,7 +55,11 @@ static void set_single_led(uint8_t index, st3m_rgb_t c) { flow3r_bsp_leds_set_pixel(index, c.r, c.g, c.b); } -uint8_t led_get_slew(int16_t old, int16_t new, int16_t slew) { +static uint16_t led_get_slew(uint16_t old, uint16_t new, uint16_t slew) { + new = new << 8; + if (slew == 255) return new; + slew = 30 + (slew << 2) + ((slew * slew) >> 3); + if (new > old + slew) { return old + slew; } else if (new > old) { @@ -81,21 +91,22 @@ void st3m_leds_update_hardware() { if (state.auto_update) leds_update_target(); for (int i = 0; i < 40; i++) { - st3m_rgb_t c = state.target[i]; - c.r = c.r * state.brightness / 255; - c.g = c.g * state.brightness / 255; - c.b = c.b * state.brightness / 255; - - c.r = state.gamma_red.lut[c.r]; - c.g = state.gamma_red.lut[c.g]; - c.b = state.gamma_red.lut[c.b]; - - c.r = led_get_slew(state.hardware_value[i].r, c.r, state.slew_rate); - c.g = led_get_slew(state.hardware_value[i].g, c.g, state.slew_rate); - c.b = led_get_slew(state.hardware_value[i].b, c.b, state.slew_rate); - state.hardware_value[i] = c; - - set_single_led(i, c); + st3m_rgb_t ret = state.target[i]; + st3m_leds_rgb_t c; + c.r = led_get_slew(state.slew_output[i].r, ret.r, state.slew_rate); + c.g = led_get_slew(state.slew_output[i].g, ret.g, state.slew_rate); + c.b = led_get_slew(state.slew_output[i].b, ret.b, state.slew_rate); + state.slew_output[i] = c; + + c.r = ((uint32_t)c.r * state.brightness) >> 8; + c.g = ((uint32_t)c.g * state.brightness) >> 8; + c.b = ((uint32_t)c.b * state.brightness) >> 8; + + ret.r = state.gamma_red.lut[c.r >> 8]; + ret.g = state.gamma_red.lut[c.g >> 8]; + ret.b = state.gamma_red.lut[c.b >> 8]; + + set_single_led(i, ret); } UNLOCK; @@ -105,6 +116,18 @@ void st3m_leds_update_hardware() { } } +void st3m_leds_set_single_rgba(uint8_t index, float red, float green, + float blue, float alpha) { + float r, g, b; + st3m_leds_get_single_rgb(index, &r, &g, &b); + + float nalpha = 1 - alpha; + r = alpha * red + nalpha * r; + g = alpha * green + nalpha * g; + b = alpha * blue + nalpha * blue; + st3m_leds_set_single_rgb(index, r, g, b); +} + void st3m_leds_set_single_rgb(uint8_t index, float red, float green, float blue) { if (red > 1.0) red /= 255.0; @@ -118,6 +141,15 @@ void st3m_leds_set_single_rgb(uint8_t index, float red, float green, UNLOCK_INCOMING; } +void st3m_leds_get_single_rgb(uint8_t index, float *red, float *green, + float *blue) { + LOCK_INCOMING; + *red = ((float)state.target_buffer[index].r) / 255; + *green = ((float)state.target_buffer[index].g) / 255; + *blue = ((float)state.target_buffer[index].b) / 255; + UNLOCK_INCOMING; +} + void st3m_leds_set_single_hsv(uint8_t index, float hue, float sat, float val) { st3m_hsv_t hsv = { .h = hue, @@ -135,6 +167,12 @@ void st3m_leds_set_all_rgb(float red, float green, float blue) { } } +void st3m_leds_set_all_rgba(float red, float green, float blue, float alpha) { + for (int i = 0; i < 40; i++) { + st3m_leds_set_single_rgba(i, red, green, blue, alpha); + } +} + void st3m_leds_set_all_hsv(float h, float s, float v) { for (int i = 0; i < 40; i++) { st3m_leds_set_single_hsv(i, h, s, v); @@ -148,7 +186,7 @@ static void _leds_task(void *_data) { TickType_t last_wake = xTaskGetTickCount(); while (true) { - vTaskDelayUntil(&last_wake, pdMS_TO_TICKS(100)); // 10 Hz + vTaskDelayUntil(&last_wake, pdMS_TO_TICKS(20)); // 50 Hz st3m_leds_update_hardware(); } } diff --git a/components/st3m/st3m_leds.h b/components/st3m/st3m_leds.h index 10b817f5a4c430b7af9d9373dff798504c29b037..ba05cbd0a14cf5ac12a67c55081cc792a0bdc19b 100644 --- a/components/st3m/st3m_leds.h +++ b/components/st3m/st3m_leds.h @@ -25,9 +25,14 @@ void st3m_leds_init(); // autoupdates. void st3m_leds_set_single_rgb(uint8_t index, float red, float green, float blue); +void st3m_leds_set_single_rgba(uint8_t index, float red, float green, + float blue, float alpha); void st3m_leds_set_single_hsv(uint8_t index, float hue, float sat, float value); void st3m_leds_set_all_rgb(float red, float green, float blue); +void st3m_leds_set_all_rgba(float red, float green, float blue, float alpha); void st3m_leds_set_all_hsv(float hue, float sat, float value); +void st3m_leds_get_single_rgb(uint8_t index, float* red, float* green, + float* blue); // Set/get global LED brightness, 0-255. Default 69. // @@ -36,10 +41,13 @@ void st3m_leds_set_brightness(uint8_t brightness); uint8_t st3m_leds_get_brightness(); // Set/get maximum change rate of brightness. Set to 1-3 for fade effects, set -// to 255 to disable. Currently clocks at 10Hz. +// to 255 to disable. Currently clocks at 50Hz. void st3m_leds_set_slew_rate(uint8_t slew_rate); uint8_t st3m_leds_get_slew_rate(); +void st3m_leds_set_max_slew_rate(uint8_t slew_rate); +uint8_t st3m_leds_get_max_slew_rate(); + // Update LEDs. Ie., copy the LED state from the first buffer into the second // buffer, effectively scheduling the LED state to be presented to the user. void st3m_leds_update(); diff --git a/python_payload/apps/appearance/__init__.py b/python_payload/apps/appearance/__init__.py index fd7b0a53186249cb5409f7cb3f63956605460074..a3b1105f61903e3f1e4530bc54238eb4476be4d9 100644 --- a/python_payload/apps/appearance/__init__.py +++ b/python_payload/apps/appearance/__init__.py @@ -180,21 +180,13 @@ class App(Application): leds.set_brightness(settings.num_leds_brightness.value) tmp = self.draw_number("led speed", 7, int(settings.num_leds_speed.value)) - if tmp > settings.num_leds_speed.value: - tmp = settings.num_leds_speed.value * 2 - elif tmp < settings.num_leds_speed.value: - tmp = (settings.num_leds_speed.value + 1) // 2 - if tmp < 1: - tmp = 1 + if tmp < 0: + tmp = 0 elif tmp > 255: tmp = 255 if tmp != settings.num_leds_speed.value: settings.num_leds_speed.set_value(tmp) leds.set_slew_rate(settings.num_leds_speed.value) - if 255 == settings.num_leds_speed.value: - leds.set_auto_update(0) - else: - leds.set_auto_update(1) tmp = self.draw_number( "display brightness", @@ -230,8 +222,8 @@ class App(Application): if self.input.buttons.app.middle.pressed: self.select_pressed = True - while self.led_accumulator_ms > 500: - self.led_accumulator_ms = self.led_accumulator_ms % 500 + while self.led_accumulator_ms > 2000: + self.led_accumulator_ms = self.led_accumulator_ms % 2000 self.leds_toggle() def leds_toggle(self): diff --git a/python_payload/apps/led_painter/__init__.py b/python_payload/apps/led_painter/__init__.py index 5be84a8569c52c5c34a34988f2862ad304bc234b..cc93e92f88d78e80ce04aac24fb730202c54f761 100644 --- a/python_payload/apps/led_painter/__init__.py +++ b/python_payload/apps/led_painter/__init__.py @@ -114,6 +114,7 @@ class LEDPainter(Application): def on_enter(self, vm): super().on_enter(vm) self._load_settings() + leds.set_slew_rate(255) def on_exit(self): self._save_settings() diff --git a/python_payload/mypystubs/leds.pyi b/python_payload/mypystubs/leds.pyi index c6febb771e4226117614986335bc0310a1731dd7..08bb35e505ce5a1955634ade2957eeabcc67ce0f 100644 --- a/python_payload/mypystubs/leds.pyi +++ b/python_payload/mypystubs/leds.pyi @@ -1,3 +1,5 @@ +from typing import Tuple + """ Leds API. @@ -8,22 +10,19 @@ There are 8 LEDs per top petal, or 4 LEDs per petal. After you're ready setting up your blink, call update(), or enable autoupdates. """ -def set_rgb(ix: int, r: float, g: float, b: float) -> None: - """Set LED `ix` to rgb value r, g, b +def set_rgb(i: int, r: float, g: float, b: float) -> None: + """Set LED i to rgb value r, g, b - :param ix: LED index, from 0 to 39 + :param i: LED index, from 0 to 39 :param r: Red value, from 0.0 to 1.0 :param g: Green value, from 0.0 to 1.0 :param b: Blue value, from 0.0 to 1.0 """ -def set_hsv(ix: int, hue: float, sat: float, val: float) -> None: - """Set LED `ix` to hsv value hue, sat, val +def get_rgb(i: int) -> Tuple[float, float, float]: + """Get rgb tuple of LED i - :param ix: LED index, from 0 to 39 - :param hue: Hue, from 0 to 360 - :param sat: Saturation, from 0.0 to 1.0 - :param val: Value, from 0.0 to 1.0 + :param i: LED index, from 0 to 39 """ def set_all_rgb(r: float, g: float, b: float) -> None: @@ -34,12 +33,23 @@ def set_all_rgb(r: float, g: float, b: float) -> None: :param b: Blue value, from 0.0 to 1.0 """ -def set_all_hsv(h: float, s: float, v: float) -> None: - """Set all LEDs to hsv value hue, sat, val +def set_rgba(ix: int, r: float, g: float, b: float, a: float) -> None: + """Set LED i to rgb alpha value r, g, b, a + + :param ix: LED index, from 0 to 39 + :param r: Red value, from 0.0 to 1.0 + :param g: Green value, from 0.0 to 1.0 + :param b: Blue value, from 0.0 to 1.0 + :param a: Alpha value, from 0.0 to 1.0 + """ + +def set_all_rgba(r: float, g: float, b: float, a: float) -> None: + """Set all LEDs to rgb alpha value r, g, b, a - :param hue: Hue, from 0 to 360 - :param sat: Saturation, from 0.0 to 1.0 - :param val: Value, from 0.0 to 1.0 + :param r: Red value, from 0.0 to 1.0 + :param g: Green value, from 0.0 to 1.0 + :param b: Blue value, from 0.0 to 1.0 + :param a: Alpha value, from 0.0 to 1.0 """ def update() -> None: @@ -72,12 +82,6 @@ def set_auto_update(on: bool) -> None: low slew rates. """ -def set_gamma(r: float, g: float, b: float) -> None: - """ - Bend the rgb curves with an exponent each. (1,1,1) is default, (2,2,2) works - well too If someone wants to do color calibration, this is ur friend - """ - def get_slew_rate() -> int: """ Get maximum change rate of brightness. See set_slew_rate() @@ -85,6 +89,6 @@ def get_slew_rate() -> int: def set_slew_rate(b: int) -> None: """ - Set maximum change rate of brightness. Set to 1-3 for fade effects, set - to 255 to disable. Currently clocks at 10Hz. + Set maximum change rate of channel brightness. Set to 255 to disable. + Animations render to the LEDs at 50Hz. """ diff --git a/python_payload/st3m/application.py b/python_payload/st3m/application.py index b49557aad204da586169adecc65d1af8f5b91c79..ac401056bf08df45b981dc669d317b4d0d2fdba9 100644 --- a/python_payload/st3m/application.py +++ b/python_payload/st3m/application.py @@ -68,10 +68,6 @@ class Application(BaseView): elif self._wifi_preference is False: st3m.wifi.disable() leds.set_slew_rate(settings.num_leds_speed.value) - if 255 == settings.num_leds_speed.value: - leds.set_auto_update(0) - else: - leds.set_auto_update(1) super().on_enter(vm) def on_exit(self) -> None: @@ -86,16 +82,15 @@ class Application(BaseView): if fully_exiting: sys_display.set_mode(0) if fully_exiting: - leds.set_slew_rate(10) - leds.set_auto_update(1) + leds.set_slew_rate(90) led_patterns.set_menu_colors() def on_exit_done(self): fully_exiting = self.vm.direction == ViewTransitionDirection.BACKWARD if fully_exiting: - leds.set_slew_rate(10) - leds.set_auto_update(1) + leds.set_slew_rate(40) led_patterns.set_menu_colors() + leds.update() def think(self, ins: InputState, delta_ms: int) -> None: super().think(ins, delta_ms) diff --git a/python_payload/st3m/run.py b/python_payload/st3m/run.py index f609dead4f0f2c241ddb2708b97b474a05ff073a..8be8c1c9efd23800536e7f58d1c9c8a28fcaa6a3 100644 --- a/python_payload/st3m/run.py +++ b/python_payload/st3m/run.py @@ -155,11 +155,6 @@ def run_main() -> None: audio.headphones_set_maximum_volume_dB(settings.num_headphones_max_db.value) audio.speaker_set_maximum_volume_dB(settings.num_speaker_max_db.value) leds.set_brightness(settings.num_leds_brightness.value) - leds.set_slew_rate(settings.num_leds_speed.value) - if 255 == settings.num_leds_speed.value: - leds.set_auto_update(0) - else: - leds.set_auto_update(1) sys_display.set_backlight(settings.num_display_brightness.value) leds.set_rgb(0, 255, 0, 0) @@ -169,9 +164,9 @@ def run_main() -> None: leds.set_rgb(0, 0, 0, 0) leds.update() - leds.set_slew_rate(2) - leds.set_auto_update(1) led_patterns.set_menu_colors() + leds.set_slew_rate(20) + leds.update() try: network.hostname( diff --git a/python_payload/st3m/settings.py b/python_payload/st3m/settings.py index 48f62a22bc0dd0c154e599e83f434999a2e57d63..92ebedf159e8fcb7110fc2b15098d05601fbdbb9 100644 --- a/python_payload/st3m/settings.py +++ b/python_payload/st3m/settings.py @@ -243,7 +243,7 @@ num_speaker_max_db = StringTunable( num_display_brightness = StringTunable( "Display Brightness", "system.brightness.display", 100 ) -num_leds_brightness = StringTunable("LED Brightness", "system.brightness.leds", 200) +num_leds_brightness = StringTunable("LED Brightness", "system.brightness.leds", 69) num_leds_speed = StringTunable("LED speed", "system.brightness.leds_speed", 255)