aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSelene ToyKeeper2023-08-26 19:42:04 -0600
committerSelene ToyKeeper2023-08-26 19:42:04 -0600
commitf245a903db3ff4a693f2874957cd9a671c5e2331 (patch)
tree24811f92905c023fcf279c03b33e06191597d816
parentmade bike strobe ontime configurable per build, (diff)
downloadanduril-f245a903db3ff4a693f2874957cd9a671c5e2331.tar.gz
anduril-f245a903db3ff4a693f2874957cd9a671c5e2331.tar.bz2
anduril-f245a903db3ff4a693f2874957cd9a671c5e2331.zip
added "smooth steps" a.k.a. "soft start", to make brightness steps smoother
(also made ramp extras config menu count its own steps)
-rw-r--r--spaghetti-monster/anduril/anduril-manual.txt9
-rw-r--r--spaghetti-monster/anduril/anduril.c14
-rw-r--r--spaghetti-monster/anduril/config-default.h8
-rw-r--r--spaghetti-monster/anduril/load-save-config-fsm.h5
-rw-r--r--spaghetti-monster/anduril/load-save-config.h5
-rw-r--r--spaghetti-monster/anduril/off-mode.c30
-rw-r--r--spaghetti-monster/anduril/ramp-mode.c44
-rw-r--r--spaghetti-monster/anduril/ramp-mode.h21
-rw-r--r--spaghetti-monster/anduril/smooth-steps.c45
-rw-r--r--spaghetti-monster/anduril/smooth-steps.h19
10 files changed, 184 insertions, 16 deletions
diff --git a/spaghetti-monster/anduril/anduril-manual.txt b/spaghetti-monster/anduril/anduril-manual.txt
index 1d5bc46..d47cc57 100644
--- a/spaghetti-monster/anduril/anduril-manual.txt
+++ b/spaghetti-monster/anduril/anduril-manual.txt
@@ -222,6 +222,9 @@ While the light is on, a few actions are available:
2: Anduril 2 style. Ramp -> 2C goes to ceiling,
or goes to full power if user ramped up to ceiling first.
This value also affects momentary turbo in Ramp and Off modes.
+ - Item 5: Configure "smooth steps".
+ 0: Disable smooth steps.
+ 1: Enable smooth steps.
Memory determines which brightness level the light goes to with 1 click
from off. There are three types of brightness memory to choose from:
@@ -252,6 +255,11 @@ To choose a memory style, set the configuration accordingly:
manual on zero
hybrid on non-zero
+If "smooth steps" is enabled, the stepped ramp uses a smooth animation
+between steps, and turning the light on/off has the edges smoothed off
+too. With "smooth steps" turned off, these brightness changes are
+immediate.
+
Sunset Timer
------------
@@ -904,6 +912,7 @@ Ramp Full 10H Ramp Extras config menu:
2: set manual mem timeout
3: ramp after moon or not
4: advanced UI turbo style
+ 5: smooth steps
Multi-channel lights only:
Any Any 3C Next channel mode (i.e. next color mode)
diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c
index 6399ef6..e46eeaf 100644
--- a/spaghetti-monster/anduril/anduril.c
+++ b/spaghetti-monster/anduril/anduril.c
@@ -142,6 +142,10 @@
#include "sos-mode.h"
#endif
+#ifdef USE_SMOOTH_STEPS
+#include "smooth-steps.h"
+#endif
+
// this should be last, so other headers have a chance to declare values
#include "load-save-config.h"
@@ -205,6 +209,10 @@
#include "sos-mode.c"
#endif
+#ifdef USE_SMOOTH_STEPS
+#include "smooth-steps.c"
+#endif
+
// runs one time at boot, when power is connected
void setup() {
@@ -335,6 +343,12 @@ void loop() {
}
#endif
+ #ifdef USE_SMOOTH_STEPS
+ else if (cfg.smooth_steps_style && smooth_steps_in_progress) {
+ smooth_steps_iter();
+ }
+ #endif
+
#ifdef USE_IDLE_MODE
else {
// doze until next clock tick
diff --git a/spaghetti-monster/anduril/config-default.h b/spaghetti-monster/anduril/config-default.h
index 8f07e47..b66a645 100644
--- a/spaghetti-monster/anduril/config-default.h
+++ b/spaghetti-monster/anduril/config-default.h
@@ -187,3 +187,11 @@
#define USE_STEPPED_TINT_RAMPING
#define DEFAULT_TINT_RAMP_STYLE 0 // smooth
+// Use "smooth steps" to soften on/off and step changes
+// on MCUs with enough room for extra stuff like this
+#if (ATTINY==1616) || (ATTINY==1634)
+#define USE_SMOOTH_STEPS
+#endif
+// 0 = none, 1 = smooth, 2+ = undefined
+#define DEFAULT_SMOOTH_STEPS_STYLE 1
+
diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h
index 7bf87f4..0a9cabd 100644
--- a/spaghetti-monster/anduril/load-save-config-fsm.h
+++ b/spaghetti-monster/anduril/load-save-config-fsm.h
@@ -67,6 +67,11 @@ typedef struct Config {
#endif
#endif
+ ///// Smooth animation between steps, and for on/off
+ #ifdef USE_SMOOTH_STEPS
+ uint8_t smooth_steps_style;
+ #endif
+
///// strobe / blinky mode settings
#ifdef USE_STROBE_STATE
uint8_t strobe_type;
diff --git a/spaghetti-monster/anduril/load-save-config.h b/spaghetti-monster/anduril/load-save-config.h
index 2dfa8c9..c70bb2b 100644
--- a/spaghetti-monster/anduril/load-save-config.h
+++ b/spaghetti-monster/anduril/load-save-config.h
@@ -94,6 +94,11 @@ Config cfg = {
#endif
#endif
+ ///// Smooth animation between steps, and for on/off
+ #ifdef USE_SMOOTH_STEPS
+ .smooth_steps_style = DEFAULT_SMOOTH_STEPS_STYLE,
+ #endif
+
///// strobe / blinky mode settings
#ifdef USE_STROBE_STATE
diff --git a/spaghetti-monster/anduril/off-mode.c b/spaghetti-monster/anduril/off-mode.c
index a484f06..af09d70 100644
--- a/spaghetti-monster/anduril/off-mode.c
+++ b/spaghetti-monster/anduril/off-mode.c
@@ -14,6 +14,12 @@ uint8_t off_state(Event event, uint16_t arg) {
// turn emitter off when entering state
if (event == EV_enter_state) {
+ #ifdef USE_SMOOTH_STEPS
+ if (cfg.smooth_steps_style && actual_level) {
+ set_level_smooth(0, 8);
+ arg = 1; // don't go to sleep immediately
+ } else
+ #endif
set_level(0);
ticks_since_on = 0;
#if NUM_CHANNEL_MODES > 1
@@ -24,7 +30,8 @@ uint8_t off_state(Event event, uint16_t arg) {
// redundant, sleep tick does the same thing
//indicator_led_update(cfg.indicator_led_mode & 0x03, 0);
#elif defined(USE_AUX_RGB_LEDS)
- rgb_led_update(cfg.rgb_led_off_mode, 0);
+ // redundant, sleep tick does the same thing
+ //rgb_led_update(cfg.rgb_led_off_mode, 0);
#endif
#ifdef USE_SUNSET_TIMER
sunset_timer = 0; // needs a reset in case previous timer was aborted
@@ -37,13 +44,18 @@ uint8_t off_state(Event event, uint16_t arg) {
// go back to sleep eventually if we got bumped but didn't leave "off" state
else if (event == EV_tick) {
- if (arg > HOLD_TIMEOUT) {
+ if (arg > HOLD_TIMEOUT
+ #ifdef USE_SMOOTH_STEPS
+ && (! smooth_steps_in_progress)
+ #endif
+ ) {
go_to_standby = 1;
#ifdef USE_INDICATOR_LED
// redundant, sleep tick does the same thing
//indicator_led_update(cfg.indicator_led_mode & 0x03, arg);
#elif defined(USE_AUX_RGB_LEDS)
- rgb_led_update(cfg.rgb_led_off_mode, arg);
+ // redundant, sleep tick does the same thing
+ //rgb_led_update(cfg.rgb_led_off_mode, arg);
#endif
}
return EVENT_HANDLED;
@@ -127,6 +139,11 @@ uint8_t off_state(Event event, uint16_t arg) {
manual_memory_restore();
}
#endif
+ #ifdef USE_SMOOTH_STEPS
+ if (cfg.smooth_steps_style)
+ set_level_smooth(nearest_level(memorized_level), 8);
+ else
+ #endif
set_level(nearest_level(memorized_level));
return EVENT_HANDLED;
}
@@ -135,8 +152,7 @@ uint8_t off_state(Event event, uint16_t arg) {
// 1 click: regular mode
else if (event == EV_1click) {
#if (B_TIMING_ON != B_TIMEOUT_T)
- // brightness was already set; reuse previous value
- set_state(steady_state, actual_level);
+ set_state(steady_state, memorized_level);
#else
// FIXME: B_TIMEOUT_T breaks manual_memory and manual_memory_timer
// (need to duplicate manual mem logic here, probably)
@@ -186,6 +202,10 @@ uint8_t off_state(Event event, uint16_t arg) {
// 3 clicks (initial press): off, to prep for later events
else if (event == EV_click3_press) {
+ #ifdef USE_SMOOTH_STEPS
+ // immediately cancel any animations in progress
+ smooth_steps_in_progress = 0;
+ #endif
set_level(0);
return EVENT_HANDLED;
}
diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c
index f21f599..c4c995f 100644
--- a/spaghetti-monster/anduril/ramp-mode.c
+++ b/spaghetti-monster/anduril/ramp-mode.c
@@ -10,6 +10,10 @@
#include "sunset-timer.h"
#endif
+#ifdef USE_SMOOTH_STEPS
+#include "smooth-steps.h"
+#endif
+
uint8_t steady_state(Event event, uint16_t arg) {
static int8_t ramp_direction = 1;
@@ -554,21 +558,25 @@ uint8_t simple_ui_config_state(Event event, uint16_t arg) {
#ifdef USE_RAMP_EXTRAS_CONFIG
void ramp_extras_config_save(uint8_t step, uint8_t value) {
// item 1: disable manual memory, go back to automatic
- if (1 == step) { cfg.manual_memory = 0; }
+ if (manual_memory_config_step == step) {
+ cfg.manual_memory = 0;
+ }
#ifdef USE_MANUAL_MEMORY_TIMER
// item 2: set manual memory timer duration
// FIXME: should be limited to (65535 / SLEEP_TICKS_PER_MINUTE)
// to avoid overflows or impossibly long timeouts
// (by default, the effective limit is 145, but it allows up to 255)
- else if (2 == step) { cfg.manual_memory_timer = value; }
+ else if (manual_memory_timer_config_step == step) {
+ cfg.manual_memory_timer = value;
+ }
#endif
#ifdef USE_RAMP_AFTER_MOON_CONFIG
// item 3: ramp up after hold-from-off for moon?
// 0 = yes, ramp after moon
// 1+ = no, stay at moon
- else if (3 == step) {
+ else if (dont_ramp_after_moon_config_step == step) {
cfg.dont_ramp_after_moon = value;
}
#endif
@@ -577,14 +585,22 @@ void ramp_extras_config_save(uint8_t step, uint8_t value) {
// item 4: Anduril 1 2C turbo, or Anduril 2 2C ceiling?
// 1 = Anduril 1, 2C turbo
// 2+ = Anduril 2, 2C ceiling
- else if (4 == step) {
+ else if (ramp_2c_style_config_step == step) {
cfg.ramp_2c_style = value;
}
#endif
+
+ #ifdef USE_SMOOTH_STEPS
+ else if (smooth_steps_style_config_step == step) {
+ cfg.smooth_steps_style = value;
+ }
+ #endif
}
uint8_t ramp_extras_config_state(Event event, uint16_t arg) {
- return config_state_base(event, arg, 4, ramp_extras_config_save);
+ return config_state_base(event, arg,
+ ramp_extras_config_num_steps - 1,
+ ramp_extras_config_save);
}
#endif
@@ -592,16 +608,17 @@ uint8_t ramp_extras_config_state(Event event, uint16_t arg) {
void globals_config_save(uint8_t step, uint8_t value) {
if (0) {}
#if defined(USE_CHANNEL_MODE_ARGS) && defined(USE_STEPPED_TINT_RAMPING)
- else if (step == 1+tint_style_config_step) { cfg.tint_ramp_style = value; }
+ else if (step == tint_style_config_step) { cfg.tint_ramp_style = value; }
#endif
#ifdef USE_JUMP_START
- else if (step == 1+jump_start_config_step) { cfg.jump_start_level = value; }
+ else if (step == jump_start_config_step) { cfg.jump_start_level = value; }
#endif
}
uint8_t globals_config_state(Event event, uint16_t arg) {
- // TODO: set number of steps based on how many configurable options
- return config_state_base(event, arg, globals_config_num_steps, globals_config_save);
+ return config_state_base(event, arg,
+ globals_config_num_steps - 1,
+ globals_config_save);
}
#endif
@@ -657,9 +674,16 @@ void ramp_update_config() {
ramp_ceil = cfg.ramp_ceils[which];
}
-#ifdef USE_THERMAL_REGULATION
+#if defined(USE_THERMAL_REGULATION) || defined(USE_SMOOTH_STEPS)
void set_level_and_therm_target(uint8_t level) {
+ #ifdef USE_THERMAL_REGULATION
target_level = level;
+ #endif
+ #ifdef USE_SMOOTH_STEPS
+ if (cfg.smooth_steps_style && cfg.ramp_style)
+ set_level_smooth(level, 4);
+ else
+ #endif
set_level(level);
}
#else
diff --git a/spaghetti-monster/anduril/ramp-mode.h b/spaghetti-monster/anduril/ramp-mode.h
index 20986cc..21e2149 100644
--- a/spaghetti-monster/anduril/ramp-mode.h
+++ b/spaghetti-monster/anduril/ramp-mode.h
@@ -186,10 +186,29 @@ uint8_t sunset_timer_orig_level = 0;
void reset_sunset_timer();
#endif
+#ifdef USE_RAMP_EXTRAS_CONFIG
+typedef enum {
+ manual_memory_config_step = 1,
+ #ifdef USE_MANUAL_MEMORY_TIMER
+ manual_memory_timer_config_step,
+ #endif
+ #ifdef USE_RAMP_AFTER_MOON_CONFIG
+ dont_ramp_after_moon_config_step,
+ #endif
+ #ifdef USE_2C_STYLE_CONFIG
+ ramp_2c_style_config_step,
+ #endif
+ #ifdef USE_SMOOTH_STEPS
+ smooth_steps_style_config_step,
+ #endif
+ ramp_extras_config_num_steps
+} ramp_extras_config_steps_e;
+#endif
+
#ifdef USE_GLOBALS_CONFIG
typedef enum {
#if defined(USE_CHANNEL_MODE_ARGS) && defined(USE_STEPPED_TINT_RAMPING)
- tint_style_config_step,
+ tint_style_config_step = 1,
#endif
#ifdef USE_JUMP_START
jump_start_config_step,
diff --git a/spaghetti-monster/anduril/smooth-steps.c b/spaghetti-monster/anduril/smooth-steps.c
new file mode 100644
index 0000000..9a09228
--- /dev/null
+++ b/spaghetti-monster/anduril/smooth-steps.c
@@ -0,0 +1,45 @@
+// smooth-steps.c: Smooth step adjustments for Anduril.
+// Copyright (C) 2023 Selene ToyKeeper
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "smooth-steps.h"
+
+#ifdef USE_SMOOTH_STEPS
+
+// one iteration of main loop()
+void smooth_steps_iter() {
+ if (actual_level == smooth_steps_target) {
+ smooth_steps_in_progress = 0;
+ // restore prev_level when animation ends
+ prev_level = smooth_steps_start;
+ return;
+ }
+
+ if (actual_level < smooth_steps_target) {
+ uint8_t diff = smooth_steps_target - actual_level;
+ uint8_t this = diff / smooth_steps_speed;
+ if (!this) this = 1;
+ set_level(actual_level + this);
+ } else if (actual_level > smooth_steps_target) {
+ uint8_t diff = actual_level - smooth_steps_target;
+ uint8_t this = diff / smooth_steps_speed;
+ if (!this) this = 1;
+ set_level(actual_level - this);
+ }
+ // TODO: maybe change the delay based on the speed var?
+ nice_delay_ms(10);
+}
+
+void set_level_smooth(uint8_t level, uint8_t speed) {
+ smooth_steps_target = level;
+ // TODO: maybe speed should be a desired total time for the animation?
+ smooth_steps_speed = speed;
+ smooth_steps_in_progress = 1;
+ // for setting prev_level after animation ends
+ smooth_steps_start = actual_level;
+}
+
+#endif
+
diff --git a/spaghetti-monster/anduril/smooth-steps.h b/spaghetti-monster/anduril/smooth-steps.h
new file mode 100644
index 0000000..a553af2
--- /dev/null
+++ b/spaghetti-monster/anduril/smooth-steps.h
@@ -0,0 +1,19 @@
+// smooth-steps.h: Smooth step adjustments for Anduril.
+// Copyright (C) 2023 Selene ToyKeeper
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#ifdef USE_SMOOTH_STEPS
+
+uint8_t smooth_steps_start;
+uint8_t smooth_steps_target;
+uint8_t smooth_steps_in_progress;
+uint8_t smooth_steps_speed;
+
+void smooth_steps_iter();
+
+void set_level_smooth(uint8_t level, uint8_t speed);
+
+#endif
+