From 7cb4fe0944b839f28dfd96a88a772cd6a8b58019 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 2 Nov 2023 17:16:25 -0600 Subject: 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) --- fsm/ramping.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 fsm/ramping.c (limited to 'fsm/ramping.c') 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 + -- cgit v1.2.3