aboutsummaryrefslogtreecommitdiff
path: root/fsm/ramping.c
diff options
context:
space:
mode:
authorSelene ToyKeeper2023-11-02 17:16:25 -0600
committerSelene ToyKeeper2023-11-02 17:16:25 -0600
commit7cb4fe0944b839f28dfd96a88a772cd6a8b58019 (patch)
tree8d3b203f1650edc28b1f67e1589e3bc870b33fa6 /fsm/ramping.c
parentadded LICENSE (GPLv3) (diff)
downloadanduril-7cb4fe0944b839f28dfd96a88a772cd6a8b58019.tar.gz
anduril-7cb4fe0944b839f28dfd96a88a772cd6a8b58019.tar.bz2
anduril-7cb4fe0944b839f28dfd96a88a772cd6a8b58019.zip
reorganized project files (part 1)
(just moved files, didn't change the contents yet, and nothing will work without updating #includes and build scripts and stuff)
Diffstat (limited to 'fsm/ramping.c')
-rw-r--r--fsm/ramping.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/fsm/ramping.c b/fsm/ramping.c
new file mode 100644
index 0000000..adc8acb
--- /dev/null
+++ b/fsm/ramping.c
@@ -0,0 +1,259 @@
+// fsm-ramping.c: Ramping functions for SpaghettiMonster.
+// Copyright (C) 2017-2023 Selene ToyKeeper
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#ifdef USE_RAMPING
+
+#ifdef HAS_AUX_LEDS
+inline void set_level_aux_leds(uint8_t level) {
+ #ifdef USE_INDICATOR_LED_WHILE_RAMPING
+ // use side-facing aux LEDs while main LEDs are on
+ if (! go_to_standby) {
+ #ifdef USE_INDICATOR_LED
+ indicator_led((level > 0) + (level > DEFAULT_LEVEL));
+ #endif
+ #ifdef USE_BUTTON_LED
+ button_led_set((level > 0) + (level > DEFAULT_LEVEL));
+ #endif
+ }
+ #else // turn off front-facing aux LEDs while main LEDs are on
+ #if defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS)
+ if (! go_to_standby) {
+ #ifdef USE_INDICATOR_LED
+ indicator_led(0);
+ #endif
+ #ifdef USE_AUX_RGB_LEDS
+ rgb_led_set(0);
+ #ifdef USE_BUTTON_LED
+ button_led_set((level > 0) + (level > DEFAULT_LEVEL));
+ #endif
+ #endif
+ }
+ #endif
+ #endif
+}
+#endif // ifdef HAS_AUX_LEDS
+
+#ifdef USE_AUX_RGB_LEDS_WHILE_ON
+// TODO: maybe move this stuff into FSM
+#include "anduril/aux-leds.h" // for rgb_led_voltage_readout()
+inline void set_level_aux_rgb_leds(uint8_t level) {
+ if (! go_to_standby) {
+ if (level > 0) {
+ rgb_led_voltage_readout(level > USE_AUX_RGB_LEDS_WHILE_ON);
+ } else {
+ rgb_led_set(0);
+ }
+ // some drivers can be wired with RGB or single color to button
+ // ... so support both even though only one is connected
+ #ifdef USE_BUTTON_LED
+ button_led_set((level > 0) + (level > DEFAULT_LEVEL));
+ #endif
+ }
+}
+#endif // ifdef USE_AUX_RGB_LEDS_WHILE_ON
+
+
+void set_level(uint8_t level) {
+ #ifdef USE_JUMP_START
+ // maybe "jump start" the engine, if it's prone to slow starts
+ // (pulse the output high for a moment to wake up the power regulator)
+ // (only do this when starting from off and going to a low level)
+ // TODO: allow different jump start behavior per channel mode
+ // FIXME: don't jump-start during factory reset
+ // (it seems to cause some eeprom issues on KR4
+ // when doing a click with a loose tailcap)
+ if ((! actual_level)
+ && level
+ && (level < JUMP_START_LEVEL)) {
+ set_level(JUMP_START_LEVEL);
+ delay_4ms(JUMP_START_TIME/4);
+ }
+ #endif
+
+ #ifdef HAS_AUX_LEDS
+ set_level_aux_leds(level);
+ #endif
+
+ #ifdef USE_AUX_RGB_LEDS_WHILE_ON
+ set_level_aux_rgb_leds(level);
+ #endif
+
+ if (0 == level) {
+ set_level_zero();
+ } else {
+ // call the relevant hardware-specific set_level_*()
+ SetLevelFuncPtr set_level_func = channels[channel_mode].set_level;
+ set_level_func(level - 1);
+ }
+
+ if (actual_level != level) prev_level = actual_level;
+ actual_level = level;
+
+ #ifdef USE_SET_LEVEL_GRADUALLY
+ gradual_target = level;
+ #endif
+
+ #ifdef USE_DYNAMIC_UNDERCLOCKING
+ auto_clock_speed();
+ #endif
+}
+
+#ifdef USE_LEGACY_SET_LEVEL
+// (this is mostly just here for reference, temporarily)
+// single set of LEDs with 1 to 3 stacked power channels,
+// like linear, FET+1, and FET+N+1
+// (default set_level_*() function for most lights)
+void set_level_legacy(uint8_t level) {
+ if (level == 0) {
+ #if PWM_CHANNELS >= 1
+ PWM1_LVL = 0;
+ #endif
+ #if PWM_CHANNELS >= 2
+ PWM2_LVL = 0;
+ #endif
+ #if PWM_CHANNELS >= 3
+ PWM3_LVL = 0;
+ #endif
+ #if defined(PWM1_CNT) && defined(PWM1_PHASE_RESET_OFF)
+ PWM1_CNT = 0;
+ #endif
+ #if defined(PWM2_CNT) && defined(PWM2_PHASE_RESET_OFF)
+ PWM2_CNT = 0;
+ #endif
+ #if defined(PWM3_CNT) && defined(PWM3_PHASE_RESET_OFF)
+ PWM3_CNT = 0;
+ #endif
+ #ifdef LED_OFF_DELAY
+ // for drivers with a slow regulator chip (eg, boost converter),
+ // delay before turning off to prevent flashes
+ delay_4ms(LED_OFF_DELAY/4);
+ #endif
+ // disable the power channel, if relevant
+ #ifdef LED_ENABLE_PIN
+ LED_ENABLE_PORT &= ~(1 << LED_ENABLE_PIN);
+ #endif
+ #ifdef LED2_ENABLE_PIN
+ LED2_ENABLE_PORT &= ~(1 << LED2_ENABLE_PIN);
+ #endif
+ } else {
+ // enable the power channel, if relevant
+ #ifdef LED_ENABLE_PIN
+ #ifdef LED_ON_DELAY
+ uint8_t led_enable_port_save = LED_ENABLE_PORT;
+ #endif
+
+ #ifndef LED_ENABLE_PIN_LEVEL_MIN
+ LED_ENABLE_PORT |= (1 << LED_ENABLE_PIN);
+ #else
+ // only enable during part of the ramp
+ if ((level >= LED_ENABLE_PIN_LEVEL_MIN)
+ && (level <= LED_ENABLE_PIN_LEVEL_MAX))
+ LED_ENABLE_PORT |= (1 << LED_ENABLE_PIN);
+ else // disable during other parts of the ramp
+ LED_ENABLE_PORT &= ~(1 << LED_ENABLE_PIN);
+ #endif
+
+ // for drivers with a slow regulator chip (eg, boost converter),
+ // delay before lighting up to prevent flashes
+ #ifdef LED_ON_DELAY
+ // only delay if the pin status changed
+ if (LED_ENABLE_PORT != led_enable_port_save)
+ delay_4ms(LED_ON_DELAY/4);
+ #endif
+ #endif
+ #ifdef LED2_ENABLE_PIN
+ #ifdef LED2_ON_DELAY
+ uint8_t led2_enable_port_save = LED2_ENABLE_PORT;
+ #endif
+
+ LED2_ENABLE_PORT |= (1 << LED2_ENABLE_PIN);
+
+ // for drivers with a slow regulator chip (eg, boost converter),
+ // delay before lighting up to prevent flashes
+ #ifdef LED2_ON_DELAY
+ // only delay if the pin status changed
+ if (LED2_ENABLE_PORT != led2_enable_port_save)
+ delay_4ms(LED2_ON_DELAY/4);
+ #endif
+ #endif
+
+ // PWM array index = level - 1
+ level --;
+
+ #if PWM_CHANNELS >= 1
+ PWM1_LVL = PWM_GET(pwm1_levels, level);
+ #endif
+ #if PWM_CHANNELS >= 2
+ PWM2_LVL = PWM_GET(pwm2_levels, level);
+ #endif
+ #if PWM_CHANNELS >= 3
+ PWM3_LVL = PWM_GET(pwm3_levels, level);
+ #endif
+
+ #ifdef USE_DYN_PWM
+ uint16_t top = PWM_GET(pwm_tops, level);
+ #if defined(PWM1_CNT) && defined(PWM1_PHASE_SYNC)
+ // wait to ensure compare match won't be missed
+ // (causes visible flickering when missed, because the counter
+ // goes all the way to 65535 before returning)
+ // (see attiny1634 reference manual page 103 for a warning about
+ // the timing of changing the TOP value (section 12.8.4))
+ // (but don't wait when turning on from zero, because
+ // it'll reset the phase below anyway)
+ // to be safe, allow at least 32 cycles to update TOP
+ while(actual_level && (PWM1_CNT > (top - 32))) {}
+ #endif
+ // pulse frequency modulation, a.k.a. dynamic PWM
+ PWM1_TOP = top;
+ #endif // ifdef USE_DYN_PWM
+ #if defined(PWM1_CNT) && defined(PWM1_PHASE_RESET_ON)
+ // force reset phase when turning on from zero
+ // (because otherwise the initial response is inconsistent)
+ if (! actual_level) {
+ PWM1_CNT = 0;
+ #if defined(PWM2_CNT) && defined(PWM2_PHASE_RESET_ON)
+ PWM2_CNT = 0;
+ #endif
+ #if defined(PWM3_CNT) && defined(PWM3_PHASE_RESET_ON)
+ PWM3_CNT = 0;
+ #endif
+ }
+ #endif
+ }
+ #ifdef USE_DYNAMIC_UNDERCLOCKING
+ auto_clock_speed();
+ #endif
+}
+#endif
+
+
+#ifdef USE_SET_LEVEL_GRADUALLY
+inline void set_level_gradually(uint8_t lvl) {
+ gradual_target = lvl;
+}
+
+
+// call this every frame or every few frames to change brightness very smoothly
+void gradual_tick() {
+ uint8_t gt = gradual_target;
+ if (gt < actual_level) gt = actual_level - 1;
+ else if (gt > actual_level) gt = actual_level + 1;
+
+ // call the relevant hardware-specific function
+ GradualTickFuncPtr gradual_tick_func = channels[channel_mode].gradual_tick;
+ bool done = gradual_tick_func(gt - 1);
+
+ if (done) {
+ uint8_t orig = gradual_target;
+ set_level(gt);
+ gradual_target = orig;
+ }
+}
+#endif // ifdef USE_SET_LEVEL_GRADUALLY
+
+
+#endif // ifdef USE_RAMPING
+