diff options
Diffstat (limited to 'fsm/standby.c')
| -rw-r--r-- | fsm/standby.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/fsm/standby.c b/fsm/standby.c new file mode 100644 index 0000000..5def07c --- /dev/null +++ b/fsm/standby.c @@ -0,0 +1,105 @@ +// fsm-standby.c: standby mode functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <avr/interrupt.h> +#include <avr/sleep.h> + +#include "fsm-adc.h" +#include "fsm-wdt.h" +#include "fsm-pcint.h" + +// low-power standby mode used while off but power still connected +#define standby_mode sleep_until_eswitch_pressed +void sleep_until_eswitch_pressed() +{ + #ifdef TICK_DURING_STANDBY + WDT_slow(); + #else + WDT_off(); + #endif + + ADC_off(); + + // make sure switch isn't currently pressed + while (button_is_pressed()) {} + empty_event_sequence(); // cancel pending input on suspend + + PCINT_on(); // wake on e-switch event + + #ifdef TICK_DURING_STANDBY + // detect which type of event caused a wake-up + irq_adc = 0; + irq_wdt = 0; + irq_pcint = 0; + while (go_to_standby) { + #else + go_to_standby = 0; + #endif + + // configure sleep mode + #ifdef TICK_DURING_STANDBY + // needs a special sleep mode during measurements + if (adc_active_now) adc_sleep_mode(); + else + #endif + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + + sleep_enable(); + #ifdef BODCR // only do this on MCUs which support it + sleep_bod_disable(); + #endif + sleep_cpu(); // wait here + + // something happened; wake up + sleep_disable(); + + #ifdef TICK_DURING_STANDBY + // determine what woke us up... + if (irq_pcint) { // button pressed; wake up + go_to_standby = 0; + } + if (irq_adc) { // ADC done measuring + #ifndef USE_LOWPASS_WHILE_ASLEEP + adc_reset = 1; // don't lowpass while asleep + #endif + adc_deferred_enable = 1; + adc_deferred(); + //ADC_off(); // takes care of itself + //irq_adc = 0; // takes care of itself + } + if (irq_wdt) { // generate a sleep tick + WDT_inner(); + } + } + #endif + + // don't lowpass immediately after waking + // also, reset thermal history + adc_reset = 2; + + // go back to normal running mode + // PCINT not needed any more, and can cause problems if on + // (occasional reboots on wakeup-by-button-press) + PCINT_off(); + // restore normal awake-mode interrupts + ADC_on(); + WDT_on(); +} + +#ifdef USE_IDLE_MODE +void idle_mode() +{ + // configure sleep mode + set_sleep_mode(SLEEP_MODE_IDLE); + + sleep_enable(); + sleep_cpu(); // wait here + + // something happened; wake up + sleep_disable(); +} +#endif + |
