diff options
Diffstat (limited to 'spaghetti-monster')
28 files changed, 572 insertions, 596 deletions
diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 07560bc..e180cc4 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -104,7 +104,6 @@ #include "off-mode.h" #include "ramp-mode.h" -#include "load-save-config.h" #include "config-mode.h" #include "aux-leds.h" #include "misc.h" @@ -158,6 +157,9 @@ #include "sos-mode.h" #endif +// this should be last, so other headers have a chance to declare values +#include "load-save-config.h" + /********* Include all the app logic source files *********/ // (is a bit weird to do things this way, @@ -239,7 +241,7 @@ void setup() { #if defined(USE_MANUAL_MEMORY) && defined(USE_MANUAL_MEMORY_TIMER) // without this, initial boot-up brightness is wrong // when manual mem is enabled with a non-zero timer - if (manual_memory) manual_memory_restore(); + if (cfg.manual_memory) manual_memory_restore(); #endif #if defined(USE_CHANNEL_MODES) @@ -321,7 +323,7 @@ void loop() { // in simple mode, turn off after one readout // FIXME: can eat the next button press // (state changes in loop() act weird) - if (simple_ui_active) set_state_deferred(off_state, 0); + if (cfg.simple_ui_active) set_state_deferred(off_state, 0); else nice_delay_ms(1000); #endif } diff --git a/spaghetti-monster/anduril/aux-leds.h b/spaghetti-monster/anduril/aux-leds.h index 71a14e3..f496ddc 100644 --- a/spaghetti-monster/anduril/aux-leds.h +++ b/spaghetti-monster/anduril/aux-leds.h @@ -61,8 +61,6 @@ const PROGMEM uint8_t rgb_led_colors[] = { #ifndef RGB_RAINBOW_SPEED #define RGB_RAINBOW_SPEED 0x0f // change color every 16 frames #endif -uint8_t rgb_led_off_mode = RGB_LED_OFF_DEFAULT; -uint8_t rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT; #endif //#define USE_OLD_BLINKING_INDICATOR @@ -71,14 +69,11 @@ uint8_t rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT; // bits 2-3 control lockout mode // bits 0-1 control "off" mode // modes are: 0=off, 1=low, 2=high, 3=blinking (if TICK_DURING_STANDBY enabled) - #ifdef INDICATOR_LED_DEFAULT_MODE - uint8_t indicator_led_mode = INDICATOR_LED_DEFAULT_MODE; - #else + #ifndef INDICATOR_LED_DEFAULT_MODE #ifdef USE_INDICATOR_LED_WHILE_RAMPING - //uint8_t indicator_led_mode = (1<<2) + 2; - uint8_t indicator_led_mode = (2<<2) + 1; + #define INDICATOR_LED_DEFAULT_MODE ((2<<2) + 1) #else - uint8_t indicator_led_mode = (3<<2) + 1; + #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) #endif #endif #endif diff --git a/spaghetti-monster/anduril/battcheck-mode.c b/spaghetti-monster/anduril/battcheck-mode.c index d34559b..5edc6f4 100644 --- a/spaghetti-monster/anduril/battcheck-mode.c +++ b/spaghetti-monster/anduril/battcheck-mode.c @@ -25,7 +25,7 @@ uint8_t battcheck_state(Event event, uint16_t arg) { ////////// Every action below here is blocked in the simple UI ////////// #ifdef USE_SIMPLE_UI - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif @@ -69,7 +69,7 @@ uint8_t battcheck_state(Event event, uint16_t arg) { // ... // 13 = add 0.30V void voltage_config_save(uint8_t step, uint8_t value) { - if (value) voltage_correction = value; + if (value) cfg.voltage_correction = value; } uint8_t voltage_config_state(Event event, uint16_t arg) { diff --git a/spaghetti-monster/anduril/beacon-mode.c b/spaghetti-monster/anduril/beacon-mode.c index e8e5004..76ada0f 100644 --- a/spaghetti-monster/anduril/beacon-mode.c +++ b/spaghetti-monster/anduril/beacon-mode.c @@ -28,7 +28,7 @@ inline void beacon_mode_iter() { set_level(memorized_level); nice_delay_ms(100); set_level(0); - nice_delay_ms(((beacon_seconds) * 1000) - 100); + nice_delay_ms(((cfg.beacon_seconds) * 1000) - 100); } } @@ -61,7 +61,7 @@ uint8_t beacon_state(Event event, uint16_t arg) { } // release hold: save new timing else if (event == EV_click1_hold_release) { - beacon_seconds = 1 + (arg / TICKS_PER_SECOND); + cfg.beacon_seconds = 1 + (arg / TICKS_PER_SECOND); save_config(); return MISCHIEF_MANAGED; } diff --git a/spaghetti-monster/anduril/beacon-mode.h b/spaghetti-monster/anduril/beacon-mode.h index 752918e..c0f0b18 100644 --- a/spaghetti-monster/anduril/beacon-mode.h +++ b/spaghetti-monster/anduril/beacon-mode.h @@ -20,9 +20,6 @@ #ifndef BEACON_MODE_H #define BEACON_MODE_H -// beacon timing -uint8_t beacon_seconds = 2; - // beacon mode uint8_t beacon_state(Event event, uint16_t arg); inline void beacon_mode_iter(); diff --git a/spaghetti-monster/anduril/channel-modes.c b/spaghetti-monster/anduril/channel-modes.c index 958b375..f3a21cf 100644 --- a/spaghetti-monster/anduril/channel-modes.c +++ b/spaghetti-monster/anduril/channel-modes.c @@ -20,7 +20,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { // in addition to changing state... so ignore any tint-ramp events which // don't look like they were meant to be here static uint8_t active = 0; - uint8_t tint = channel_mode_args[channel_mode]; + uint8_t tint = cfg.channel_mode_args[cfg.channel_mode]; #endif // it's possible that a light may need 3H but not 3C, @@ -28,7 +28,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { #if NUM_CHANNEL_MODES > 1 // 3 clicks: next channel mode if (event == EV_3clicks) { - uint8_t next = channel_mode; + uint8_t next = cfg.channel_mode; // go to next channel mode until we find one which is enabled // (and don't do any infinite loops if the user disabled them all) uint8_t count = 0; @@ -39,10 +39,10 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { //} while ((! channel_modes_enabled[next]) && count < NUM_CHANNEL_MODES); // undo change if infinite loop detected (redundant?) - //if (NUM_CHANNEL_MODES == count) next = channel_mode; + //if (NUM_CHANNEL_MODES == count) next = cfg.channel_mode; // if mode hasn't changed, abort - if (channel_mode == next) + if (cfg.channel_mode == next) return EVENT_NOT_HANDLED; set_channel_mode(next); @@ -55,9 +55,9 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { #ifdef USE_CUSTOM_CHANNEL_3H_MODES // defer to mode-specific function if defined - if (tint_ramp_modes[channel_mode]) { - StatePtr tint_func = channel_3H_modes[channel_mode]; - return tint_func(channel_mode); + if (tint_ramp_modes[cfg.channel_mode]) { + StatePtr tint_func = channel_3H_modes[cfg.channel_mode]; + return tint_func(cfg.channel_mode); } else #endif #ifdef USE_CHANNEL_MODE_ARGS @@ -86,7 +86,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { past_edge_counter = 1; } prev_tint = tint; - channel_mode_args[channel_mode] = tint; + cfg.channel_mode_args[cfg.channel_mode] = tint; set_level(actual_level); return EVENT_HANDLED; } @@ -99,7 +99,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { if (0 == tint) tint_ramp_direction = 1; else if (255 == tint) tint_ramp_direction = -1; // remember tint after battery change - channel_mode_args[channel_mode] = tint; + cfg.channel_mode_args[cfg.channel_mode] = tint; save_config(); // bug?: for some reason, brightness can seemingly change // from 1/150 to 2/150 without this next line... not sure why @@ -111,7 +111,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { #if defined(USE_SIMPLE_UI) // remaining mappings aren't "simple", so stop here - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif diff --git a/spaghetti-monster/anduril/channel-modes.h b/spaghetti-monster/anduril/channel-modes.h index 167c293..c10af5b 100644 --- a/spaghetti-monster/anduril/channel-modes.h +++ b/spaghetti-monster/anduril/channel-modes.h @@ -6,11 +6,6 @@ #pragma once -#if defined(USE_MANUAL_MEMORY) && defined(USE_CHANNEL_MODE_ARGS) -// remember and reset 1 extra parameter per channel mode (like tint) -uint8_t manual_memory_channel_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; -#endif - // not actually a mode, more of a fallback under other modes uint8_t channel_mode_state(Event event, uint16_t arg); diff --git a/spaghetti-monster/anduril/config-mode.c b/spaghetti-monster/anduril/config-mode.c index a74bdbe..394998a 100644 --- a/spaghetti-monster/anduril/config-mode.c +++ b/spaghetti-monster/anduril/config-mode.c @@ -34,7 +34,7 @@ uint8_t config_state_base( #endif if (event == EV_enter_state) { #ifdef USE_CONFIG_COLORS - orig_channel = channel_mode; + orig_channel = cfg.channel_mode; #endif config_step = 0; set_level(0); diff --git a/spaghetti-monster/anduril/factory-reset.c b/spaghetti-monster/anduril/factory-reset.c index a14b5b9..1e9714a 100644 --- a/spaghetti-monster/anduril/factory-reset.c +++ b/spaghetti-monster/anduril/factory-reset.c @@ -8,7 +8,6 @@ // allows setting channel mode per animation stage, // so it can ramp up in red then explode in white (as one example) -// TODO: maybe also do the same in menus? void factory_reset() { // display a warning for a few seconds before doing the actual reset, @@ -38,7 +37,7 @@ void factory_reset() { // AVR 1-Series has factory calibrated thermal sensor, always remove the offset on reset #if defined(USE_THERMAL_REGULATION) && defined(AVRXMEGA3) // this will cancel out the offset - thermal_config_save(1, temperature - therm_cal_offset); + thermal_config_save(1, temperature - cfg.therm_cal_offset); #elif defined(USE_THERMAL_REGULATION) && defined(USE_THERM_AUTOCALIBRATE) // assume current temperature is 21 C thermal_config_save(1, 21); diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h index 9004f1f..ef079db 100644 --- a/spaghetti-monster/anduril/load-save-config-fsm.h +++ b/spaghetti-monster/anduril/load-save-config-fsm.h @@ -1,127 +1,122 @@ -/* - * load-save-config-fsm.h: FSM config for eeprom configuration in Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef LOAD_SAVE_CONFIG_FSM_H -#define LOAD_SAVE_CONFIG_FSM_H +// load-save-config-fsm.h: FSM config for eeprom configuration in Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once -// auto-detect how many eeprom bytes #define USE_EEPROM -typedef enum { - ramp_style_e, - #ifdef USE_RAMP_CONFIG - ramp_smooth_floor_e, - ramp_smooth_ceil_e, - #ifdef USE_RAMP_SPEED_CONFIG - ramp_speed_e, +// load into a custom RAM location instead of FSM's default byte array +#define EEPROM_OVERRIDE + +#ifdef USE_SIMPLE_UI +#define NUM_RAMPS 3 +#else +#define NUM_RAMPS 2 +#endif + +// let FSM know this config struct exists +#define USE_CFG + +typedef struct Config { + + ///// ramp vars + uint8_t ramp_style; + #ifdef USE_2C_STYLE_CONFIG + uint8_t ramp_2c_style; #endif - ramp_discrete_floor_e, - ramp_discrete_ceil_e, - ramp_discrete_steps_e, + #ifdef USE_RAMP_CONFIG + uint8_t ramp_floors[NUM_RAMPS]; + uint8_t ramp_ceils [NUM_RAMPS]; + uint8_t ramp_stepss[NUM_RAMPS]; #endif #ifdef USE_SIMPLE_UI - simple_ui_floor_e, - simple_ui_ceil_e, - simple_ui_steps_e, - simple_ui_active_e, - #ifdef USE_2C_STYLE_CONFIG - ramp_2c_style_simple_e, - #endif + uint8_t simple_ui_active; + #ifdef USE_2C_STYLE_CONFIG + uint8_t ramp_2c_style_simple; + #endif #endif #ifdef USE_RAMP_AFTER_MOON_CONFIG - dont_ramp_after_moon_e, - #endif - #ifdef USE_2C_STYLE_CONFIG - ramp_2c_style_e, + uint8_t dont_ramp_after_moon; #endif #ifdef USE_MANUAL_MEMORY - manual_memory_e, + uint8_t manual_memory; #ifdef USE_MANUAL_MEMORY_TIMER - manual_memory_timer_e, + uint8_t manual_memory_timer; #endif #endif - #ifdef USE_JUMP_START - jump_start_level_e, + + ///// channel modes / color modes + #if NUM_CHANNEL_MODES > 1 + uint8_t channel_mode; + uint8_t channel_modes_enabled; + #ifdef USE_MANUAL_MEMORY + uint8_t manual_memory_channel_mode; + #endif + #endif + #ifdef USE_CHANNEL_MODE_ARGS + // this is an array, needs a few bytes + uint8_t channel_mode_args[NUM_CHANNEL_MODES]; + #ifdef USE_MANUAL_MEMORY + uint8_t manual_memory_channel_args[NUM_CHANNEL_MODES]; + #endif #endif + + ///// strobe / blinky mode settings #ifdef USE_STROBE_STATE - strobe_type_e, + uint8_t strobe_type; #endif #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) - strobe_delays_0_e, - strobe_delays_1_e, + uint8_t strobe_delays[2]; #endif #ifdef USE_BIKE_FLASHER_MODE - bike_flasher_brightness_e, + uint8_t bike_flasher_brightness; #endif #ifdef USE_BEACON_MODE - beacon_seconds_e, - #endif - #ifdef USE_THERMAL_REGULATION - therm_ceil_e, - therm_cal_offset_e, + uint8_t beacon_seconds; #endif + + ///// voltage and temperature #ifdef USE_VOLTAGE_CORRECTION - voltage_correction_e, + uint8_t voltage_correction; + #endif + #ifdef USE_THERMAL_REGULATION + uint8_t therm_ceil; + uint8_t therm_cal_offset; #endif + + ///// aux LEDs #ifdef USE_INDICATOR_LED - indicator_led_mode_e, + uint8_t indicator_led_mode; #endif #ifdef USE_AUX_RGB_LEDS - rgb_led_off_mode_e, - rgb_led_lockout_mode_e, + uint8_t rgb_led_off_mode; + uint8_t rgb_led_lockout_mode; #endif + + ///// misc other mode settings #ifdef USE_AUTOLOCK - autolock_time_e, + uint8_t autolock_time; #endif #ifdef USE_TACTICAL_MODE - tactical_lvl_1_e, - tactical_lvl_2_e, - tactical_lvl_3_e, - #endif - #if NUM_CHANNEL_MODES > 1 - channel_mode_e, - channel_modes_enabled_e, - #if defined(USE_MANUAL_MEMORY) - manual_memory_channel_mode_e, - #endif + uint8_t tactical_levels[3]; #endif - #ifdef USE_CHANNEL_MODE_ARGS - // this is an array, needs a few bytes - channel_mode_args_e, - #if defined(USE_MANUAL_MEMORY) - // this is an array, needs a few bytes - manual_memory_channel_args_e = channel_mode_args_e + NUM_CHANNEL_MODES, - // and this is an ugly ugly kludge - // FIXME: use a struct for eeprom, not an array - eeprom_indexes_e_END = manual_memory_channel_args_e + NUM_CHANNEL_MODES - #else - eeprom_indexes_e_END = channel_mode_args_e + NUM_CHANNEL_MODES - #endif - #else - eeprom_indexes_e_END + + ///// hardware config / globals menu + #ifdef USE_JUMP_START + uint8_t jump_start_level; #endif -} eeprom_indexes_e; -#define EEPROM_BYTES eeprom_indexes_e_END + +} Config; + +// auto-detect how many eeprom bytes +#define EEPROM_BYTES sizeof(Config) + +// declare this so FSM can see it, +// but define its values in a file which loads later +Config cfg; #ifdef START_AT_MEMORIZED_LEVEL #define USE_EEPROM_WL #define EEPROM_WL_BYTES 1 #endif - -#endif diff --git a/spaghetti-monster/anduril/load-save-config.c b/spaghetti-monster/anduril/load-save-config.c index ad84450..aa772e1 100644 --- a/spaghetti-monster/anduril/load-save-config.c +++ b/spaghetti-monster/anduril/load-save-config.c @@ -1,114 +1,17 @@ -/* - * load-save-config.c: Load/save/eeprom functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ +// load-save-config.c: Load/save/eeprom functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef LOAD_SAVE_CONFIG_C -#define LOAD_SAVE_CONFIG_C +#pragma once #include "load-save-config-fsm.h" #include "load-save-config.h" void load_config() { - if (load_eeprom()) { - ramp_style = eeprom[ramp_style_e]; - #ifdef USE_RAMP_CONFIG - ramp_floors[0] = eeprom[ramp_smooth_floor_e]; - ramp_ceils[0] = eeprom[ramp_smooth_ceil_e]; - #ifdef USE_RAMP_SPEED_CONFIG - ramp_speed = eeprom[ramp_speed_e]; - #endif - ramp_floors[1] = eeprom[ramp_discrete_floor_e]; - ramp_ceils[1] = eeprom[ramp_discrete_ceil_e]; - ramp_stepss[1] = eeprom[ramp_discrete_steps_e]; - #endif - #ifdef USE_SIMPLE_UI - ramp_floors[2] = eeprom[simple_ui_floor_e]; - ramp_ceils[2] = eeprom[simple_ui_ceil_e]; - ramp_stepss[2] = eeprom[simple_ui_steps_e]; - simple_ui_active = eeprom[simple_ui_active_e]; - #ifdef USE_2C_STYLE_CONFIG - ramp_2c_style_simple = eeprom[ramp_2c_style_simple_e]; - #endif - #endif - #ifdef USE_RAMP_AFTER_MOON_CONFIG - dont_ramp_after_moon = eeprom[dont_ramp_after_moon_e]; - #endif - #ifdef USE_2C_STYLE_CONFIG - ramp_2c_style = eeprom[ramp_2c_style_e]; - #endif - #ifdef USE_MANUAL_MEMORY - manual_memory = eeprom[manual_memory_e]; - #ifdef USE_MANUAL_MEMORY_TIMER - manual_memory_timer = eeprom[manual_memory_timer_e]; - #endif - #endif - #ifdef USE_JUMP_START - jump_start_level = eeprom[jump_start_level_e], - #endif - #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) - strobe_type = eeprom[strobe_type_e]; // TODO: move this to eeprom_wl? - strobe_delays[0] = eeprom[strobe_delays_0_e]; - strobe_delays[1] = eeprom[strobe_delays_1_e]; - #endif - #ifdef USE_BIKE_FLASHER_MODE - bike_flasher_brightness = eeprom[bike_flasher_brightness_e]; - #endif - #ifdef USE_BEACON_MODE - beacon_seconds = eeprom[beacon_seconds_e]; - #endif - #ifdef USE_THERMAL_REGULATION - therm_ceil = eeprom[therm_ceil_e]; - therm_cal_offset = eeprom[therm_cal_offset_e]; - #endif - #ifdef USE_VOLTAGE_CORRECTION - voltage_correction = eeprom[voltage_correction_e]; - #endif - #ifdef USE_INDICATOR_LED - indicator_led_mode = eeprom[indicator_led_mode_e]; - #endif - #ifdef USE_AUX_RGB_LEDS - rgb_led_off_mode = eeprom[rgb_led_off_mode_e]; - rgb_led_lockout_mode = eeprom[rgb_led_lockout_mode_e]; - #endif - #ifdef USE_AUTOLOCK - autolock_time = eeprom[autolock_time_e]; - #endif - #ifdef USE_TACTICAL_MODE - tactical_levels[0] = eeprom[tactical_lvl_1_e]; - tactical_levels[1] = eeprom[tactical_lvl_2_e]; - tactical_levels[2] = eeprom[tactical_lvl_3_e]; - #endif - #if NUM_CHANNEL_MODES > 1 - channel_mode = eeprom[channel_mode_e]; - channel_modes_enabled = eeprom[channel_modes_enabled_e]; - #if defined(USE_MANUAL_MEMORY) - manual_memory_channel_mode = eeprom[manual_memory_channel_mode_e]; - #endif - #endif - #ifdef USE_CHANNEL_MODE_ARGS - for (uint8_t i=0; i<NUM_CHANNEL_MODES; i++) - channel_mode_args[i] = eeprom[i + channel_mode_args_e]; - #if defined(USE_MANUAL_MEMORY) - for (uint8_t i=0; i<NUM_CHANNEL_MODES; i++) - manual_memory_channel_args[i] = eeprom[i + manual_memory_channel_args_e]; - #endif - #endif - } + eeprom = (uint8_t *)&cfg; + + if (! load_eeprom()) return; + #ifdef START_AT_MEMORIZED_LEVEL if (load_eeprom_wl()) { memorized_level = eeprom_wl[0]; @@ -117,90 +20,7 @@ void load_config() { } void save_config() { - eeprom[ramp_style_e] = ramp_style; - #ifdef USE_RAMP_CONFIG - eeprom[ramp_smooth_floor_e] = ramp_floors[0]; - eeprom[ramp_smooth_ceil_e] = ramp_ceils[0]; - #ifdef USE_RAMP_SPEED_CONFIG - eeprom[ramp_speed_e] = ramp_speed; - #endif - eeprom[ramp_discrete_floor_e] = ramp_floors[1]; - eeprom[ramp_discrete_ceil_e] = ramp_ceils[1]; - eeprom[ramp_discrete_steps_e] = ramp_stepss[1]; - #endif - #ifdef USE_SIMPLE_UI - eeprom[simple_ui_floor_e] = ramp_floors[2]; - eeprom[simple_ui_ceil_e] = ramp_ceils[2]; - eeprom[simple_ui_steps_e] = ramp_stepss[2]; - eeprom[simple_ui_active_e] = simple_ui_active; - #ifdef USE_2C_STYLE_CONFIG - eeprom[ramp_2c_style_simple_e] = ramp_2c_style_simple; - #endif - #endif - #ifdef USE_RAMP_AFTER_MOON_CONFIG - eeprom[dont_ramp_after_moon_e] = dont_ramp_after_moon; - #endif - #ifdef USE_2C_STYLE_CONFIG - eeprom[ramp_2c_style_e] = ramp_2c_style; - #endif - #ifdef USE_MANUAL_MEMORY - eeprom[manual_memory_e] = manual_memory; - #ifdef USE_MANUAL_MEMORY_TIMER - eeprom[manual_memory_timer_e] = manual_memory_timer; - #endif - #endif - #ifdef USE_JUMP_START - eeprom[jump_start_level_e] = jump_start_level, - #endif - #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) - eeprom[strobe_type_e] = strobe_type; // TODO: move this to eeprom_wl? - eeprom[strobe_delays_0_e] = strobe_delays[0]; - eeprom[strobe_delays_1_e] = strobe_delays[1]; - #endif - #ifdef USE_BIKE_FLASHER_MODE - eeprom[bike_flasher_brightness_e] = bike_flasher_brightness; - #endif - #ifdef USE_BEACON_MODE - eeprom[beacon_seconds_e] = beacon_seconds; - #endif - #ifdef USE_THERMAL_REGULATION - eeprom[therm_ceil_e] = therm_ceil; - eeprom[therm_cal_offset_e] = therm_cal_offset; - #endif - #ifdef USE_VOLTAGE_CORRECTION - eeprom[voltage_correction_e] = voltage_correction; - #endif - #ifdef USE_INDICATOR_LED - eeprom[indicator_led_mode_e] = indicator_led_mode; - #endif - #ifdef USE_AUX_RGB_LEDS - eeprom[rgb_led_off_mode_e] = rgb_led_off_mode; - eeprom[rgb_led_lockout_mode_e] = rgb_led_lockout_mode; - #endif - #ifdef USE_AUTOLOCK - eeprom[autolock_time_e] = autolock_time; - #endif - #ifdef USE_TACTICAL_MODE - eeprom[tactical_lvl_1_e] = tactical_levels[0]; - eeprom[tactical_lvl_2_e] = tactical_levels[1]; - eeprom[tactical_lvl_3_e] = tactical_levels[2]; - #endif - #if NUM_CHANNEL_MODES > 1 - eeprom[channel_mode_e] = channel_mode; - eeprom[channel_modes_enabled_e] = channel_modes_enabled; - #if defined(USE_MANUAL_MEMORY) - eeprom[manual_memory_channel_mode_e] = manual_memory_channel_mode; - #endif - #endif - #ifdef USE_CHANNEL_MODE_ARGS - for (uint8_t i=0; i<NUM_CHANNEL_MODES; i++) - eeprom[i + channel_mode_args_e] = channel_mode_args[i]; - #if defined(USE_MANUAL_MEMORY) - for (uint8_t i=0; i<NUM_CHANNEL_MODES; i++) - eeprom[i + manual_memory_channel_args_e] = manual_memory_channel_args[i]; - #endif - #endif - + eeprom = (uint8_t *)&cfg; save_eeprom(); } @@ -211,6 +31,3 @@ void save_config_wl() { } #endif - -#endif - diff --git a/spaghetti-monster/anduril/load-save-config.h b/spaghetti-monster/anduril/load-save-config.h index 29c1a69..9fe24c7 100644 --- a/spaghetti-monster/anduril/load-save-config.h +++ b/spaghetti-monster/anduril/load-save-config.h @@ -1,24 +1,8 @@ -/* - * load-save-config.h: Load/save/eeprom functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef LOAD_SAVE_CONFIG_H -#define LOAD_SAVE_CONFIG_H +// load-save-config.h: Load/save/eeprom functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once // remember stuff even after battery was changed void load_config(); @@ -27,5 +11,139 @@ void save_config(); void save_config_wl(); #endif +// a struct to hold config values +Config cfg = { + + ///// ramp vars + + // smooth vs discrete ramping + .ramp_style = RAMP_STYLE, // 0 = smooth, 1 = discrete + #ifdef USE_2C_STYLE_CONFIG + // 1 = A1 style, 2 = A2 style + .ramp_2c_style = DEFAULT_2C_STYLE, + #endif + + // settings for each ramp (smooth, stepped, simple UI) + #ifdef USE_RAMP_CONFIG + .ramp_floors = { + RAMP_SMOOTH_FLOOR, + RAMP_DISCRETE_FLOOR, + #ifdef USE_SIMPLE_UI + SIMPLE_UI_FLOOR, + #endif + }, + .ramp_ceils = { + RAMP_SMOOTH_CEIL, + RAMP_DISCRETE_CEIL, + #ifdef USE_SIMPLE_UI + SIMPLE_UI_CEIL, + #endif + }, + .ramp_stepss = { + DEFAULT_RAMP_SPEED, + RAMP_DISCRETE_STEPS, + #ifdef USE_SIMPLE_UI + SIMPLE_UI_STEPS, + #endif + }, + #endif + + #ifdef USE_SIMPLE_UI + // whether to enable the simplified interface or not + .simple_ui_active = SIMPLE_UI_ACTIVE, + #ifdef USE_2C_STYLE_CONFIG + // 0 = no turbo, 1 = A1 style, 2 = A2 style + .ramp_2c_style_simple = DEFAULT_2C_STYLE_SIMPLE, + #endif + #endif + + .dont_ramp_after_moon = DEFAULT_DONT_RAMP_AFTER_MOON, + + #ifdef USE_MANUAL_MEMORY + .manual_memory = DEFAULT_MANUAL_MEMORY, + #ifdef USE_MANUAL_MEMORY_TIMER + .manual_memory_timer = DEFAULT_MANUAL_MEMORY_TIMER, + #endif + #endif + + ///// channel modes / color modes + + #if NUM_CHANNEL_MODES > 1 + // current multi-channel mode + .channel_mode = DEFAULT_CHANNEL_MODE, + // user can take unwanted modes out of the rotation (bitmask) + .channel_modes_enabled = CHANNEL_MODES_ENABLED, + #ifdef USE_MANUAL_MEMORY + // reset w/ manual memory + .manual_memory_channel_mode = DEFAULT_CHANNEL_MODE, + #endif + #endif + #ifdef USE_CHANNEL_MODE_ARGS + // one byte of extra data per channel mode, like for tint value + .channel_mode_args = { CHANNEL_MODE_ARGS }, + #ifdef USE_MANUAL_MEMORY + // remember and reset 1 extra parameter per channel mode (like tint) + .manual_memory_channel_args = { CHANNEL_MODE_ARGS }, + #endif + #endif + + ///// strobe / blinky mode settings + + #ifdef USE_STROBE_STATE + .strobe_type = DEFAULT_STROBE, + #endif + #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) + // party / tactical strobe timing + // party strobe 24 Hz, tactical strobe 10 Hz + .strobe_delays = { 41, 67 }, + #endif + #ifdef USE_BIKE_FLASHER_MODE + .bike_flasher_brightness = MAX_1x7135, + #endif + #ifdef USE_BEACON_MODE + // beacon timing + .beacon_seconds = 2, + #endif + + ///// voltage and temperature + + #ifdef USE_VOLTAGE_CORRECTION + // same 0.05V units as fudge factor, + // but 7 is neutral, and the expected range is from 1 to 13 + .voltage_correction = 7, + #endif + #ifdef USE_THERMAL_REGULATION + .therm_ceil = DEFAULT_THERM_CEIL, + .therm_cal_offset = 0, + #endif + + ///// aux LEDs + + #ifdef USE_INDICATOR_LED + // bits 2-3 control lockout mode + // bits 0-1 control "off" mode + // modes are: 0=off, 1=low, 2=high, 3=blinking (if TICK_DURING_STANDBY enabled) + .indicator_led_mode = INDICATOR_LED_DEFAULT_MODE, + #endif + #ifdef USE_AUX_RGB_LEDS + .rgb_led_off_mode = RGB_LED_OFF_DEFAULT, + .rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT, + #endif + + ///// misc other mode settings + + #ifdef USE_AUTOLOCK + .autolock_time = DEFAULT_AUTOLOCK_TIME, + #endif + #ifdef USE_TACTICAL_MODE + .tactical_levels = { TACTICAL_LEVELS }, + #endif + + ///// hardware config / globals menu + + #ifdef USE_JUMP_START + .jump_start_level = DEFAULT_JUMP_START_LEVEL, + #endif + +}; -#endif diff --git a/spaghetti-monster/anduril/lockout-mode.c b/spaghetti-monster/anduril/lockout-mode.c index 4997f29..3bf7ce0 100644 --- a/spaghetti-monster/anduril/lockout-mode.c +++ b/spaghetti-monster/anduril/lockout-mode.c @@ -33,14 +33,14 @@ uint8_t lockout_state(Event event, uint16_t arg) { if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) { // hold: lowest floor // click, hold: highest floor (or manual mem level) - uint8_t lvl = ramp_floors[0]; + uint8_t lvl = cfg.ramp_floors[0]; if ((event & 0x0f) == 2) { // second click - if (ramp_floors[1] > lvl) lvl = ramp_floors[1]; + if (cfg.ramp_floors[1] > lvl) lvl = cfg.ramp_floors[1]; #ifdef USE_MANUAL_MEMORY - if (manual_memory) lvl = manual_memory; + if (cfg.manual_memory) lvl = cfg.manual_memory; #endif } else { // anything except second click - if (ramp_floors[1] < lvl) lvl = ramp_floors[1]; + if (cfg.ramp_floors[1] < lvl) lvl = cfg.ramp_floors[1]; } set_level(lvl); } @@ -58,11 +58,11 @@ uint8_t lockout_state(Event event, uint16_t arg) { #ifdef USE_INDICATOR_LED // redundant, sleep tick does the same thing //if (event == EV_enter_state) { - // indicator_led_update(indicator_led_mode >> 2, 0); + // indicator_led_update(cfg.indicator_led_mode >> 2, 0); //} else #elif defined(USE_AUX_RGB_LEDS) if (event == EV_enter_state) { - rgb_led_update(rgb_led_lockout_mode, 0); + rgb_led_update(cfg.rgb_led_lockout_mode, 0); } else #endif @@ -71,9 +71,9 @@ uint8_t lockout_state(Event event, uint16_t arg) { go_to_standby = 1; #ifdef USE_INDICATOR_LED // redundant, sleep tick does the same thing - //indicator_led_update(indicator_led_mode >> 2, arg); + //indicator_led_update(cfg.indicator_led_mode >> 2, arg); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(rgb_led_lockout_mode, arg); + rgb_led_update(cfg.rgb_led_lockout_mode, arg); #endif } return MISCHIEF_MANAGED; @@ -82,9 +82,9 @@ uint8_t lockout_state(Event event, uint16_t arg) { #if defined(TICK_DURING_STANDBY) && (defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS)) else if (event == EV_sleep_tick) { #if defined(USE_INDICATOR_LED) - indicator_led_update(indicator_led_mode >> 2, arg); + indicator_led_update(cfg.indicator_led_mode >> 2, arg); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(rgb_led_lockout_mode, arg); + rgb_led_update(cfg.rgb_led_lockout_mode, arg); #endif return MISCHIEF_MANAGED; } @@ -101,8 +101,8 @@ uint8_t lockout_state(Event event, uint16_t arg) { else if (event == EV_4clicks) { #ifdef USE_MANUAL_MEMORY // FIXME: memory timer is totally ignored - if (manual_memory) - set_state(steady_state, manual_memory); + if (cfg.manual_memory) + set_state(steady_state, cfg.manual_memory); else #endif set_state(steady_state, memorized_level); @@ -129,7 +129,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { ////////// Every action below here is blocked in the (non-Extended) Simple UI ////////// #if defined(USE_SIMPLE_UI) && !defined(USE_EXTENDED_SIMPLE_UI) - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif // if simple UI but not extended simple UI @@ -138,7 +138,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { // 7 clicks: rotate through indicator LED modes (lockout mode) else if (event == EV_7clicks) { #if defined(USE_INDICATOR_LED) - uint8_t mode = indicator_led_mode >> 2; + uint8_t mode = cfg.indicator_led_mode >> 2; #ifdef TICK_DURING_STANDBY mode = (mode + 1) & 3; #else @@ -147,9 +147,9 @@ uint8_t lockout_state(Event event, uint16_t arg) { #ifdef INDICATOR_LED_SKIP_LOW if (mode == 1) { mode ++; } #endif - indicator_led_mode = (mode << 2) + (indicator_led_mode & 0x03); + cfg.indicator_led_mode = (mode << 2) + (cfg.indicator_led_mode & 0x03); // redundant, sleep tick does the same thing - //indicator_led_update(indicator_led_mode >> 2, arg); + //indicator_led_update(cfg.indicator_led_mode >> 2, arg); #elif defined(USE_AUX_RGB_LEDS) #endif save_config(); @@ -158,10 +158,10 @@ uint8_t lockout_state(Event event, uint16_t arg) { #elif defined(USE_AUX_RGB_LEDS) // 7 clicks: change RGB aux LED pattern else if (event == EV_7clicks) { - uint8_t mode = (rgb_led_lockout_mode >> 4) + 1; + uint8_t mode = (cfg.rgb_led_lockout_mode >> 4) + 1; mode = mode % RGB_LED_NUM_PATTERNS; - rgb_led_lockout_mode = (mode << 4) | (rgb_led_lockout_mode & 0x0f); - rgb_led_update(rgb_led_lockout_mode, 0); + cfg.rgb_led_lockout_mode = (mode << 4) | (cfg.rgb_led_lockout_mode & 0x0f); + rgb_led_update(cfg.rgb_led_lockout_mode, 0); save_config(); blink_once(); return MISCHIEF_MANAGED; @@ -170,12 +170,12 @@ uint8_t lockout_state(Event event, uint16_t arg) { else if (event == EV_click7_hold) { setting_rgb_mode_now = 1; if (0 == (arg & 0x3f)) { - uint8_t mode = (rgb_led_lockout_mode & 0x0f) + 1; + uint8_t mode = (cfg.rgb_led_lockout_mode & 0x0f) + 1; mode = mode % RGB_LED_NUM_COLORS; - rgb_led_lockout_mode = mode | (rgb_led_lockout_mode & 0xf0); + cfg.rgb_led_lockout_mode = mode | (cfg.rgb_led_lockout_mode & 0xf0); //save_config(); } - rgb_led_update(rgb_led_lockout_mode, arg); + rgb_led_update(cfg.rgb_led_lockout_mode, arg); return MISCHIEF_MANAGED; } // 7H, release: save new color @@ -188,7 +188,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { #if defined(USE_EXTENDED_SIMPLE_UI) && defined(USE_SIMPLE_UI) ////////// Every action below here is blocked in the Extended Simple UI ////////// - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif // if extended simple UI @@ -207,7 +207,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { #ifdef USE_AUTOLOCK // set the auto-lock timer to N minutes, where N is the number of clicks void autolock_config_save(uint8_t step, uint8_t value) { - autolock_time = value; + cfg.autolock_time = value; } uint8_t autolock_config_state(Event event, uint16_t arg) { diff --git a/spaghetti-monster/anduril/lockout-mode.h b/spaghetti-monster/anduril/lockout-mode.h index 1c9c081..37b02ab 100644 --- a/spaghetti-monster/anduril/lockout-mode.h +++ b/spaghetti-monster/anduril/lockout-mode.h @@ -27,7 +27,6 @@ uint8_t lockout_state(Event event, uint16_t arg); #ifndef DEFAULT_AUTOLOCK_TIME #define DEFAULT_AUTOLOCK_TIME 0 // autolock time in minutes, 0 = disabled #endif -uint8_t autolock_time = DEFAULT_AUTOLOCK_TIME; uint8_t autolock_config_state(Event event, uint16_t arg); #endif diff --git a/spaghetti-monster/anduril/off-mode.c b/spaghetti-monster/anduril/off-mode.c index c459979..d9ab5cb 100644 --- a/spaghetti-monster/anduril/off-mode.c +++ b/spaghetti-monster/anduril/off-mode.c @@ -33,9 +33,9 @@ uint8_t off_state(Event event, uint16_t arg) { set_level(0); #ifdef USE_INDICATOR_LED // redundant, sleep tick does the same thing - //indicator_led_update(indicator_led_mode & 0x03, 0); + //indicator_led_update(cfg.indicator_led_mode & 0x03, 0); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(rgb_led_off_mode, 0); + 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 @@ -52,9 +52,9 @@ uint8_t off_state(Event event, uint16_t arg) { go_to_standby = 1; #ifdef USE_INDICATOR_LED // redundant, sleep tick does the same thing - //indicator_led_update(indicator_led_mode & 0x03, arg); + //indicator_led_update(cfg.indicator_led_mode & 0x03, arg); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(rgb_led_off_mode, arg); + rgb_led_update(cfg.rgb_led_off_mode, arg); #endif } return MISCHIEF_MANAGED; @@ -65,21 +65,21 @@ uint8_t off_state(Event event, uint16_t arg) { else if (event == EV_sleep_tick) { #ifdef USE_MANUAL_MEMORY_TIMER // reset to manual memory level when timer expires - if (manual_memory && - (arg >= (manual_memory_timer * SLEEP_TICKS_PER_MINUTE))) { + if (cfg.manual_memory && + (arg >= (cfg.manual_memory_timer * SLEEP_TICKS_PER_MINUTE))) { manual_memory_restore(); } #endif #ifdef USE_INDICATOR_LED - indicator_led_update(indicator_led_mode & 0x03, arg); + indicator_led_update(cfg.indicator_led_mode & 0x03, arg); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(rgb_led_off_mode, arg); + rgb_led_update(cfg.rgb_led_off_mode, arg); #endif #ifdef USE_AUTOLOCK // lock the light after being off for N minutes - uint16_t ticks = autolock_time * SLEEP_TICKS_PER_MINUTE; - if ((autolock_time > 0) && (arg > ticks)) { + uint16_t ticks = cfg.autolock_time * SLEEP_TICKS_PER_MINUTE; + if ((cfg.autolock_time > 0) && (arg > ticks)) { set_state(lockout_state, 0); } #endif // ifdef USE_AUTOLOCK @@ -108,14 +108,14 @@ uint8_t off_state(Event event, uint16_t arg) { set_level(nearest_level(1)); #endif #ifdef USE_RAMP_AFTER_MOON_CONFIG - if (dont_ramp_after_moon) { + if (cfg.dont_ramp_after_moon) { return MISCHIEF_MANAGED; } #endif // don't start ramping immediately; // give the user time to release at moon level //if (arg >= HOLD_TIMEOUT) { // smaller - if (arg >= (!ramp_style) * HOLD_TIMEOUT) { // more consistent + if (arg >= (!cfg.ramp_style) * HOLD_TIMEOUT) { // more consistent set_state(steady_state, 1); } return MISCHIEF_MANAGED; @@ -133,7 +133,7 @@ uint8_t off_state(Event event, uint16_t arg) { #if defined(USE_MANUAL_MEMORY) && !defined(USE_MANUAL_MEMORY_TIMER) // this clause probably isn't used by any configs any more // but is included just in case someone configures it this way - if (manual_memory) { + if (cfg.manual_memory) { manual_memory_restore(); } #endif @@ -160,10 +160,10 @@ uint8_t off_state(Event event, uint16_t arg) { uint8_t turbo_level; // how bright is "turbo"? #if defined(USE_2C_STYLE_CONFIG) // user can choose 2C behavior - uint8_t style_2c = ramp_2c_style; + uint8_t style_2c = cfg.ramp_2c_style; #ifdef USE_SIMPLE_UI // simple UI has its own turbo config - if (simple_ui_active) style_2c = ramp_2c_style_simple; + if (cfg.simple_ui_active) style_2c = cfg.ramp_2c_style_simple; #endif // 0 = ceiling // 1+ = full power @@ -173,7 +173,7 @@ uint8_t off_state(Event event, uint16_t arg) { // simple UI: ceiling // full UI: full power #ifdef USE_SIMPLE_UI - if (simple_ui_active) turbo_level = nearest_level(MAX_LEVEL); + if (cfg.simple_ui_active) turbo_level = nearest_level(MAX_LEVEL); else #endif turbo_level = MAX_LEVEL; @@ -235,9 +235,9 @@ uint8_t off_state(Event event, uint16_t arg) { #ifdef USE_SIMPLE_UI // 10 clicks, but hold last click: turn simple UI off (or configure it) else if ((event == EV_click10_hold) && (!arg)) { - if (simple_ui_active) { // turn off simple UI + if (cfg.simple_ui_active) { // turn off simple UI blink_once(); - simple_ui_active = 0; + cfg.simple_ui_active = 0; save_config(); } else { // configure simple UI ramp @@ -249,7 +249,7 @@ uint8_t off_state(Event event, uint16_t arg) { ////////// Every action below here is blocked in the (non-Extended) Simple UI ////////// #ifndef USE_EXTENDED_SIMPLE_UI - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif // ifndef USE_EXTENDED_SIMPLE_UI @@ -271,7 +271,7 @@ uint8_t off_state(Event event, uint16_t arg) { #ifdef USE_INDICATOR_LED // 7 clicks: change indicator LED mode else if (event == EV_7clicks) { - uint8_t mode = (indicator_led_mode & 3) + 1; + uint8_t mode = (cfg.indicator_led_mode & 3) + 1; #ifdef TICK_DURING_STANDBY mode = mode & 3; #else @@ -280,19 +280,19 @@ uint8_t off_state(Event event, uint16_t arg) { #ifdef INDICATOR_LED_SKIP_LOW if (mode == 1) { mode ++; } #endif - indicator_led_mode = (indicator_led_mode & 0b11111100) | mode; + cfg.indicator_led_mode = (cfg.indicator_led_mode & 0b11111100) | mode; // redundant, sleep tick does the same thing - //indicator_led_update(indicator_led_mode & 0x03, arg); + //indicator_led_update(cfg.indicator_led_mode & 0x03, arg); save_config(); return MISCHIEF_MANAGED; } #elif defined(USE_AUX_RGB_LEDS) // 7 clicks: change RGB aux LED pattern else if (event == EV_7clicks) { - uint8_t mode = (rgb_led_off_mode >> 4) + 1; + uint8_t mode = (cfg.rgb_led_off_mode >> 4) + 1; mode = mode % RGB_LED_NUM_PATTERNS; - rgb_led_off_mode = (mode << 4) | (rgb_led_off_mode & 0x0f); - rgb_led_update(rgb_led_off_mode, 0); + cfg.rgb_led_off_mode = (mode << 4) | (cfg.rgb_led_off_mode & 0x0f); + rgb_led_update(cfg.rgb_led_off_mode, 0); save_config(); blink_once(); return MISCHIEF_MANAGED; @@ -301,12 +301,12 @@ uint8_t off_state(Event event, uint16_t arg) { else if (event == EV_click7_hold) { setting_rgb_mode_now = 1; if (0 == (arg & 0x3f)) { - uint8_t mode = (rgb_led_off_mode & 0x0f) + 1; + uint8_t mode = (cfg.rgb_led_off_mode & 0x0f) + 1; mode = mode % RGB_LED_NUM_COLORS; - rgb_led_off_mode = mode | (rgb_led_off_mode & 0xf0); + cfg.rgb_led_off_mode = mode | (cfg.rgb_led_off_mode & 0xf0); //save_config(); } - rgb_led_update(rgb_led_off_mode, arg); + rgb_led_update(cfg.rgb_led_off_mode, arg); return MISCHIEF_MANAGED; } else if (event == EV_click7_hold_release) { @@ -320,7 +320,7 @@ uint8_t off_state(Event event, uint16_t arg) { #ifdef USE_SIMPLE_UI #ifdef USE_EXTENDED_SIMPLE_UI - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif // ifdef USE_EXTENDED_SIMPLE_UI @@ -328,7 +328,7 @@ uint8_t off_state(Event event, uint16_t arg) { // 10 clicks: enable simple UI else if (event == EV_10clicks) { blink_once(); - simple_ui_active = 1; + cfg.simple_ui_active = 1; save_config(); return MISCHIEF_MANAGED; } diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index a87e9b0..88b141e 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -27,16 +27,16 @@ uint8_t steady_state(Event event, uint16_t arg) { uint8_t mode_min = ramp_floor; uint8_t mode_max = ramp_ceil; uint8_t step_size; - if (ramp_style) { step_size = ramp_discrete_step_size; } + if (cfg.ramp_style) { step_size = ramp_discrete_step_size; } else { step_size = 1; } // how bright is "turbo"? uint8_t turbo_level; #if defined(USE_2C_STYLE_CONFIG) // user can choose 2C behavior - uint8_t style_2c = ramp_2c_style; + uint8_t style_2c = cfg.ramp_2c_style; #ifdef USE_SIMPLE_UI // simple UI has its own turbo config - if (simple_ui_active) style_2c = ramp_2c_style_simple; + if (cfg.simple_ui_active) style_2c = cfg.ramp_2c_style_simple; #endif // 0 = no turbo // 1 = Anduril 1 direct to turbo @@ -51,7 +51,7 @@ uint8_t steady_state(Event event, uint16_t arg) { // simple UI: to/from ceiling // full UI: to/from turbo (Anduril1 behavior) #ifdef USE_SIMPLE_UI - if (simple_ui_active) turbo_level = mode_max; + if (cfg.simple_ui_active) turbo_level = mode_max; else #endif turbo_level = MAX_LEVEL; @@ -61,7 +61,7 @@ uint8_t steady_state(Event event, uint16_t arg) { // or to/from turbo if mem >= ceiling if ((memorized_level < mode_max) #ifdef USE_SIMPLE_UI - || simple_ui_active + || cfg.simple_ui_active #endif ) { turbo_level = mode_max; } else { turbo_level = MAX_LEVEL; } @@ -146,12 +146,12 @@ uint8_t steady_state(Event event, uint16_t arg) { // click, hold: change brightness (dimmer) else if ((event == EV_click1_hold) || (event == EV_click2_hold)) { // ramp slower in discrete mode - if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { + if (cfg.ramp_style && (arg % HOLD_TIMEOUT != 0)) { return MISCHIEF_MANAGED; } #ifdef USE_RAMP_SPEED_CONFIG // ramp slower if user configured things that way - if ((! ramp_style) && (arg % ramp_speed)) { + if ((! cfg.ramp_style) && (arg % ramp_speed)) { return MISCHIEF_MANAGED; } #endif @@ -211,13 +211,13 @@ uint8_t steady_state(Event event, uint16_t arg) { } #endif #if defined(BLINK_AT_STEPS) - uint8_t foo = ramp_style; - ramp_style = 1; + uint8_t foo = cfg.ramp_style; + cfg.ramp_style = 1; uint8_t nearest = nearest_level((int16_t)actual_level); - ramp_style = foo; + cfg.ramp_style = foo; // only blink once for each threshold if ((memorized_level != actual_level) && - (ramp_style == 0) && + (cfg.ramp_style == 0) && (memorized_level == nearest) ) { @@ -360,7 +360,7 @@ uint8_t steady_state(Event event, uint16_t arg) { ////////// Every action below here is blocked in the simple UI ////////// // That is, unless we specifically want to enable 3C for smooth/stepped selection in Simple UI #if defined(USE_SIMPLE_UI) && !defined(USE_SIMPLE_UI_RAMPING_TOGGLE) - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif @@ -386,7 +386,7 @@ uint8_t steady_state(Event event, uint16_t arg) { ) { #endif - ramp_style = !ramp_style; + cfg.ramp_style = !cfg.ramp_style; save_config(); #ifdef START_AT_MEMORIZED_LEVEL save_config_wl(); @@ -402,13 +402,14 @@ uint8_t steady_state(Event event, uint16_t arg) { // If we allowed 3C in Simple UI, now block further actions #if defined(USE_SIMPLE_UI) && defined(USE_SIMPLE_UI_RAMPING_TOGGLE) - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif // 3H: momentary turbo (on lights with no tint ramping) // (or 4H on lights with tint ramping) + // FIXME: handle 3H if channel mode has no args else if (event == EV_MOMENTARY_TURBO) { if (! arg) { // first frame only, to allow thermal regulation to work #ifdef USE_2C_STYLE_CONFIG @@ -457,7 +458,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #else // manual mem, but no timer // turn off manual memory; go back to automatic if (0 == arg) { - manual_memory = 0; + cfg.manual_memory = 0; save_config(); blink_once(); } @@ -474,7 +475,7 @@ uint8_t steady_state(Event event, uint16_t arg) { void ramp_config_save(uint8_t step, uint8_t value) { // 0 = smooth ramp, 1 = stepped ramp, 2 = simple UI's ramp - uint8_t style = ramp_style; + uint8_t style = cfg.ramp_style; #ifdef USE_SIMPLE_UI if (current_state == simple_ui_config_state) style = 2; #endif @@ -483,7 +484,7 @@ void ramp_config_save(uint8_t step, uint8_t value) { // simple UI config is weird... // has some ramp extras after floor/ceil/steps if (4 == step) { - ramp_2c_style_simple = value; + cfg.ramp_2c_style_simple = value; } else #endif @@ -496,7 +497,7 @@ void ramp_config_save(uint8_t step, uint8_t value) { // which option are we configuring? // TODO? maybe rearrange definitions to avoid the need for this table // (move all ramp values into a single array?) - uint8_t *steps[] = { ramp_floors, ramp_ceils, ramp_stepss }; + uint8_t *steps[] = { cfg.ramp_floors, cfg.ramp_ceils, cfg.ramp_stepss }; uint8_t *option; option = steps[step-1]; option[style] = value; @@ -507,7 +508,7 @@ uint8_t ramp_config_state(Event event, uint16_t arg) { #ifdef USE_RAMP_SPEED_CONFIG const uint8_t num_config_steps = 3; #else - uint8_t num_config_steps = ramp_style + 2; + uint8_t num_config_steps = cfg.ramp_style + 2; #endif return config_state_base(event, arg, num_config_steps, ramp_config_save); @@ -530,14 +531,14 @@ 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) { manual_memory = 0; } + if (1 == 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) { manual_memory_timer = value; } + else if (2 == step) { cfg.manual_memory_timer = value; } #endif #ifdef USE_RAMP_AFTER_MOON_CONFIG @@ -545,7 +546,7 @@ void ramp_extras_config_save(uint8_t step, uint8_t value) { // 0 = yes, ramp after moon // 1+ = no, stay at moon else if (3 == step) { - dont_ramp_after_moon = value; + cfg.dont_ramp_after_moon = value; } #endif @@ -554,7 +555,7 @@ void ramp_extras_config_save(uint8_t step, uint8_t value) { // 1 = Anduril 1, 2C turbo // 2+ = Anduril 2, 2C ceiling else if (4 == step) { - ramp_2c_style = value; + cfg.ramp_2c_style = value; } #endif } @@ -575,7 +576,7 @@ void globals_config_save(uint8_t step, uint8_t value) { } #endif #ifdef USE_JUMP_START - else if (step == 1+jump_start_config_step) { jump_start_level = value; } + else if (step == 1+jump_start_config_step) { cfg.jump_start_level = value; } #endif } @@ -597,20 +598,20 @@ uint8_t nearest_level(int16_t target) { // bounds check uint8_t mode_min = ramp_floor; uint8_t mode_max = ramp_ceil; - uint8_t num_steps = ramp_stepss[1 + uint8_t num_steps = cfg.ramp_stepss[1 #ifdef USE_SIMPLE_UI - + simple_ui_active + + cfg.simple_ui_active #endif ]; // special case for 1-step ramp... use halfway point between floor and ceiling - if (ramp_style && (1 == num_steps)) { + if (cfg.ramp_style && (1 == num_steps)) { uint8_t mid = (mode_max + mode_min) >> 1; return mid; } if (target < mode_min) return mode_min; if (target > mode_max) return mode_max; // the rest isn't relevant for smooth ramping - if (! ramp_style) return target; + if (! cfg.ramp_style) return target; uint8_t ramp_range = mode_max - mode_min; ramp_discrete_step_size = ramp_range / (num_steps-1); @@ -628,13 +629,13 @@ uint8_t nearest_level(int16_t target) { // ensure ramp globals are correct void ramp_update_config() { - uint8_t which = ramp_style; + uint8_t which = cfg.ramp_style; #ifdef USE_SIMPLE_UI - if (simple_ui_active) { which = 2; } + if (cfg.simple_ui_active) { which = 2; } #endif - ramp_floor = ramp_floors[which]; - ramp_ceil = ramp_ceils[which]; + ramp_floor = cfg.ramp_floors[which]; + ramp_ceil = cfg.ramp_ceils[which]; } #ifdef USE_THERMAL_REGULATION @@ -647,24 +648,24 @@ void set_level_and_therm_target(uint8_t level) { #endif void manual_memory_restore() { - memorized_level = manual_memory; + memorized_level = cfg.manual_memory; #if NUM_CHANNEL_MODES > 1 - channel_mode = manual_memory_channel_mode; + cfg.channel_mode = cfg.manual_memory_channel_mode; #endif #ifdef USE_CHANNEL_MODE_ARGS for (uint8_t i=0; i<NUM_CHANNEL_MODES; i++) - channel_mode_args[i] = manual_memory_channel_args[i]; + cfg.channel_mode_args[i] = cfg.manual_memory_channel_args[i]; #endif } void manual_memory_save() { - manual_memory = actual_level; + cfg.manual_memory = actual_level; #if NUM_CHANNEL_MODES > 1 - manual_memory_channel_mode = channel_mode; + cfg.manual_memory_channel_mode = cfg.channel_mode; #endif #ifdef USE_CHANNEL_MODE_ARGS for (uint8_t i=0; i<NUM_CHANNEL_MODES; i++) - manual_memory_channel_args[i] = channel_mode_args[i]; + cfg.manual_memory_channel_args[i] = cfg.channel_mode_args[i]; #endif } diff --git a/spaghetti-monster/anduril/ramp-mode.h b/spaghetti-monster/anduril/ramp-mode.h index 6bc3846..c50e36a 100644 --- a/spaghetti-monster/anduril/ramp-mode.h +++ b/spaghetti-monster/anduril/ramp-mode.h @@ -151,76 +151,44 @@ void set_level_and_therm_target(uint8_t level); // brightness control uint8_t memorized_level = DEFAULT_LEVEL; #ifdef USE_MANUAL_MEMORY -#ifndef DEFAULT_MANUAL_MEMORY -#define DEFAULT_MANUAL_MEMORY 0 -#endif -uint8_t manual_memory = DEFAULT_MANUAL_MEMORY; -#ifdef USE_MANUAL_MEMORY_TIMER -#ifndef DEFAULT_MANUAL_MEMORY_TIMER -#define DEFAULT_MANUAL_MEMORY_TIMER 0 -#endif -uint8_t manual_memory_timer = DEFAULT_MANUAL_MEMORY_TIMER; -#endif -#endif -void manual_memory_restore(); -void manual_memory_save(); - -#ifdef USE_SIMPLE_UI - // whether to enable the simplified interface or not - uint8_t simple_ui_active = SIMPLE_UI_ACTIVE; - #ifdef USE_2C_STYLE_CONFIG - #ifndef DEFAULT_2C_STYLE_SIMPLE - #define DEFAULT_2C_STYLE_SIMPLE 0 + void manual_memory_restore(); + void manual_memory_save(); + #ifndef DEFAULT_MANUAL_MEMORY + #define DEFAULT_MANUAL_MEMORY 0 + #endif + #ifdef USE_MANUAL_MEMORY_TIMER + #ifndef DEFAULT_MANUAL_MEMORY_TIMER + #define DEFAULT_MANUAL_MEMORY_TIMER 0 #endif - uint8_t ramp_2c_style_simple = DEFAULT_2C_STYLE_SIMPLE; // 0 = no turbo, 1 = A1 style, 2 = A2 style #endif #endif -// smooth vs discrete ramping -uint8_t ramp_style = RAMP_STYLE; // 0 = smooth, 1 = discrete + +#ifndef DEFAULT_2C_STYLE_SIMPLE + #define DEFAULT_2C_STYLE_SIMPLE 0 +#endif + #ifdef USE_2C_STYLE_CONFIG #ifndef DEFAULT_2C_STYLE #define DEFAULT_2C_STYLE 2 #endif -uint8_t ramp_2c_style = DEFAULT_2C_STYLE; // 1 = A1 style, 2 = A2 style + #ifdef USE_2C_MAX_TURBO #error Cannot use USE_2C_MAX_TURBO and USE_2C_STYLE_CONFIG at the same time. #endif #endif #ifdef USE_RAMP_SPEED_CONFIG -#define ramp_speed (ramp_stepss[0]) +#define ramp_speed (cfg.ramp_stepss[0]) #endif #ifdef USE_RAMP_AFTER_MOON_CONFIG #ifndef DEFAULT_DONT_RAMP_AFTER_MOON #define DEFAULT_DONT_RAMP_AFTER_MOON 0 #endif -uint8_t dont_ramp_after_moon = DEFAULT_DONT_RAMP_AFTER_MOON; #endif // current values, regardless of style uint8_t ramp_floor = RAMP_SMOOTH_FLOOR; uint8_t ramp_ceil = RAMP_SMOOTH_CEIL; -// per style -uint8_t ramp_floors[] = { - RAMP_SMOOTH_FLOOR, - RAMP_DISCRETE_FLOOR, - #ifdef USE_SIMPLE_UI - SIMPLE_UI_FLOOR, - #endif - }; -uint8_t ramp_ceils[] = { - RAMP_SMOOTH_CEIL, - RAMP_DISCRETE_CEIL, - #ifdef USE_SIMPLE_UI - SIMPLE_UI_CEIL, - #endif - }; -uint8_t ramp_stepss[] = { - DEFAULT_RAMP_SPEED, - RAMP_DISCRETE_STEPS, - #ifdef USE_SIMPLE_UI - SIMPLE_UI_STEPS, - #endif - }; + uint8_t ramp_discrete_step_size; // don't set this #ifdef USE_SUNSET_TIMER diff --git a/spaghetti-monster/anduril/strobe-modes.c b/spaghetti-monster/anduril/strobe-modes.c index 5ee2386..0664418 100644 --- a/spaghetti-monster/anduril/strobe-modes.c +++ b/spaghetti-monster/anduril/strobe-modes.c @@ -27,7 +27,7 @@ uint8_t strobe_state(Event event, uint16_t arg) { static int8_t ramp_direction = 1; // 'st' reduces ROM size slightly - strobe_mode_te st = strobe_type; + strobe_mode_te st = cfg.strobe_type; #ifdef USE_MOMENTARY_MODE momentary_mode = 1; // 0 = ramping, 1 = strobes @@ -54,13 +54,13 @@ uint8_t strobe_state(Event event, uint16_t arg) { } // 2 clicks: rotate through strobe/flasher modes else if (event == EV_2clicks) { - strobe_type = (st + 1) % NUM_STROBES; + cfg.strobe_type = (st + 1) % NUM_STROBES; save_config(); return MISCHIEF_MANAGED; } // 4 clicks: rotate backward through strobe/flasher modes else if (event == EV_4clicks) { - strobe_type = (st - 1 + NUM_STROBES) % NUM_STROBES; + cfg.strobe_type = (st - 1 + NUM_STROBES) % NUM_STROBES; save_config(); return MISCHIEF_MANAGED; } @@ -77,11 +77,11 @@ uint8_t strobe_state(Event event, uint16_t arg) { else if (st == party_strobe_e) { #endif if ((arg & 1) == 0) { - uint8_t d = strobe_delays[st]; + uint8_t d = cfg.strobe_delays[st]; d -= ramp_direction; if (d < 8) d = 8; else if (d > 254) d = 254; - strobe_delays[st] = d; + cfg.strobe_delays[st] = d; } } #endif @@ -92,10 +92,10 @@ uint8_t strobe_state(Event event, uint16_t arg) { // biking mode brighter #ifdef USE_BIKE_FLASHER_MODE else if (st == bike_flasher_e) { - bike_flasher_brightness += ramp_direction; - if (bike_flasher_brightness < 2) bike_flasher_brightness = 2; - else if (bike_flasher_brightness > MAX_BIKING_LEVEL) bike_flasher_brightness = MAX_BIKING_LEVEL; - set_level(bike_flasher_brightness); + cfg.bike_flasher_brightness += ramp_direction; + if (cfg.bike_flasher_brightness < 2) cfg.bike_flasher_brightness = 2; + else if (cfg.bike_flasher_brightness > MAX_BIKING_LEVEL) cfg.bike_flasher_brightness = MAX_BIKING_LEVEL; + set_level(cfg.bike_flasher_brightness); } #endif @@ -123,7 +123,7 @@ uint8_t strobe_state(Event event, uint16_t arg) { else if (st == party_strobe_e) { #endif if ((arg & 1) == 0) { - if (strobe_delays[st] < 255) strobe_delays[st] ++; + if (cfg.strobe_delays[st] < 255) cfg.strobe_delays[st] ++; } } #endif @@ -134,9 +134,9 @@ uint8_t strobe_state(Event event, uint16_t arg) { // biking mode dimmer #ifdef USE_BIKE_FLASHER_MODE else if (st == bike_flasher_e) { - if (bike_flasher_brightness > 2) - bike_flasher_brightness --; - set_level(bike_flasher_brightness); + if (cfg.bike_flasher_brightness > 2) + cfg.bike_flasher_brightness --; + set_level(cfg.bike_flasher_brightness); } #endif @@ -170,7 +170,7 @@ uint8_t strobe_state(Event event, uint16_t arg) { // runs repeatedly in FSM loop() whenever UI is in strobe_state or momentary strobe inline void strobe_state_iter() { - uint8_t st = strobe_type; // can't use switch() on an enum + uint8_t st = cfg.strobe_type; // can't use switch() on an enum switch(st) { #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) @@ -208,7 +208,7 @@ inline void strobe_state_iter() { #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) inline void party_tactical_strobe_mode_iter(uint8_t st) { // one iteration of main loop() - uint8_t del = strobe_delays[st]; + uint8_t del = cfg.strobe_delays[st]; // TODO: make tac strobe brightness configurable? set_level(STROBE_BRIGHTNESS); if (0) {} // placeholder @@ -238,7 +238,7 @@ inline void police_color_strobe_iter() { uint8_t del = 66; // TODO: make police strobe brightness configurable uint8_t bright = memorized_level; - uint8_t channel = channel_mode; + uint8_t channel = cfg.channel_mode; for (uint8_t i=0; i<10; i++) { if (0 == i) set_channel_mode(POLICE_COLOR_STROBE_CH1); @@ -304,12 +304,12 @@ inline void lightning_storm_iter() { #ifdef USE_BIKE_FLASHER_MODE inline void bike_flasher_iter() { // one iteration of main loop() - uint8_t burst = bike_flasher_brightness << 1; + uint8_t burst = cfg.bike_flasher_brightness << 1; if (burst > MAX_LEVEL) burst = MAX_LEVEL; for(uint8_t i=0; i<4; i++) { set_level(burst); nice_delay_ms(5); - set_level(bike_flasher_brightness); + set_level(cfg.bike_flasher_brightness); nice_delay_ms(65); } nice_delay_ms(720); // no return check necessary on final delay diff --git a/spaghetti-monster/anduril/strobe-modes.h b/spaghetti-monster/anduril/strobe-modes.h index 685c249..0e7c873 100644 --- a/spaghetti-monster/anduril/strobe-modes.h +++ b/spaghetti-monster/anduril/strobe-modes.h @@ -48,9 +48,9 @@ const int NUM_STROBES = strobe_mode_END; // which strobe mode is active? #ifdef USE_CANDLE_MODE -strobe_mode_te strobe_type = candle_mode_e; + #define DEFAULT_STROBE candle_mode_e #else -strobe_mode_te strobe_type = 0; + #define DEFAULT_STROBE 0 #endif #endif @@ -79,8 +79,6 @@ inline void strobe_state_iter(); #endif #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) -// party / tactical strobe timing -uint8_t strobe_delays[] = { 41, 67 }; // party strobe 24 Hz, tactical strobe 10 Hz inline void party_tactical_strobe_mode_iter(uint8_t st); #endif @@ -95,7 +93,6 @@ inline void lightning_storm_iter(); // bike mode config options #ifdef USE_BIKE_FLASHER_MODE #define MAX_BIKING_LEVEL 120 // should be 127 or less -uint8_t bike_flasher_brightness = MAX_1x7135; inline void bike_flasher_iter(); #endif diff --git a/spaghetti-monster/anduril/sunset-timer.c b/spaghetti-monster/anduril/sunset-timer.c index bad317c..bb59ec9 100644 --- a/spaghetti-monster/anduril/sunset-timer.c +++ b/spaghetti-monster/anduril/sunset-timer.c @@ -10,7 +10,7 @@ uint8_t sunset_timer_state(Event event, uint16_t arg) { #if defined(USE_SIMPLE_UI) && !defined(USE_EXTENDED_SIMPLE_UI) // No timer functions in Simple UI - if (simple_ui_active) return EVENT_NOT_HANDLED; + if (cfg.simple_ui_active) return EVENT_NOT_HANDLED; #endif // reset on start diff --git a/spaghetti-monster/anduril/tactical-mode.c b/spaghetti-monster/anduril/tactical-mode.c index 7e9d66b..2447a11 100644 --- a/spaghetti-monster/anduril/tactical-mode.c +++ b/spaghetti-monster/anduril/tactical-mode.c @@ -22,8 +22,6 @@ #include "tactical-mode.h" -// TODO: save these in eeprom -uint8_t tactical_levels[] = { TACTICAL_LEVELS }; // high, low, strobe uint8_t tactical_state(Event event, uint16_t arg) { // momentary(ish) tactical mode @@ -42,14 +40,14 @@ uint8_t tactical_state(Event event, uint16_t arg) { if (click <= 3) { momentary_active = 1; uint8_t lvl; - lvl = tactical_levels[click-1]; + lvl = cfg.tactical_levels[click-1]; if ((1 <= lvl) && (lvl <= RAMP_SIZE)) { // steady output memorized_level = lvl; momentary_mode = 0; } else { // momentary strobe mode momentary_mode = 1; if (lvl > RAMP_SIZE) { - strobe_type = (lvl - RAMP_SIZE - 1) % strobe_mode_END; + cfg.strobe_type = (lvl - RAMP_SIZE - 1) % strobe_mode_END; } } } @@ -92,7 +90,7 @@ uint8_t tactical_state(Event event, uint16_t arg) { // (unnecessary since this entire mode is blocked in simple UI) /* #ifdef USE_SIMPLE_UI - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif @@ -113,7 +111,7 @@ void tactical_config_save(uint8_t step, uint8_t value) { // each value is 1 to 150, or other: // - 1..150 is a ramp level // - other means "strobe mode" - tactical_levels[step - 1] = value; + cfg.tactical_levels[step - 1] = value; } uint8_t tactical_config_state(Event event, uint16_t arg) { diff --git a/spaghetti-monster/anduril/tactical-mode.h b/spaghetti-monster/anduril/tactical-mode.h index 4403314..14bf7ff 100644 --- a/spaghetti-monster/anduril/tactical-mode.h +++ b/spaghetti-monster/anduril/tactical-mode.h @@ -20,14 +20,13 @@ #ifndef TACTICAL_MODE_H #define TACTICAL_MODE_H -// tactical(ish) mode -uint8_t tactical_state(Event event, uint16_t arg); - #ifndef TACTICAL_LEVELS // high, low, tactical strobe #define TACTICAL_LEVELS 120,30,(RAMP_SIZE+2) #endif -uint8_t tactical_levels[]; + +// tactical(ish) mode +uint8_t tactical_state(Event event, uint16_t arg); uint8_t tactical_config_state(Event event, uint16_t arg); diff --git a/spaghetti-monster/anduril/tempcheck-mode.c b/spaghetti-monster/anduril/tempcheck-mode.c index f6e1ebe..2e3b56f 100644 --- a/spaghetti-monster/anduril/tempcheck-mode.c +++ b/spaghetti-monster/anduril/tempcheck-mode.c @@ -51,18 +51,18 @@ void thermal_config_save(uint8_t step, uint8_t value) { if (value) { // item 1: calibrate room temperature if (step == 1) { - int8_t rawtemp = temperature - therm_cal_offset; - therm_cal_offset = value - rawtemp; + int8_t rawtemp = temperature - cfg.therm_cal_offset; + cfg.therm_cal_offset = value - rawtemp; adc_reset = 2; // invalidate all recent temperature data } // item 2: set maximum heat limit else { - therm_ceil = 30 + value - 1; + cfg.therm_ceil = 30 + value - 1; } } - if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL; + if (cfg.therm_ceil > MAX_THERM_CEIL) cfg.therm_ceil = MAX_THERM_CEIL; } uint8_t thermal_config_state(Event event, uint16_t arg) { diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 60eb843..9dc8866 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -149,7 +149,7 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { uint8_t result = ((value / adc_per_volt) + VOLTAGE_FUDGE_FACTOR #ifdef USE_VOLTAGE_CORRECTION - + voltage_correction - 7 + + VOLT_CORR - 7 #endif ) >> 1; return result; @@ -349,7 +349,7 @@ static inline void ADC_voltage_handler() { voltage = ((uint16_t)(2*1.1*1024*10)/(measurement>>6) + VOLTAGE_FUDGE_FACTOR #ifdef USE_VOLTAGE_CORRECTION - + voltage_correction - 7 + + VOLT_CORR - 7 #endif ) >> 1; #endif @@ -428,10 +428,10 @@ static inline void ADC_temperature_handler() { // Convert ADC units to Celsius (ish) #ifndef USE_EXTERNAL_TEMP_SENSOR // onboard sensor for attiny25/45/85/1634 - temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)therm_cal_offset - 275; + temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; #else // external sensor - temperature = EXTERN_TEMP_FORMULA(measurement>>1) + THERM_CAL_OFFSET + (int16_t)therm_cal_offset; + temperature = EXTERN_TEMP_FORMULA(measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL; #endif // how much has the temperature changed between now and a few seconds ago? @@ -447,10 +447,10 @@ static inline void ADC_temperature_handler() { pt = measurement + (diff * THERM_LOOKAHEAD); // convert temperature limit from C to raw 16-bit ADC units - // C = (ADC>>6) - 275 + THERM_CAL_OFFSET + therm_cal_offset; + // C = (ADC>>6) - 275 + THERM_CAL_OFFSET + TH_CAL; // ... so ... - // (C + 275 - THERM_CAL_OFFSET - therm_cal_offset) << 6 = ADC; - uint16_t ceil = (therm_ceil + 275 - therm_cal_offset - THERM_CAL_OFFSET) << 1; + // (C + 275 - THERM_CAL_OFFSET - TH_CAL) << 6 = ADC; + uint16_t ceil = (TH_CEIL + 275 - TH_CAL - THERM_CAL_OFFSET) << 1; int16_t offset = pt - ceil; // bias small errors toward zero, while leaving large errors mostly unaffected diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index db2bb7b..77f625a 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -63,9 +63,14 @@ void adc_deferred(); // do the actual ADC-related calculations static inline void ADC_voltage_handler(); uint8_t voltage = 0; #ifdef USE_VOLTAGE_CORRECTION -// same 0.05V units as fudge factor, -// but 7 is neutral, and the expected range is from 1 to 13 -uint8_t voltage_correction = 7; + #ifdef USE_CFG + #define VOLT_CORR cfg.voltage_correction + #else + // same 0.05V units as fudge factor, + // but 7 is neutral, and the expected range is from 1 to 13 + uint8_t voltage_correction = 7; + #define VOLT_CORR voltage_correction + #endif #endif #ifdef USE_LVP void low_voltage(); @@ -98,8 +103,15 @@ void battcheck(); #endif // temperature now, in C (ish) int16_t temperature; -uint8_t therm_ceil = DEFAULT_THERM_CEIL; -int8_t therm_cal_offset = 0; +#ifdef USE_CFG + #define TH_CEIL cfg.therm_ceil + #define TH_CAL cfg.therm_cal_offset +#else + #define TH_CEIL therm_ceil + #define TH_CAL therm_cal_offset + uint8_t therm_ceil = DEFAULT_THERM_CEIL; + int8_t therm_cal_offset = 0; +#endif static inline void ADC_temperature_handler(); #endif // ifdef USE_THERMAL_REGULATION diff --git a/spaghetti-monster/fsm-eeprom.h b/spaghetti-monster/fsm-eeprom.h index 3621106..cda290b 100644 --- a/spaghetti-monster/fsm-eeprom.h +++ b/spaghetti-monster/fsm-eeprom.h @@ -33,9 +33,10 @@ #endif #ifdef USE_EEPROM -#if EEPROM_BYTES >= (EEPSIZE/2) -#error Requested EEPROM_BYTES too big. -#endif +// this fails when EEPROM_BYTES is a sizeof() +//#if EEPROM_BYTES >= (EEPSIZE/2) +//#error Requested EEPROM_BYTES too big. +//#endif #ifdef EEPROM_OVERRIDE uint8_t *eeprom; #else diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c index a55c74b..14b0db8 100644 --- a/spaghetti-monster/fsm-ramping.c +++ b/spaghetti-monster/fsm-ramping.c @@ -16,7 +16,7 @@ void set_channel_mode(uint8_t mode) { set_level(0); // change the channel - channel_mode = mode; + CH_MODE = mode; // update the LEDs set_level(cur_level); @@ -61,8 +61,8 @@ void set_level(uint8_t level) { // TODO: allow different jump start behavior per channel mode if ((! actual_level) && level - && (level < jump_start_level)) { - set_level(jump_start_level); + && (level < JUMP_START_LEVEL)) { + set_level(JUMP_START_LEVEL); delay_4ms(JUMP_START_TIME/4); } #endif @@ -72,7 +72,7 @@ void set_level(uint8_t level) { #endif // call the relevant hardware-specific set_level_*() - SetLevelFuncPtr set_level_func = channel_modes[channel_mode]; + SetLevelFuncPtr set_level_func = channel_modes[CH_MODE]; set_level_func(level); actual_level = level; @@ -138,54 +138,52 @@ void set_level_3ch_stacked(uint8_t level) { // TODO: 2ch stacked w/ dynamic PWM // TODO: 2ch stacked w/ dynamic PWM and opamp enable pins? -#ifdef USE_SET_LEVEL_2CH_BLEND -// warm + cool blend w/ middle sag correction -void set_level_2ch_blend(uint8_t level) { +#ifdef USE_CALC_2CH_BLEND +// calculate a "tint ramp" blend between 2 channels +// results are placed in *warm and *cool vars +// brightness : total amount of light units to distribute +// top : maximum allowed brightness per channel +// blend : ratio between warm and cool (0 = warm, 128 = 50%, 255 = cool) +void calc_2ch_blend( + PWM_DATATYPE *warm, + PWM_DATATYPE *cool, + PWM_DATATYPE brightness, + PWM_DATATYPE top, + uint8_t blend) { + #ifndef TINT_RAMPING_CORRECTION #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint #endif - BLEND_PWM_DATATYPE vpwm; - - if (level == 0) { - vpwm = 0; - } else { - level --; // PWM array index = level - 1 - vpwm = PWM_GET(blend_pwm_levels, level); - } - // calculate actual PWM levels based on a single-channel ramp - // and a global tint value - uint16_t brightness = vpwm; - uint16_t warm_PWM, cool_PWM; - const uint16_t top = PWM_TOP; - - // auto-tint modes - uint8_t mytint = channel_mode_args[channel_mode]; - + // and a blend value + PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE2 base_PWM = brightness; + #if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0) + uint8_t level = actual_level - 1; + // middle tints sag, so correct for that effect // by adding extra power which peaks at the middle tint // (correction is only necessary when PWM is fast) if (level > HALFSPEED_LEVEL) { base_PWM = brightness + ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64) - * triangle_wave(mytint) / 255); + * triangle_wave(blend) / 255); } // fade the triangle wave out when above 100% power, // so it won't go over 200% if (brightness > top) { base_PWM -= 2 * ( ((brightness - top) * TINT_RAMPING_CORRECTION / 64) - * triangle_wave(mytint) / 255 + * triangle_wave(blend) / 255 ); } // guarantee no more than 200% power if (base_PWM > (top << 1)) { base_PWM = top << 1; } #endif - cool_PWM = (((PWM_DATATYPE2)mytint * (PWM_DATATYPE2)base_PWM) + 127) / 255; + cool_PWM = (((PWM_DATATYPE2)blend * (PWM_DATATYPE2)base_PWM) + 127) / 255; warm_PWM = base_PWM - cool_PWM; // when running at > 100% power, spill extra over to other channel if (cool_PWM > top) { @@ -196,10 +194,76 @@ void set_level_2ch_blend(uint8_t level) { warm_PWM = top; } - WARM_PWM_LVL = warm_PWM; - COOL_PWM_LVL = cool_PWM; + *warm = warm_PWM; + *cool = cool_PWM; } -#endif // ifdef USE_TINT_RAMPING +#endif // ifdef USE_CALC_2CH_BLEND + +#ifdef USE_HSV2RGB +RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v) { + RGB_t color; + + uint16_t region, fpart, high, low, rising, falling; + + if (s == 0) { // grey + color.r = color.g = color.b = v; + return color; + } + + // make hue 0-5 + region = ((uint16_t)h * 6) >> 8; + // find remainder part, make it from 0-255 + fpart = ((uint16_t)h * 6) - (region << 8); + + // calculate graph segments, doing integer multiplication + high = v; + low = (v * (255 - s)) >> 8; + falling = (v * (255 - ((s * fpart) >> 8))) >> 8; + rising = (v * (255 - ((s * (255 - fpart)) >> 8))) >> 8; + + // default floor + color.r = low; + color.g = low; + color.b = low; + + // assign graph shapes based on color cone region + switch (region) { + case 0: + color.r = high; + color.g = rising; + //color.b = low; + break; + case 1: + color.r = falling; + color.g = high; + //color.b = low; + break; + case 2: + //color.r = low; + color.g = high; + color.b = rising; + break; + case 3: + //color.r = low; + color.g = falling; + color.b = high; + break; + case 4: + color.r = rising; + //color.g = low; + color.b = high; + break; + default: + color.r = high; + //color.g = low; + color.b = falling; + break; + } + + return color; +} +#endif // ifdef USE_HSV2RGB + #ifdef USE_LEGACY_SET_LEVEL // (this is mostly just here for reference, temporarily) @@ -339,7 +403,7 @@ inline void set_level_gradually(uint8_t lvl) { // call this every frame or every few frames to change brightness very smoothly void gradual_tick() { // call the relevant hardware-specific function - GradualTickFuncPtr gradual_tick_func = gradual_tick_modes[channel_mode]; + GradualTickFuncPtr gradual_tick_func = gradual_tick_modes[CH_MODE]; gradual_tick_func(); } diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 8a12cc8..5ffd8d9 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -28,11 +28,12 @@ uint8_t actual_level = 0; // TODO: size-optimize the case with only 1 channel mode // (the arrays and stuff shouldn't be needed) -// current multi-channel mode -uint8_t channel_mode = DEFAULT_CHANNEL_MODE; -#ifdef USE_MANUAL_MEMORY -// reset w/ manual memory -uint8_t manual_memory_channel_mode = DEFAULT_CHANNEL_MODE; +#ifdef USE_CFG + #define CH_MODE cfg.channel_mode +#else + // current multi-channel mode + uint8_t channel_mode = DEFAULT_CHANNEL_MODE; + #define CH_MODE channel_mode #endif #if NUM_CHANNEL_MODES > 1 @@ -62,36 +63,49 @@ StatePtr channel_3H_modes[NUM_CHANNEL_MODES]; //#ifdef USE_CHANNEL_MODE_TOGGLES #if NUM_CHANNEL_MODES > 1 // user can take unwanted modes out of the rotation -// TODO: save to eeprom -// array -//uint8_t channel_modes_enabled[NUM_CHANNEL_MODES] = { CHANNEL_MODES_ENABLED }; // bitmask -uint8_t channel_modes_enabled = CHANNEL_MODES_ENABLED; -#define channel_mode_enabled(n) ((channel_modes_enabled >> n) & 1) -#define channel_mode_enable(n) channel_modes_enabled |= (1 << n) -#define channel_mode_disable(n) channel_modes_enabled &= ((1 << n) ^ 0xff) +#ifdef USE_CFG + #define channel_mode_enabled(n) ((cfg.channel_modes_enabled >> n) & 1) + #define channel_mode_enable(n) cfg.channel_modes_enabled |= (1 << n) + #define channel_mode_disable(n) cfg.channel_modes_enabled &= ((1 << n) ^ 0xff) +#else + uint8_t channel_modes_enabled = CHANNEL_MODES_ENABLED; + #define channel_mode_enabled(n) ((channel_modes_enabled >> n) & 1) + #define channel_mode_enable(n) channel_modes_enabled |= (1 << n) + #define channel_mode_disable(n) channel_modes_enabled &= ((1 << n) ^ 0xff) + #endif #endif -#ifdef USE_CHANNEL_MODE_ARGS -// one byte of extra data per channel mode, like for tint value -uint8_t channel_mode_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; +#ifndef USE_CFG + #ifdef USE_CHANNEL_MODE_ARGS + // one byte of extra data per channel mode, like for tint value + uint8_t channel_mode_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; + #endif #endif -// TODO: remove this after implementing channel modes -//#ifdef USE_TINT_RAMPING -//#ifdef TINT_RAMP_TOGGLE_ONLY -//uint8_t tint = 0; -//#else -//uint8_t tint = 128; -//#endif -//#define USE_TRIANGLE_WAVE -//#endif - void set_channel_mode(uint8_t mode); void set_level(uint8_t level); //void set_level_smooth(uint8_t level); +#ifdef USE_CALC_2CH_BLEND +void calc_2ch_blend( + PWM_DATATYPE *warm, + PWM_DATATYPE *cool, + PWM_DATATYPE brightness, + PWM_DATATYPE top, + uint8_t blend); +#endif + +#ifdef USE_HSV2RGB +typedef struct RGB_t { + uint8_t r; + uint8_t g; + uint8_t b; +} RGB_t; +RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v); +#endif // ifdef USE_HSV2RGB + #ifdef USE_SET_LEVEL_GRADUALLY // adjust brightness very smoothly uint8_t gradual_target; @@ -213,13 +227,18 @@ PROGMEM const PWM_DATATYPE pwm_tops[] = { PWM_TOPS }; // FIXME: jump start should be per channel / channel mode #ifdef USE_JUMP_START -#ifndef JUMP_START_TIME -#define JUMP_START_TIME 8 // in ms, should be 4, 8, or 12 -#endif -#ifndef DEFAULT_JUMP_START_LEVEL -#define DEFAULT_JUMP_START_LEVEL 10 -#endif -uint8_t jump_start_level = DEFAULT_JUMP_START_LEVEL; + #ifndef JUMP_START_TIME + #define JUMP_START_TIME 8 // in ms, should be 4, 8, or 12 + #endif + #ifndef DEFAULT_JUMP_START_LEVEL + #define DEFAULT_JUMP_START_LEVEL 10 + #endif + #ifdef USE_CFG + #define JUMP_START_LEVEL cfg.jump_start_level + #else + #define JUMP_START_LEVEL jump_start_level + uint8_t jump_start_level = DEFAULT_JUMP_START_LEVEL; + #endif #endif // RAMP_SIZE / MAX_LVL |
