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
+
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.