From afdd12955841217ee8b95f8378204deb2fcdad34 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 12 Mar 2019 00:26:53 -0600 Subject: created directory for Fireflies UI --- spaghetti-monster/fireflies-ui/Makefile | 7 + spaghetti-monster/fireflies-ui/build-all.sh | 13 + spaghetti-monster/fireflies-ui/fireflies-ui.c | 1956 +++++++++++++++++++++++++ 3 files changed, 1976 insertions(+) create mode 100644 spaghetti-monster/fireflies-ui/Makefile create mode 100755 spaghetti-monster/fireflies-ui/build-all.sh create mode 100644 spaghetti-monster/fireflies-ui/fireflies-ui.c diff --git a/spaghetti-monster/fireflies-ui/Makefile b/spaghetti-monster/fireflies-ui/Makefile new file mode 100644 index 0000000..8db198e --- /dev/null +++ b/spaghetti-monster/fireflies-ui/Makefile @@ -0,0 +1,7 @@ +all: + ./build-all.sh + +clean: + rm -f *.hex cfg-*.h *~ *.elf *.o + +.phony: clean diff --git a/spaghetti-monster/fireflies-ui/build-all.sh b/spaghetti-monster/fireflies-ui/build-all.sh new file mode 100755 index 0000000..41d92d0 --- /dev/null +++ b/spaghetti-monster/fireflies-ui/build-all.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +cp -av ../anduril/cfg-ff*.h . + +UI=fireflies-ui + +for TARGET in cfg-*.h ; do + NAME=$(echo "$TARGET" | perl -ne '/cfg-(.*).h/ && print "$1\n";') + echo "===== $NAME =====" + echo ../../../bin/build.sh 85 "$UI" "-DCONFIGFILE=${TARGET}" + ../../../bin/build.sh 85 "$UI" "-DCONFIGFILE=${TARGET}" + mv -f "$UI".hex "$UI".$NAME.hex +done diff --git a/spaghetti-monster/fireflies-ui/fireflies-ui.c b/spaghetti-monster/fireflies-ui/fireflies-ui.c new file mode 100644 index 0000000..09c7927 --- /dev/null +++ b/spaghetti-monster/fireflies-ui/fireflies-ui.c @@ -0,0 +1,1956 @@ +/* + * Anduril: Narsil-inspired UI for SpaghettiMonster. + * (Anduril is Aragorn's sword, the blade Narsil reforged) + * + * 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 . + */ + +/********* User-configurable options *********/ +// Anduril config file name (set it here or define it at the gcc command line) +//#define CONFIGFILE cfg-blf-q8.h + +#define USE_LVP // FIXME: won't build when this option is turned off + +// parameters for this defined below or per-driver +#define USE_THERMAL_REGULATION +#define DEFAULT_THERM_CEIL 45 // try not to get hotter than this + +// short blip when crossing from "click" to "hold" from off +// (helps the user hit moon mode exactly, instead of holding too long +// or too short) +#define MOON_TIMING_HINT +// short blips while ramping +#define BLINK_AT_CHANNEL_BOUNDARIES +//#define BLINK_AT_RAMP_FLOOR +#define BLINK_AT_RAMP_CEILING +//#define BLINK_AT_STEPS // whenever a discrete ramp mode is passed in smooth mode + +// ramp down via regular button hold if a ramp-up ended <1s ago +// ("hold, release, hold" ramps down instead of up) +#define USE_REVERSING + +// battery readout style (pick one) +#define BATTCHECK_VpT +//#define BATTCHECK_8bars // FIXME: breaks build +//#define BATTCHECK_4bars // FIXME: breaks build + +// enable/disable various strobe modes +#define USE_BIKE_FLASHER_MODE +#define USE_PARTY_STROBE_MODE +#define USE_TACTICAL_STROBE_MODE +#define USE_LIGHTNING_MODE +#define USE_CANDLE_MODE + +//Muggle mode for easy UI +#define USE_MUGGLE_MODE + +#define GOODNIGHT_TIME 60 // minutes (approximately) +#define GOODNIGHT_LEVEL 24 // ~11 lm + +// dual-switch support (second switch is a tail clicky) +//#define START_AT_MEMORIZED_LEVEL + +/***** specific settings for known driver types *****/ +#include "tk.h" +#include incfile(CONFIGFILE) + + +// thermal properties, if not defined per-driver +#ifndef MIN_THERM_STEPDOWN +#define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to +#endif +#ifndef THERM_FASTER_LEVEL + #ifdef MAX_Nx7135 + #define THERM_FASTER_LEVEL MAX_Nx7135 // throttle back faster when high + #else + #define THERM_FASTER_LEVEL (RAMP_SIZE*4/5) // throttle back faster when high + #endif +#endif +#ifdef USE_THERMAL_REGULATION +#define USE_SET_LEVEL_GRADUALLY // isn't used except for thermal adjustments +#endif + + +/********* Configure SpaghettiMonster *********/ +#define USE_DELAY_ZERO +#define USE_RAMPING +#ifndef RAMP_LENGTH +#define RAMP_LENGTH 150 // default, if not overridden in a driver cfg file +#endif +#define MAX_BIKING_LEVEL 120 // should be 127 or less +#define USE_BATTCHECK + +#if defined(USE_MUGGLE_MODE) +#ifndef MUGGLE_FLOOR +#define MUGGLE_FLOOR 22 +#endif +#ifndef MUGGLE_CEILING +#define MUGGLE_CEILING (MAX_1x7135+20) +#endif +#endif +#define USE_IDLE_MODE // reduce power use while awake and no tasks are pending +#define USE_DYNAMIC_UNDERCLOCKING // cut clock speed at very low modes for better efficiency + +// full FET strobe can be a bit much... use max regulated level instead, +// if there's a bright enough regulated level +#ifdef MAX_Nx7135 +#define STROBE_BRIGHTNESS MAX_Nx7135 +#else +#define STROBE_BRIGHTNESS MAX_LEVEL +#endif + +#if defined(USE_CANDLE_MODE) || defined(USE_BIKE_FLASHER_MODE) || defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) || defined(USE_LIGHTNING_MODE) +#define USE_STROBE_STATE +#endif + +// auto-detect how many eeprom bytes +#define USE_EEPROM +typedef enum { + ramp_style_e, + ramp_smooth_floor_e, + ramp_smooth_ceil_e, + ramp_discrete_floor_e, + ramp_discrete_ceil_e, + ramp_discrete_steps_e, + #ifdef USE_STROBE_STATE + strobe_type_e, + #endif + #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) + strobe_delays_0_e, + strobe_delays_1_e, + #endif + #ifdef USE_BIKE_FLASHER_MODE + bike_flasher_brightness_e, + #endif + beacon_seconds_e, + #ifdef USE_MUGGLE_MODE + muggle_mode_active_e, + #endif + #ifdef USE_THERMAL_REGULATION + therm_ceil_e, + therm_cal_offset_e, + #endif + #ifdef USE_INDICATOR_LED + indicator_led_mode_e, + #endif + eeprom_indexes_e_END +} eeprom_indexes_e; +#define EEPROM_BYTES eeprom_indexes_e_END + +#ifdef START_AT_MEMORIZED_LEVEL +#define USE_EEPROM_WL +#define EEPROM_WL_BYTES 1 +#endif + +// auto-configure other stuff... +#if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) +#define USE_PSEUDO_RAND +#endif + +#include "spaghetti-monster.h" + + +// FSM states +uint8_t off_state(Event event, uint16_t arg); +// simple numeric entry config menu +uint8_t config_state_base(Event event, uint16_t arg, + uint8_t num_config_steps, + void (*savefunc)()); +#define MAX_CONFIG_VALUES 3 +uint8_t config_state_values[MAX_CONFIG_VALUES]; +// ramping mode and its related config mode +uint8_t steady_state(Event event, uint16_t arg); +uint8_t ramp_config_state(Event event, uint16_t arg); +// party and tactical strobes +#ifdef USE_STROBE_STATE +uint8_t strobe_state(Event event, uint16_t arg); +#endif +#ifdef USE_BATTCHECK +uint8_t battcheck_state(Event event, uint16_t arg); +#endif +#ifdef USE_THERMAL_REGULATION +uint8_t tempcheck_state(Event event, uint16_t arg); +uint8_t thermal_config_state(Event event, uint16_t arg); +#endif +// 1-hour ramp down from low, then automatic off +uint8_t goodnight_state(Event event, uint16_t arg); +// beacon mode and its related config mode +uint8_t beacon_state(Event event, uint16_t arg); +uint8_t beacon_config_state(Event event, uint16_t arg); +// soft lockout +#define MOON_DURING_LOCKOUT_MODE +// if enabled, 2nd lockout click goes to the other ramp's floor level +//#define LOCKOUT_MOON_FANCY +uint8_t lockout_state(Event event, uint16_t arg); +// momentary / signalling mode +uint8_t momentary_state(Event event, uint16_t arg); +#ifdef USE_MUGGLE_MODE +// muggle mode, super-simple, hard to exit +uint8_t muggle_state(Event event, uint16_t arg); +uint8_t muggle_mode_active = 0; +#endif + +// general helper function for config modes +uint8_t number_entry_state(Event event, uint16_t arg); +// return value from number_entry_state() +volatile uint8_t number_entry_value; + +void blink_confirm(uint8_t num); +#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) +void indicator_blink(uint8_t arg); +#endif + +// remember stuff even after battery was changed +void load_config(); +void save_config(); +#ifdef START_AT_MEMORIZED_LEVEL +void save_config_wl(); +#endif + +// default ramp options if not overridden earlier per-driver +#ifndef RAMP_SMOOTH_FLOOR + #define RAMP_SMOOTH_FLOOR 1 +#endif +#ifndef RAMP_SMOOTH_CEIL + #if PWM_CHANNELS == 3 + #define RAMP_SMOOTH_CEIL MAX_Nx7135 + #else + #define RAMP_SMOOTH_CEIL MAX_LEVEL - 30 + #endif +#endif +#ifndef RAMP_DISCRETE_FLOOR + #define RAMP_DISCRETE_FLOOR 20 +#endif +#ifndef RAMP_DISCRETE_CEIL + #define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#endif +#ifndef RAMP_DISCRETE_STEPS + #define RAMP_DISCRETE_STEPS 7 +#endif + +// brightness control +uint8_t memorized_level = MAX_1x7135; +// smooth vs discrete ramping +volatile uint8_t ramp_style = 0; // 0 = smooth, 1 = discrete +volatile uint8_t ramp_smooth_floor = RAMP_SMOOTH_FLOOR; +volatile uint8_t ramp_smooth_ceil = RAMP_SMOOTH_CEIL; +volatile uint8_t ramp_discrete_floor = RAMP_DISCRETE_FLOOR; +volatile uint8_t ramp_discrete_ceil = RAMP_DISCRETE_CEIL; +volatile uint8_t ramp_discrete_steps = RAMP_DISCRETE_STEPS; +uint8_t ramp_discrete_step_size; // don't set this + +#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) + #ifdef INDICATOR_LED_DEFAULT_MODE + uint8_t indicator_led_mode = INDICATOR_LED_DEFAULT_MODE; + #else + #ifdef USE_INDICATOR_LED_WHILE_RAMPING + //uint8_t indicator_led_mode = (1<<2) + 2; + uint8_t indicator_led_mode = (2<<2) + 1; + #else + uint8_t indicator_led_mode = (3<<2) + 1; + #endif + #endif +#endif + +// calculate the nearest ramp level which would be valid at the moment +// (is a no-op for smooth ramp, but limits discrete ramp to only the +// correct levels for the user's config) +uint8_t nearest_level(int16_t target); + +#ifdef USE_THERMAL_REGULATION +// brightness before thermal step-down +uint8_t target_level = 0; +#endif + +// internal numbering for strobe modes +#ifdef USE_STROBE_STATE +typedef enum { + #ifdef USE_PARTY_STROBE_MODE + party_strobe_e, + #endif + #ifdef USE_TACTICAL_STROBE_MODE + tactical_strobe_e, + #endif + #ifdef USE_LIGHTNING_MODE + lightning_storm_e, + #endif + #ifdef USE_CANDLE_MODE + candle_mode_e, + #endif + #ifdef USE_BIKE_FLASHER_MODE + bike_flasher_e, + #endif + strobe_mode_END +} strobe_mode_te; + +const int NUM_STROBES = strobe_mode_END; + +// which strobe mode is active? +#ifdef USE_CANDLE_MODE +volatile strobe_mode_te strobe_type = candle_mode_e; +#else +volatile strobe_mode_te strobe_type = 0; +#endif +#endif + +#if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) +// party / tactical strobe timing +volatile uint8_t strobe_delays[] = { 40, 67 }; // party strobe, tactical strobe +#endif + +// bike mode config options +#ifdef USE_BIKE_FLASHER_MODE +volatile uint8_t bike_flasher_brightness = MAX_1x7135; +#endif + +#ifdef USE_CANDLE_MODE +uint8_t triangle_wave(uint8_t phase); +#endif + +// beacon timing +volatile uint8_t beacon_seconds = 2; + + +uint8_t off_state(Event event, uint16_t arg) { + // turn emitter off when entering state + if (event == EV_enter_state) { + set_level(0); + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode & 0x03); + #endif + // sleep while off (lower power use) + go_to_standby = 1; + return MISCHIEF_MANAGED; + } + // go back to sleep eventually if we got bumped but didn't leave "off" state + else if (event == EV_tick) { + if (arg > TICKS_PER_SECOND*2) { + go_to_standby = 1; + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode & 0x03); + #endif + } + return MISCHIEF_MANAGED; + } + #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) + // blink the indicator LED, maybe + else if (event == EV_sleep_tick) { + if ((indicator_led_mode & 0b00000011) == 0b00000011) { + indicator_blink(arg); + } + return MISCHIEF_MANAGED; + } + #endif + // hold (initially): go to lowest level (floor), but allow abort for regular click + else if (event == EV_click1_press) { + set_level(nearest_level(1)); + return MISCHIEF_MANAGED; + } + // hold: go to lowest level + else if (event == EV_click1_hold) { + #ifdef MOON_TIMING_HINT + if (arg == 0) { + // let the user know they can let go now to stay at moon + uint8_t temp = actual_level; + set_level(0); + delay_4ms(2); + set_level(temp); + } else + #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 + set_state(steady_state, 1); + } + return MISCHIEF_MANAGED; + } + // hold, release quickly: go to lowest level (floor) + else if (event == EV_click1_hold_release) { + set_state(steady_state, 1); + return MISCHIEF_MANAGED; + } + // 1 click (before timeout): go to memorized level, but allow abort for double click + else if (event == EV_click1_release) { + set_level(nearest_level(memorized_level)); + return MISCHIEF_MANAGED; + } + // 1 click: regular mode + else if (event == EV_1click) { + set_state(steady_state, memorized_level); + return MISCHIEF_MANAGED; + } + // click, hold: go to highest level (ceiling) (for ramping down) + else if (event == EV_click2_hold) { + set_state(steady_state, MAX_LEVEL); + return MISCHIEF_MANAGED; + } + // 2 clicks: highest mode (ceiling) + else if (event == EV_2clicks) { + set_state(steady_state, MAX_LEVEL); + return MISCHIEF_MANAGED; + } + // 3 clicks (initial press): off, to prep for later events + else if (event == EV_click3_press) { + set_level(0); + return MISCHIEF_MANAGED; + } + #ifdef USE_BATTCHECK + // 3 clicks: battcheck mode / blinky mode group 1 + else if (event == EV_3clicks) { + set_state(battcheck_state, 0); + return MISCHIEF_MANAGED; + } + #endif + // click, click, long-click: strobe mode + #ifdef USE_STROBE_STATE + else if (event == EV_click3_hold) { + set_state(strobe_state, 0); + return MISCHIEF_MANAGED; + } + #endif + // 4 clicks: soft lockout + else if (event == EV_4clicks) { + blink_confirm(2); + set_state(lockout_state, 0); + return MISCHIEF_MANAGED; + } + // 5 clicks: momentary mode + else if (event == EV_5clicks) { + blink_confirm(1); + set_state(momentary_state, 0); + return MISCHIEF_MANAGED; + } + #ifdef USE_MUGGLE_MODE + // 6 clicks: muggle mode + else if (event == EV_6clicks) { + blink_confirm(1); + set_state(muggle_state, 0); + return MISCHIEF_MANAGED; + } + #endif + #ifdef USE_INDICATOR_LED + // 7 clicks: change indicator LED mode + else if (event == EV_7clicks) { + uint8_t mode = (indicator_led_mode & 3) + 1; + #ifdef TICK_DURING_STANDBY + mode = mode & 3; + #else + mode = mode % 3; + #endif + #ifdef INDICATOR_LED_SKIP_LOW + if (mode == 1) { mode ++; } + #endif + indicator_led_mode = (indicator_led_mode & 0b11111100) | mode; + indicator_led(mode); + save_config(); + return MISCHIEF_MANAGED; + } + #endif + return EVENT_NOT_HANDLED; +} + + +uint8_t steady_state(Event event, uint16_t arg) { + uint8_t mode_min = ramp_smooth_floor; + uint8_t mode_max = ramp_smooth_ceil; + uint8_t ramp_step_size = 1; + #ifdef USE_REVERSING + static int8_t ramp_direction = 1; + #endif + if (ramp_style) { + mode_min = ramp_discrete_floor; + mode_max = ramp_discrete_ceil; + ramp_step_size = ramp_discrete_step_size; + } + + // turn LED on when we first enter the mode + if ((event == EV_enter_state) || (event == EV_reenter_state)) { + // if we just got back from config mode, go back to memorized level + if (event == EV_reenter_state) { + arg = memorized_level; + } + // remember this level, unless it's moon or turbo + if ((arg > mode_min) && (arg < mode_max)) + memorized_level = arg; + // use the requested level even if not memorized + arg = nearest_level(arg); + #ifdef USE_THERMAL_REGULATION + target_level = arg; + #endif + set_level(arg); + #ifdef USE_REVERSING + ramp_direction = 1; + #endif + return MISCHIEF_MANAGED; + } + // 1 click: off + else if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: go to/from highest level + else if (event == EV_2clicks) { + if (actual_level < MAX_LEVEL) { + #ifdef USE_THERMAL_REGULATION + target_level = MAX_LEVEL; + #endif + // true turbo, not the mode-specific ceiling + set_level(MAX_LEVEL); + } + else { + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + set_level(memorized_level); + } + return MISCHIEF_MANAGED; + } + // 3 clicks: toggle smooth vs discrete ramping + else if (event == EV_3clicks) { + ramp_style = !ramp_style; + memorized_level = nearest_level(actual_level); + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #ifdef USE_SET_LEVEL_GRADUALLY + //set_level_gradually(lvl); + #endif + #endif + save_config(); + #ifdef START_AT_MEMORIZED_LEVEL + save_config_wl(); + #endif + set_level(0); + delay_4ms(20/4); + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + // 4 clicks: configure this ramp mode + else if (event == EV_4clicks) { + push_state(ramp_config_state, 0); + return MISCHIEF_MANAGED; + } + // hold: change brightness (brighter) + else if (event == EV_click1_hold) { + // ramp slower in discrete mode + if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { + return MISCHIEF_MANAGED; + } + #ifdef USE_REVERSING + // make it ramp down instead, if already at max + if ((arg <= 1) && (actual_level >= mode_max)) { + ramp_direction = -1; + } + memorized_level = nearest_level((int16_t)actual_level \ + + (ramp_step_size * ramp_direction)); + #else + memorized_level = nearest_level((int16_t)actual_level + ramp_step_size); + #endif + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + #if defined(BLINK_AT_RAMP_CEILING) || defined(BLINK_AT_CHANNEL_BOUNDARIES) + // only blink once for each threshold + if ((memorized_level != actual_level) && ( + 0 // for easier syntax below + #ifdef BLINK_AT_CHANNEL_BOUNDARIES + || (memorized_level == MAX_1x7135) + #if PWM_CHANNELS >= 3 + || (memorized_level == MAX_Nx7135) + #endif + #endif + #ifdef BLINK_AT_RAMP_CEILING + || (memorized_level == mode_max) + #endif + #if defined(USE_REVERSING) && defined(BLINK_AT_RAMP_FLOOR) + || (memorized_level == mode_min) + #endif + )) { + set_level(0); + delay_4ms(8/4); + } + #endif + #if defined(BLINK_AT_STEPS) + uint8_t foo = ramp_style; + ramp_style = 1; + uint8_t nearest = nearest_level((int16_t)actual_level); + ramp_style = foo; + // only blink once for each threshold + if ((memorized_level != actual_level) && + (ramp_style == 0) && + (memorized_level == nearest) + ) + { + set_level(0); + delay_4ms(8/4); + } + #endif + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + #if defined(USE_REVERSING) || defined(START_AT_MEMORIZED_LEVEL) + // reverse ramp direction on hold release + else if (event == EV_click1_hold_release) { + #ifdef USE_REVERSING + ramp_direction = -ramp_direction; + #endif + #ifdef START_AT_MEMORIZED_LEVEL + save_config_wl(); + #endif + return MISCHIEF_MANAGED; + } + #endif + // click, hold: change brightness (dimmer) + else if (event == EV_click2_hold) { + #ifdef USE_REVERSING + ramp_direction = 1; + #endif + // ramp slower in discrete mode + if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { + return MISCHIEF_MANAGED; + } + // TODO? make it ramp up instead, if already at min? + memorized_level = nearest_level((int16_t)actual_level - ramp_step_size); + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + #if defined(BLINK_AT_RAMP_FLOOR) || defined(BLINK_AT_CHANNEL_BOUNDARIES) + // only blink once for each threshold + if ((memorized_level != actual_level) && ( + 0 // for easier syntax below + #ifdef BLINK_AT_CHANNEL_BOUNDARIES + || (memorized_level == MAX_1x7135) + #if PWM_CHANNELS >= 3 + || (memorized_level == MAX_Nx7135) + #endif + #endif + #ifdef BLINK_AT_RAMP_FLOOR + || (memorized_level == mode_min) + #endif + )) { + set_level(0); + delay_4ms(8/4); + } + #endif + #if defined(BLINK_AT_STEPS) + uint8_t foo = ramp_style; + ramp_style = 1; + uint8_t nearest = nearest_level((int16_t)actual_level); + ramp_style = foo; + // only blink once for each threshold + if ((memorized_level != actual_level) && + (ramp_style == 0) && + (memorized_level == nearest) + ) + { + set_level(0); + delay_4ms(8/4); + } + #endif + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + #ifdef START_AT_MEMORIZED_LEVEL + // click, release, hold, release: save new ramp level (if necessary) + else if (event == EV_click2_hold_release) { + save_config_wl(); + return MISCHIEF_MANAGED; + } + #endif + #if defined(USE_SET_LEVEL_GRADUALLY) || defined(USE_REVERSING) + else if (event == EV_tick) { + #ifdef USE_REVERSING + // un-reverse after 1 second + if (arg == TICKS_PER_SECOND) ramp_direction = 1; + #endif + #ifdef USE_SET_LEVEL_GRADUALLY + // make thermal adjustment speed scale with magnitude + if ((arg & 1) && (actual_level < THERM_FASTER_LEVEL)) { + return MISCHIEF_MANAGED; // adjust slower when not a high mode + } + #ifdef THERM_HARD_TURBO_DROP + else if ((! (actual_level < THERM_FASTER_LEVEL)) + && (actual_level > gradual_target)) { + gradual_tick(); + } + else { + #endif + // [int(62*4 / (x**0.8)) for x in (1,2,4,8,16,32,64,128)] + //uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5}; + // [int(62*4 / (x**0.9)) for x in (1,2,4,8,16,32,64,128)] + //uint8_t intervals[] = {248, 132, 71, 38, 20, 10, 5, 3}; + // [int(62*4 / (x**0.95)) for x in (1,2,4,8,16,32,64,128)] + uint8_t intervals[] = {248, 128, 66, 34, 17, 9, 4, 2}; + uint8_t diff; + static uint8_t ticks_since_adjust = 0; + ticks_since_adjust ++; + if (gradual_target > actual_level) diff = gradual_target - actual_level; + else { + diff = actual_level - gradual_target; + } + uint8_t magnitude = 0; + #ifndef THERM_HARD_TURBO_DROP + // if we're on a really high mode, drop faster + if (actual_level >= THERM_FASTER_LEVEL) { magnitude ++; } + #endif + while (diff) { + magnitude ++; + diff >>= 1; + } + uint8_t ticks_per_adjust = intervals[magnitude]; + if (ticks_since_adjust > ticks_per_adjust) + { + gradual_tick(); + ticks_since_adjust = 0; + } + //if (!(arg % ticks_per_adjust)) gradual_tick(); + #ifdef THERM_HARD_TURBO_DROP + } + #endif + #endif + return MISCHIEF_MANAGED; + } + #endif + #ifdef USE_THERMAL_REGULATION + // overheating: drop by an amount proportional to how far we are above the ceiling + else if (event == EV_temperature_high) { + #if 0 + uint8_t foo = actual_level; + set_level(0); + delay_4ms(2); + set_level(foo); + #endif + #ifdef THERM_HARD_TURBO_DROP + if (actual_level > THERM_FASTER_LEVEL) { + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(THERM_FASTER_LEVEL); + #else + set_level(THERM_FASTER_LEVEL); + #endif + target_level = THERM_FASTER_LEVEL; + } else + #endif + if (actual_level > MIN_THERM_STEPDOWN) { + int16_t stepdown = actual_level - arg; + if (stepdown < MIN_THERM_STEPDOWN) stepdown = MIN_THERM_STEPDOWN; + else if (stepdown > MAX_LEVEL) stepdown = MAX_LEVEL; + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(stepdown); + #else + set_level(stepdown); + #endif + } + return MISCHIEF_MANAGED; + } + // underheating: increase slowly if we're lower than the target + // (proportional to how low we are) + else if (event == EV_temperature_low) { + #if 0 + uint8_t foo = actual_level; + set_level(0); + delay_4ms(2); + set_level(foo); + #endif + if (actual_level < target_level) { + //int16_t stepup = actual_level + (arg>>1); + int16_t stepup = actual_level + arg; + if (stepup > target_level) stepup = target_level; + else if (stepup < MIN_THERM_STEPDOWN) stepup = MIN_THERM_STEPDOWN; + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(stepup); + #else + set_level(stepup); + #endif + } + return MISCHIEF_MANAGED; + } + #endif + return EVENT_NOT_HANDLED; +} + + +#ifdef USE_STROBE_STATE +uint8_t strobe_state(Event event, uint16_t arg) { + // 'st' reduces ROM size by avoiding access to a volatile var + // (maybe I should just make it nonvolatile?) + strobe_mode_te st = strobe_type; + #ifdef USE_CANDLE_MODE + // FIXME: make candle variance magnitude a compile-time option, + // since 20 is sometimes too much or too little, + // depending on the driver type and ramp shape + //#define MAX_CANDLE_LEVEL (RAMP_SIZE-8-6-4) + #define MAX_CANDLE_LEVEL (RAMP_SIZE/2) + static uint8_t candle_wave1 = 0; + static uint8_t candle_wave2 = 0; + static uint8_t candle_wave3 = 0; + static uint8_t candle_wave2_speed = 0; + static uint8_t candle_wave2_depth = 7; + static uint8_t candle_wave3_depth = 4; + static uint8_t candle_mode_brightness = 24; + static uint8_t candle_mode_timer = 0; + #define TICKS_PER_CANDLE_MINUTE 4096 // about 65 seconds + #define MINUTES_PER_CANDLE_HALFHOUR 27 // ish + #endif + + if (event == EV_enter_state) { + #ifdef USE_CANDLE_MODE + candle_mode_timer = 0; // in case any time was left over from earlier + #endif + return MISCHIEF_MANAGED; + } + // 1 click: off + else if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: rotate through strobe/flasher modes + else if (event == EV_2clicks) { + strobe_type = (st + 1) % NUM_STROBES; + #ifdef USE_CANDLE_MODE + candle_mode_timer = 0; // in case any time was left over from earlier + #endif + //interrupt_nice_delays(); + save_config(); + return MISCHIEF_MANAGED; + } + // hold: change speed (go faster) + // or change brightness (brighter) + else if (event == EV_click1_hold) { + if (0) {} // placeholder + + // party / tactical strobe faster + #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) + #ifdef USE_TACTICAL_STROBE_MODE + else if (st <= tactical_strobe_e) { + #else + else if (st == party_strobe_e) { + #endif + if ((arg & 1) == 0) { + if (strobe_delays[st] > 8) strobe_delays[st] --; + } + } + #endif + + // lightning has no adjustments + //else if (st == lightning_storm_e) {} + + // candle mode brighter + #ifdef USE_CANDLE_MODE + else if (st == candle_mode_e) { + if (candle_mode_brightness < MAX_CANDLE_LEVEL) + candle_mode_brightness ++; + } + #endif + + // biking mode brighter + #ifdef USE_BIKE_FLASHER_MODE + else if (st == bike_flasher_e) { + if (bike_flasher_brightness < MAX_BIKING_LEVEL) + bike_flasher_brightness ++; + set_level(bike_flasher_brightness); + } + #endif + + return MISCHIEF_MANAGED; + } + // click, hold: change speed (go slower) + // or change brightness (dimmer) + else if (event == EV_click2_hold) { + if (0) {} // placeholder + + // party / tactical strobe slower + #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) + #ifdef USE_TACTICAL_STROBE_MODE + else if (st <= tactical_strobe_e) { + #else + else if (st == party_strobe_e) { + #endif + if ((arg & 1) == 0) { + if (strobe_delays[st] < 255) strobe_delays[st] ++; + } + } + #endif + + // lightning has no adjustments + //else if (st == lightning_storm_e) {} + + // candle mode dimmer + #ifdef USE_CANDLE_MODE + else if (st == candle_mode_e) { + if (candle_mode_brightness > 1) + candle_mode_brightness --; + } + #endif + + // 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); + } + #endif + + return MISCHIEF_MANAGED; + } + // release hold: save new strobe settings + else if ((event == EV_click1_hold_release) + || (event == EV_click2_hold_release)) { + save_config(); + return MISCHIEF_MANAGED; + } + #if defined(USE_CANDLE_MODE) + // 3 clicks: add 30m to candle timer + else if (event == EV_3clicks) { + // candle mode only + if (st == candle_mode_e) { + if (candle_mode_timer < (255 - MINUTES_PER_CANDLE_HALFHOUR)) { + // add 30m to the timer + candle_mode_timer += MINUTES_PER_CANDLE_HALFHOUR; + // blink to confirm + set_level(actual_level + 32); + delay_4ms(2); + } + } + return MISCHIEF_MANAGED; + } + #endif + #if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) + // clock tick: bump the random seed, adjust candle brightness + else if (event == EV_tick) { + pseudo_rand_seed += arg; + + #ifdef USE_CANDLE_MODE + if (st == candle_mode_e) { + // self-timer dims the light during the final minute + uint8_t subtract = 0; + if (candle_mode_timer == 1) { + subtract = ((candle_mode_brightness+20) + * ((arg & (TICKS_PER_CANDLE_MINUTE-1)) >> 4)) + >> 8; + } + // we passed a minute mark, decrease timer if it's running + if ((arg & (TICKS_PER_CANDLE_MINUTE-1)) == (TICKS_PER_CANDLE_MINUTE - 1)) { + if (candle_mode_timer > 0) { + candle_mode_timer --; + //set_level(0); delay_4ms(2); + // if the timer ran out, shut off + if (! candle_mode_timer) { + set_state(off_state, 0); + } + } + } + // 3-oscillator synth for a relatively organic pattern + uint8_t add; + add = ((triangle_wave(candle_wave1) * 8) >> 8) + + ((triangle_wave(candle_wave2) * candle_wave2_depth) >> 8) + + ((triangle_wave(candle_wave3) * candle_wave3_depth) >> 8); + int8_t brightness = candle_mode_brightness + add - subtract; + if (brightness < 0) { brightness = 0; } + set_level(brightness); + + // wave1: slow random LFO + if ((arg & 1) == 0) candle_wave1 += pseudo_rand() & 1; + // wave2: medium-speed erratic LFO + candle_wave2 += candle_wave2_speed; + // wave3: erratic fast wave + candle_wave3 += pseudo_rand() % 37; + // S&H on wave2 frequency to make it more erratic + if ((pseudo_rand() & 0b00111111) == 0) + candle_wave2_speed = pseudo_rand() % 13; + // downward sawtooth on wave2 depth to simulate stabilizing + if ((candle_wave2_depth > 0) && ((pseudo_rand() & 0b00111111) == 0)) + candle_wave2_depth --; + // random sawtooth retrigger + if ((pseudo_rand()) == 0) { + candle_wave2_depth = 7; + //candle_wave3_depth = 5; + candle_wave2 = 0; + } + // downward sawtooth on wave3 depth to simulate stabilizing + if ((candle_wave3_depth > 2) && ((pseudo_rand() & 0b00011111) == 0)) + candle_wave3_depth --; + if ((pseudo_rand() & 0b01111111) == 0) + candle_wave3_depth = 5; + } + #endif + return MISCHIEF_MANAGED; + } + #endif + return EVENT_NOT_HANDLED; +} +#endif // ifdef USE_STROBE_STATE + + +#ifdef USE_BATTCHECK +uint8_t battcheck_state(Event event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: goodnight mode + else if (event == EV_2clicks) { + set_state(goodnight_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} +#endif + + +#ifdef USE_THERMAL_REGULATION +uint8_t tempcheck_state(Event event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: battcheck mode + else if (event == EV_2clicks) { + set_state(battcheck_state, 0); + return MISCHIEF_MANAGED; + } + // 4 clicks: thermal config mode + else if (event == EV_4clicks) { + push_state(thermal_config_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} +#endif + + +uint8_t beacon_state(Event event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // TODO: use sleep ticks to measure time between pulses, + // to save power + // 2 clicks: tempcheck mode + else if (event == EV_2clicks) { + #ifdef USE_THERMAL_REGULATION + set_state(tempcheck_state, 0); + #else + set_state(battcheck_state, 0); + #endif + return MISCHIEF_MANAGED; + } + // 4 clicks: beacon config mode + else if (event == EV_4clicks) { + push_state(beacon_config_state, 0); + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + + +#define GOODNIGHT_TICKS_PER_STEPDOWN (GOODNIGHT_TIME*TICKS_PER_SECOND*60L/GOODNIGHT_LEVEL) +uint8_t goodnight_state(Event event, uint16_t arg) { + static uint16_t ticks_since_stepdown = 0; + // blink on start + if (event == EV_enter_state) { + ticks_since_stepdown = 0; + blink_confirm(2); + set_level(GOODNIGHT_LEVEL); + return MISCHIEF_MANAGED; + } + // 1 click: off + else if (event == EV_1click) { + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: beacon mode + else if (event == EV_2clicks) { + set_state(beacon_state, 0); + return MISCHIEF_MANAGED; + } + // tick: step down (maybe) or off (maybe) + else if (event == EV_tick) { + if (++ticks_since_stepdown > GOODNIGHT_TICKS_PER_STEPDOWN) { + ticks_since_stepdown = 0; + set_level(actual_level-1); + if (! actual_level) { + #if 0 // test blink, to help measure timing + set_level(MAX_LEVEL>>2); + delay_4ms(8/2); + set_level(0); + #endif + set_state(off_state, 0); + } + } + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + + +uint8_t lockout_state(Event event, uint16_t arg) { + #ifdef MOON_DURING_LOCKOUT_MODE + // momentary(ish) moon mode during lockout + // button is being held + if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) { + #ifdef LOCKOUT_MOON_LOWEST + // Use lowest moon configured + uint8_t lvl = ramp_smooth_floor; + if (ramp_discrete_floor < lvl) lvl = ramp_discrete_floor; + set_level(lvl); + #elif defined(LOCKOUT_MOON_FANCY) + uint8_t levels[] = { ramp_smooth_floor, ramp_discrete_floor }; + if ((event & 0x0f) == 2) { + set_level(levels[ramp_style^1]); + } else { + set_level(levels[ramp_style]); + } + #else + // Use moon from current ramp + set_level(nearest_level(1)); + #endif + } + // button was released + else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) { + set_level(0); + } + #endif + + // regular event handling + // conserve power while locked out + // (allow staying awake long enough to exit, but otherwise + // be persistent about going back to sleep every few seconds + // even if the user keeps pressing the button) + #ifdef USE_INDICATOR_LED + if (event == EV_enter_state) { + indicator_led(indicator_led_mode >> 2); + } else + #endif + if (event == EV_tick) { + if (arg > TICKS_PER_SECOND*2) { + go_to_standby = 1; + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode >> 2); + #endif + } + return MISCHIEF_MANAGED; + } + #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) + else if (event == EV_sleep_tick) { + if ((indicator_led_mode & 0b00001100) == 0b00001100) { + indicator_blink(arg); + } + return MISCHIEF_MANAGED; + } + #endif + #ifdef USE_INDICATOR_LED + // 3 clicks: rotate through indicator LED modes (lockout mode) + else if (event == EV_3clicks) { + uint8_t mode = indicator_led_mode >> 2; + #ifdef TICK_DURING_STANDBY + mode = (mode + 1) & 3; + #else + mode = (mode + 1) % 3; + #endif + #ifdef INDICATOR_LED_SKIP_LOW + if (mode == 1) { mode ++; } + #endif + indicator_led_mode = (mode << 2) + (indicator_led_mode & 0x03); + indicator_led(mode); + save_config(); + return MISCHIEF_MANAGED; + } + #if 0 // old method, deprecated in favor of "7 clicks from off" + // click, click, hold: rotate through indicator LED modes (off mode) + else if (event == EV_click3_hold) { + #ifndef USE_INDICATOR_LED_WHILE_RAMPING + // if main LED obscures aux LEDs, turn it off + set_level(0); + #endif + #ifdef TICK_DURING_STANDBY + uint8_t mode = (arg >> 5) & 3; + #else + uint8_t mode = (arg >> 5) % 3; + #endif + #ifdef INDICATOR_LED_SKIP_LOW + if (mode == 1) { mode ++; } + #endif + indicator_led_mode = (indicator_led_mode & 0b11111100) | mode; + #ifdef TICK_DURING_STANDBY + if (mode == 3) + indicator_led(mode & (arg&3)); + else + indicator_led(mode); + #else + indicator_led(mode); + #endif + //save_config(); + return MISCHIEF_MANAGED; + } + // click, click, hold, release: save indicator LED mode (off mode) + else if (event == EV_click3_hold_release) { + save_config(); + return MISCHIEF_MANAGED; + } + #endif + #endif + // 4 clicks: exit + else if (event == EV_4clicks) { + blink_confirm(1); + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + + return EVENT_NOT_HANDLED; +} + + +uint8_t momentary_state(Event event, uint16_t arg) { + // TODO: momentary strobe here? (for light painting) + + // light up when the button is pressed; go dark otherwise + // button is being held + if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) { + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + // button was released + else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) { + set_level(0); + //go_to_standby = 1; // sleep while light is off + return MISCHIEF_MANAGED; + } + + // Sleep, dammit! (but wait a few seconds first) + // (because standby mode uses such little power that it can interfere + // with exiting via tailcap loosen+tighten unless you leave power + // disconnected for several seconds, so we want to be awake when that + // happens to speed up the process) + else if ((event == EV_tick) && (actual_level == 0)) { + if (arg > TICKS_PER_SECOND*15) { // sleep after 15 seconds + go_to_standby = 1; // sleep while light is off + // TODO: lighted button should use lockout config? + } + return MISCHIEF_MANAGED; + } + + return EVENT_NOT_HANDLED; +} + + +#ifdef USE_MUGGLE_MODE +uint8_t muggle_state(Event event, uint16_t arg) { + static int8_t ramp_direction; + static int8_t muggle_off_mode; + + // turn LED off when we first enter the mode + if (event == EV_enter_state) { + ramp_direction = 1; + + #ifdef START_AT_MEMORIZED_LEVEL + memorized_level = arg; + muggle_off_mode = 0; + set_level(memorized_level); + + if (! muggle_mode_active) { // don't write eeprom at every boot + muggle_mode_active = 1; + save_config(); + } + #else + muggle_mode_active = 1; + save_config(); + + muggle_off_mode = 1; + //memorized_level = MAX_1x7135; + memorized_level = (MUGGLE_FLOOR + MUGGLE_CEILING) / 2; + #endif + return MISCHIEF_MANAGED; + } + // initial press: moon hint + else if (event == EV_click1_press) { + if (muggle_off_mode) + set_level(MUGGLE_FLOOR); + } + // initial release: direct to memorized level + else if (event == EV_click1_release) { + if (muggle_off_mode) + set_level(memorized_level); + } + // if the user keeps pressing, turn off + else if (event == EV_click2_press) { + muggle_off_mode = 1; + set_level(0); + } + // 1 click: on/off + else if (event == EV_1click) { + muggle_off_mode ^= 1; + if (muggle_off_mode) { + set_level(0); + } + /* + else { + set_level(memorized_level); + } + */ + return MISCHIEF_MANAGED; + } + // hold: change brightness + else if (event == EV_click1_hold) { + // ramp at half speed + if (arg & 1) return MISCHIEF_MANAGED; + + // if off, start at bottom + if (muggle_off_mode) { + muggle_off_mode = 0; + ramp_direction = 1; + set_level(MUGGLE_FLOOR); + } + else { + uint8_t m; + m = actual_level; + // ramp down if already at ceiling + if ((arg <= 1) && (m >= MUGGLE_CEILING)) ramp_direction = -1; + // ramp + m += ramp_direction; + if (m < MUGGLE_FLOOR) + m = MUGGLE_FLOOR; + if (m > MUGGLE_CEILING) + m = MUGGLE_CEILING; + memorized_level = m; + set_level(m); + } + return MISCHIEF_MANAGED; + } + // reverse ramp direction on hold release + else if (event == EV_click1_hold_release) { + ramp_direction = -ramp_direction; + #ifdef START_AT_MEMORIZED_LEVEL + save_config_wl(); // momentary use should retain brightness level + #endif + return MISCHIEF_MANAGED; + } + /* + // click, hold: change brightness (dimmer) + else if (event == EV_click2_hold) { + ramp_direction = 1; + if (memorized_level > MUGGLE_FLOOR) + memorized_level = actual_level - 1; + set_level(memorized_level); + return MISCHIEF_MANAGED; + } + */ + // 6 clicks: exit muggle mode + else if (event == EV_6clicks) { + blink_confirm(1); + muggle_mode_active = 0; + save_config(); + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // tick: housekeeping + else if (event == EV_tick) { + // un-reverse after 1 second + if (arg == TICKS_PER_SECOND) ramp_direction = 1; + + // turn off, but don't go to the main "off" state + if (muggle_off_mode) { + if (arg > TICKS_PER_SECOND*1) { // sleep after 1 second + go_to_standby = 1; // sleep while light is off + } + } + return MISCHIEF_MANAGED; + } + #ifdef USE_THERMAL_REGULATION + // overheating is handled specially in muggle mode + else if(event == EV_temperature_high) { + // don't even try... + // go immediately to the bottom, in case someone put the light on + // maximum while wrapped in dark-colored flammable insulation + // or something, because muggles are cool like that + // memorized_level = MUGGLE_FLOOR; // override memory? maybe not + set_level(MUGGLE_FLOOR); + return MISCHIEF_MANAGED; + } + #endif + // low voltage is handled specially in muggle mode + else if(event == EV_voltage_low) { + uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); + if (lvl >= MUGGLE_FLOOR) { + set_level(lvl); + } else { + muggle_off_mode = 1; + } + return MISCHIEF_MANAGED; + } + + return EVENT_NOT_HANDLED; +} +#endif + + +// ask the user for a sequence of numbers, then save them and return to caller +uint8_t config_state_base(Event event, uint16_t arg, + uint8_t num_config_steps, + void (*savefunc)()) { + static uint8_t config_step; + if (event == EV_enter_state) { + config_step = 0; + set_level(0); + return MISCHIEF_MANAGED; + } + // advance forward through config steps + else if (event == EV_tick) { + if (config_step < num_config_steps) { + push_state(number_entry_state, config_step + 1); + } + else { + // TODO: blink out some sort of success pattern + savefunc(); + save_config(); + //set_state(retstate, retval); + pop_state(); + } + return MISCHIEF_MANAGED; + } + // an option was set (return from number_entry_state) + else if (event == EV_reenter_state) { + config_state_values[config_step] = number_entry_value; + config_step ++; + return MISCHIEF_MANAGED; + } + //return EVENT_NOT_HANDLED; + // eat all other events; don't pass any through to parent + return EVENT_HANDLED; +} + +void ramp_config_save() { + // parse values + uint8_t val; + if (ramp_style) { // discrete / stepped ramp + + val = config_state_values[0]; + if (val) { ramp_discrete_floor = val; } + + val = config_state_values[1]; + if (val) { ramp_discrete_ceil = MAX_LEVEL + 1 - val; } + + val = config_state_values[2]; + if (val) ramp_discrete_steps = val; + + } else { // smooth ramp + + val = config_state_values[0]; + if (val) { ramp_smooth_floor = val; } + + val = config_state_values[1]; + if (val) { ramp_smooth_ceil = MAX_LEVEL + 1 - val; } + + } +} + +uint8_t ramp_config_state(Event event, uint16_t arg) { + uint8_t num_config_steps; + num_config_steps = 2 + ramp_style; + return config_state_base(event, arg, + num_config_steps, ramp_config_save); +} + + +#ifdef USE_THERMAL_REGULATION +void thermal_config_save() { + // parse values + uint8_t val; + + // calibrate room temperature + val = config_state_values[0]; + if (val) { + int8_t rawtemp = (temperature >> 1) - therm_cal_offset; + therm_cal_offset = val - rawtemp; + } + + val = config_state_values[1]; + if (val) { + // set maximum heat limit + therm_ceil = 30 + val; + } + if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL; +} + +uint8_t thermal_config_state(Event event, uint16_t arg) { + return config_state_base(event, arg, + 2, thermal_config_save); +} +#endif + + +void beacon_config_save() { + // parse values + uint8_t val = config_state_values[0]; + if (val) { + beacon_seconds = val; + } +} + +uint8_t beacon_config_state(Event event, uint16_t arg) { + return config_state_base(event, arg, + 1, beacon_config_save); +} + + +uint8_t number_entry_state(Event event, uint16_t arg) { + static uint8_t value; + static uint8_t blinks_left; + static uint8_t entry_step; + static uint16_t wait_ticks; + if (event == EV_enter_state) { + value = 0; + blinks_left = arg; + entry_step = 0; + wait_ticks = 0; + return MISCHIEF_MANAGED; + } + // advance through the process: + // 0: wait a moment + // 1: blink out the 'arg' value + // 2: wait a moment + // 3: "buzz" while counting clicks + // 4: save and exit + else if (event == EV_tick) { + // wait a moment + if ((entry_step == 0) || (entry_step == 2)) { + if (wait_ticks < TICKS_PER_SECOND/2) + wait_ticks ++; + else { + entry_step ++; + wait_ticks = 0; + } + } + // blink out the option number + else if (entry_step == 1) { + if (blinks_left) { + if ((wait_ticks & 31) == 10) { + set_level(RAMP_SIZE/4); + } + else if ((wait_ticks & 31) == 20) { + set_level(0); + } + else if ((wait_ticks & 31) == 31) { + blinks_left --; + } + wait_ticks ++; + } + else { + entry_step ++; + wait_ticks = 0; + } + } + else if (entry_step == 3) { // buzz while waiting for a number to be entered + wait_ticks ++; + // buzz for N seconds after last event + if ((wait_ticks & 3) == 0) { + set_level(RAMP_SIZE/6); + } + else if ((wait_ticks & 3) == 2) { + set_level(RAMP_SIZE/8); + } + // time out after 3 seconds + if (wait_ticks > TICKS_PER_SECOND*3) { + //number_entry_value = value; + set_level(0); + entry_step ++; + } + } + else if (entry_step == 4) { + number_entry_value = value; + pop_state(); + } + return MISCHIEF_MANAGED; + } + // count clicks + else if (event == EV_click1_release) { + empty_event_sequence(); + if (entry_step == 3) { // only count during the "buzz" + value ++; + wait_ticks = 0; + // flash briefly + set_level(RAMP_SIZE/2); + delay_4ms(8/2); + set_level(0); + } + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + + +// find the ramp level closest to the target, +// using only the levels which are allowed in the current state +uint8_t nearest_level(int16_t target) { + // bounds check + // using int16_t here saves us a bunch of logic elsewhere, + // by allowing us to correct for numbers < 0 or > 255 in one central place + uint8_t mode_min = ramp_smooth_floor; + uint8_t mode_max = ramp_smooth_ceil; + if (ramp_style) { + mode_min = ramp_discrete_floor; + mode_max = ramp_discrete_ceil; + } + 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; + + uint8_t ramp_range = ramp_discrete_ceil - ramp_discrete_floor; + ramp_discrete_step_size = ramp_range / (ramp_discrete_steps-1); + uint8_t this_level = ramp_discrete_floor; + + for(uint8_t i=0; i>1)) + return this_level; + } + return this_level; +} + + +void blink_confirm(uint8_t num) { + for (; num>0; num--) { + set_level(MAX_LEVEL/4); + delay_4ms(10/4); + set_level(0); + delay_4ms(100/4); + } +} + + +#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) +// beacon-like mode for the indicator LED +void indicator_blink(uint8_t arg) { + #ifdef USE_FANCIER_BLINKING_INDICATOR + + // fancy blink, set off/low/high levels here: + uint8_t seq[] = {0, 1, 2, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0}; + indicator_led(seq[arg & 15]); + + #else // basic blink, 1/8th duty cycle + + if (! (arg & 7)) { + indicator_led(2); + } + else { + indicator_led(0); + } + + #endif +} +#endif + + +#ifdef USE_CANDLE_MODE +uint8_t triangle_wave(uint8_t phase) { + uint8_t result = phase << 1; + if (phase > 127) result = 255 - result; + return result; +} +#endif + + +void load_config() { + if (load_eeprom()) { + ramp_style = eeprom[ramp_style_e]; + ramp_smooth_floor = eeprom[ramp_smooth_floor_e]; + ramp_smooth_ceil = eeprom[ramp_smooth_ceil_e]; + ramp_discrete_floor = eeprom[ramp_discrete_floor_e]; + ramp_discrete_ceil = eeprom[ramp_discrete_ceil_e]; + ramp_discrete_steps = eeprom[ramp_discrete_steps_e]; + #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 + beacon_seconds = eeprom[beacon_seconds_e]; + #ifdef USE_MUGGLE_MODE + muggle_mode_active = eeprom[muggle_mode_active_e]; + #endif + #ifdef USE_THERMAL_REGULATION + therm_ceil = eeprom[therm_ceil_e]; + therm_cal_offset = eeprom[therm_cal_offset_e]; + #endif + #ifdef USE_INDICATOR_LED + indicator_led_mode = eeprom[indicator_led_mode_e]; + #endif + } + #ifdef START_AT_MEMORIZED_LEVEL + if (load_eeprom_wl()) { + memorized_level = eeprom_wl[0]; + } + #endif +} + +void save_config() { + eeprom[ramp_style_e] = ramp_style; + eeprom[ramp_smooth_floor_e] = ramp_smooth_floor; + eeprom[ramp_smooth_ceil_e] = ramp_smooth_ceil; + eeprom[ramp_discrete_floor_e] = ramp_discrete_floor; + eeprom[ramp_discrete_ceil_e] = ramp_discrete_ceil; + eeprom[ramp_discrete_steps_e] = ramp_discrete_steps; + #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 + eeprom[beacon_seconds_e] = beacon_seconds; + #ifdef USE_MUGGLE_MODE + eeprom[muggle_mode_active_e] = muggle_mode_active; + #endif + #ifdef USE_THERMAL_REGULATION + eeprom[therm_ceil_e] = therm_ceil; + eeprom[therm_cal_offset_e] = therm_cal_offset; + #endif + #ifdef USE_INDICATOR_LED + eeprom[indicator_led_mode_e] = indicator_led_mode; + #endif + + save_eeprom(); +} + +#ifdef START_AT_MEMORIZED_LEVEL +void save_config_wl() { + eeprom_wl[0] = memorized_level; + save_eeprom_wl(); +} +#endif + +void low_voltage() { + StatePtr state = current_state; + + // TODO: turn off aux LED(s) when power is really low + + if (0) {} // placeholder + + #ifdef USE_STROBE_STATE + // "step down" from strobe to something low + else if (state == strobe_state) { + set_state(steady_state, RAMP_SIZE/6); + } + #endif + + // in normal or muggle mode, step down or turn off + //else if ((state == steady_state) || (state == muggle_state)) { + else if (state == steady_state) { + if (actual_level > 1) { + uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); + set_level(lvl); + #ifdef USE_THERMAL_REGULATION + target_level = lvl; + #ifdef USE_SET_LEVEL_GRADUALLY + // not needed? + //set_level_gradually(lvl); + #endif + #endif + } + else { + set_state(off_state, 0); + } + } + // all other modes, just turn off when voltage is low + else { + set_state(off_state, 0); + } +} + + +void setup() { + #ifdef START_AT_MEMORIZED_LEVEL + // dual switch: e-switch + power clicky + // power clicky acts as a momentary mode + load_config(); + + #ifdef USE_MUGGLE_MODE + if (muggle_mode_active) + push_state(muggle_state, memorized_level); + else + #endif + if (button_is_pressed()) + // hold button to go to moon + push_state(steady_state, 1); + else + // otherwise use memory + push_state(steady_state, memorized_level); + + #else // if not START_AT_MEMORIZED_LEVEL + + // blink at power-on to let user know power is connected + set_level(RAMP_SIZE/8); + delay_4ms(3); + set_level(0); + + load_config(); + + #ifdef USE_MUGGLE_MODE + if (muggle_mode_active) + push_state(muggle_state, (MUGGLE_FLOOR+MUGGLE_CEILING)/2); + else + #endif + push_state(off_state, 0); + #endif + +} + + +void loop() { + + StatePtr state = current_state; + + if (0) {} + + #ifdef USE_STROBE_STATE + if (state == strobe_state) { + uint8_t st = strobe_type; + + if (0) {} // placeholder + + // party / tactial strobe + #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) + #ifdef USE_TACTICAL_STROBE_MODE + else if (st <= tactical_strobe_e) { + #else + else if (st == party_strobe_e) { + #endif + uint8_t del = strobe_delays[st]; + // TODO: make tac strobe brightness configurable? + set_level(STROBE_BRIGHTNESS); + if (st == party_strobe_e) { // party strobe + if (del < 42) delay_zero(); + else nice_delay_ms(1); + } else { //tactical strobe + nice_delay_ms(del >> 1); + } + set_level(0); + nice_delay_ms(del); // no return check necessary on final delay + } + #endif + + // lightning storm + #ifdef USE_LIGHTNING_MODE + else if (st == lightning_storm_e) { + int16_t brightness; + uint16_t rand_time; + + // turn the emitter on at a random level, + // for a random amount of time between 1ms and 32ms + //rand_time = 1 << (pseudo_rand() % 7); + rand_time = pseudo_rand() & 63; + brightness = 1 << (pseudo_rand() % 7); // 1, 2, 4, 8, 16, 32, 64 + brightness += 1 << (pseudo_rand() & 0x03); // 2 to 80 now + brightness += pseudo_rand() % brightness; // 2 to 159 now (w/ low bias) + if (brightness > MAX_LEVEL) brightness = MAX_LEVEL; + set_level(brightness); + nice_delay_ms(rand_time); + + // decrease the brightness somewhat more gradually, like lightning + uint8_t stepdown = brightness >> 3; + if (stepdown < 1) stepdown = 1; + while(brightness > 1) { + nice_delay_ms(rand_time); + brightness -= stepdown; + if (brightness < 0) brightness = 0; + set_level(brightness); + /* + if ((brightness < MAX_LEVEL/2) && (! (pseudo_rand() & 15))) { + brightness <<= 1; + set_level(brightness); + } + */ + if (! (pseudo_rand() & 3)) { + nice_delay_ms(rand_time); + set_level(brightness>>1); + } + } + + // turn the emitter off, + // for a random amount of time between 1ms and 8192ms + // (with a low bias) + rand_time = 1 << (pseudo_rand() % 13); + rand_time += pseudo_rand() % rand_time; + set_level(0); + nice_delay_ms(rand_time); // no return check necessary on final delay + } + #endif + + // candle mode + #ifdef USE_CANDLE_MODE + // this NOP should get compiled out + else if (st == candle_mode_e) {} + #endif + + // bike flasher + #ifdef USE_BIKE_FLASHER_MODE + else if (st == bike_flasher_e) { + uint8_t burst = 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); + nice_delay_ms(65); + } + nice_delay_ms(720); // no return check necessary on final delay + } + #endif + + } + #endif // #ifdef USE_STROBE_STATE + + #ifdef USE_BATTCHECK + else if (state == battcheck_state) { + battcheck(); + } + #endif + #ifdef USE_THERMAL_REGULATION + // TODO: blink out therm_ceil during thermal_config_state + else if (state == tempcheck_state) { + blink_num(temperature>>1); + nice_delay_ms(1000); + } + #endif + + else if (state == beacon_state) { + set_level(memorized_level); + nice_delay_ms(500); + set_level(0); + nice_delay_ms(((beacon_seconds) * 1000) - 500); + } + + #ifdef USE_IDLE_MODE + else { + // doze until next clock tick + idle_mode(); + } + #endif + +} -- cgit v1.2.3 From d70330a712b2b410717aa775f031fd39961adb04 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 12 Mar 2019 01:39:40 -0600 Subject: config file for unnamed Fireflies EDC thrower, with spec'd values --- .../fireflies-ui/cfg-ff-edc-thrower.h | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 spaghetti-monster/fireflies-ui/cfg-ff-edc-thrower.h diff --git a/spaghetti-monster/fireflies-ui/cfg-ff-edc-thrower.h b/spaghetti-monster/fireflies-ui/cfg-ff-edc-thrower.h new file mode 100644 index 0000000..752afe2 --- /dev/null +++ b/spaghetti-monster/fireflies-ui/cfg-ff-edc-thrower.h @@ -0,0 +1,27 @@ +// Fireflies EDC thrower config options for Fireflies UI +#include "cfg-ff-pl47.h" + +// disable indicator LED +#undef USE_INDICATOR_LED + +// ceiling is level 130/150 (50% power) +#undef RAMP_SMOOTH_CEIL +#define RAMP_SMOOTH_CEIL 130 + +// 10, 28, 46, 65, 83, 101, 120 (83 is highest regulated) +#undef RAMP_DISCRETE_FLOOR +#define RAMP_DISCRETE_FLOOR 20 +#undef RAMP_DISCRETE_CEIL +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#undef RAMP_DISCRETE_STEPS +#define RAMP_DISCRETE_STEPS 3 + +// regulate down faster when the FET is active, slower otherwise +#undef THERM_FASTER_LEVEL +#define THERM_FASTER_LEVEL 130 // throttle back faster when high + +// play it safe, don't try to regulate above the recommended safe level +#ifndef THERM_HARD_TURBO_DROP +#define THERM_HARD_TURBO_DROP +#endif + -- cgit v1.2.3 From 3a5ed200c051a3e54b4ad6ae5bf719516d2fa267 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 12 Mar 2019 01:45:40 -0600 Subject: first working rev of Fireflies UI, with changes basically as minimal as possible from Anduril to make it easier to keep the two in sync later - changed name - changed default config file - disabled ramp config - disabled muggle mode - disabled entire strobe group - disabled goodnight and beacon mode - made battcheck group only one mode, not a group - added boring strobe group (police strobe, SOS) - changed "7 clicks from off" to tempcheck mode - added "10 clicks from off" for thermal config mode - made stuff able to be turned off at compile time: - beacon mode - ramp config - goodnight mode --- spaghetti-monster/fireflies-ui/fireflies-ui.c | 197 +++++++++++++++++++++++--- 1 file changed, 176 insertions(+), 21 deletions(-) diff --git a/spaghetti-monster/fireflies-ui/fireflies-ui.c b/spaghetti-monster/fireflies-ui/fireflies-ui.c index 09c7927..5ad5ad0 100644 --- a/spaghetti-monster/fireflies-ui/fireflies-ui.c +++ b/spaghetti-monster/fireflies-ui/fireflies-ui.c @@ -1,8 +1,8 @@ /* - * Anduril: Narsil-inspired UI for SpaghettiMonster. - * (Anduril is Aragorn's sword, the blade Narsil reforged) + * Fireflies UI: A custom UI for Fireflies-brand flashlights. + * (based on Anduril by ToyKeeper) * - * Copyright (C) 2017 Selene ToyKeeper + * Copyright (C) 2019 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 @@ -19,8 +19,8 @@ */ /********* User-configurable options *********/ -// Anduril config file name (set it here or define it at the gcc command line) -//#define CONFIGFILE cfg-blf-q8.h +// UI config file name (set it here or define it at the gcc command line) +//#define CONFIGFILE cfg-ff-pl47.h #define USE_LVP // FIXME: won't build when this option is turned off @@ -67,6 +67,45 @@ #include "tk.h" #include incfile(CONFIGFILE) +// Fireflies-specific configuration +// disable ramp config +#ifdef USE_RAMP_CONFIG +#undef USE_RAMP_CONFIG +#endif + +// no muggle mode +#ifdef USE_MUGGLE_MODE +#undef USE_MUGGLE_MODE +#endif + +// turn off strobe mode entirely; we're replacing it +#ifdef USE_BIKE_FLASHER_MODE +#undef USE_BIKE_FLASHER_MODE +#endif +#ifdef USE_PARTY_STROBE_MODE +#undef USE_PARTY_STROBE_MODE +#endif +#ifdef USE_TACTICAL_STROBE_MODE +#undef USE_TACTICAL_STROBE_MODE +#endif +#ifdef USE_LIGHTNING_MODE +#undef USE_LIGHTNING_MODE +#endif +#ifdef USE_CANDLE_MODE +#undef USE_CANDLE_MODE +#endif + +// remove other blinkies too +#ifdef USE_GOODNIGHT_MODE +#undef USE_GOODNIGHT_MODE +#endif +#ifdef USE_BEACON_MODE +#undef USE_BEACON_MODE +#endif + +// use these strobes instead +#define USE_POLICE_STROBE_MODE +#define USE_SOS_MODE // thermal properties, if not defined per-driver #ifndef MIN_THERM_STEPDOWN @@ -116,6 +155,10 @@ #define USE_STROBE_STATE #endif +#if defined(USE_POLICE_STROBE_MODE) || defined(USE_SOS_MODE) +#define USE_BORING_STROBE_STATE +#endif + // auto-detect how many eeprom bytes #define USE_EEPROM typedef enum { @@ -135,7 +178,9 @@ typedef enum { #ifdef USE_BIKE_FLASHER_MODE bike_flasher_brightness_e, #endif + #ifdef USE_BEACON_MODE beacon_seconds_e, + #endif #ifdef USE_MUGGLE_MODE muggle_mode_active_e, #endif @@ -173,11 +218,19 @@ uint8_t config_state_base(Event event, uint16_t arg, uint8_t config_state_values[MAX_CONFIG_VALUES]; // ramping mode and its related config mode uint8_t steady_state(Event event, uint16_t arg); +#ifdef USE_RAMP_CONFIG uint8_t ramp_config_state(Event event, uint16_t arg); +#endif // party and tactical strobes #ifdef USE_STROBE_STATE uint8_t strobe_state(Event event, uint16_t arg); #endif +#ifdef USE_BORING_STROBE_STATE +uint8_t boring_strobe_state(Event event, uint16_t arg); +volatile uint8_t boring_strobe_type = 0; +void sos_blink(uint8_t num, uint8_t dah); +#define NUM_BORING_STROBES 2 +#endif #ifdef USE_BATTCHECK uint8_t battcheck_state(Event event, uint16_t arg); #endif @@ -185,11 +238,15 @@ uint8_t battcheck_state(Event event, uint16_t arg); uint8_t tempcheck_state(Event event, uint16_t arg); uint8_t thermal_config_state(Event event, uint16_t arg); #endif +#ifdef USE_GOODNIGHT_MODE // 1-hour ramp down from low, then automatic off uint8_t goodnight_state(Event event, uint16_t arg); +#endif +#ifdef USE_BEACON_MODE // beacon mode and its related config mode uint8_t beacon_state(Event event, uint16_t arg); uint8_t beacon_config_state(Event event, uint16_t arg); +#endif // soft lockout #define MOON_DURING_LOCKOUT_MODE // if enabled, 2nd lockout click goes to the other ramp's floor level @@ -323,8 +380,10 @@ volatile uint8_t bike_flasher_brightness = MAX_1x7135; uint8_t triangle_wave(uint8_t phase); #endif +#ifdef USE_BEACON_MODE // beacon timing volatile uint8_t beacon_seconds = 2; +#endif uint8_t off_state(Event event, uint16_t arg) { @@ -424,6 +483,11 @@ uint8_t off_state(Event event, uint16_t arg) { set_state(strobe_state, 0); return MISCHIEF_MANAGED; } + #elif defined(USE_BORING_STROBE_STATE) + else if (event == EV_click3_hold) { + set_state(boring_strobe_state, 0); + return MISCHIEF_MANAGED; + } #endif // 4 clicks: soft lockout else if (event == EV_4clicks) { @@ -445,24 +509,16 @@ uint8_t off_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif - #ifdef USE_INDICATOR_LED - // 7 clicks: change indicator LED mode + // 7 clicks: temperature check else if (event == EV_7clicks) { - uint8_t mode = (indicator_led_mode & 3) + 1; - #ifdef TICK_DURING_STANDBY - mode = mode & 3; - #else - mode = mode % 3; - #endif - #ifdef INDICATOR_LED_SKIP_LOW - if (mode == 1) { mode ++; } - #endif - indicator_led_mode = (indicator_led_mode & 0b11111100) | mode; - indicator_led(mode); - save_config(); + set_state(tempcheck_state, 0); + return MISCHIEF_MANAGED; + } + // 10 clicks: thermal config mode + else if (event == EV_10clicks) { + push_state(thermal_config_state, 0); return MISCHIEF_MANAGED; } - #endif return EVENT_NOT_HANDLED; } @@ -541,11 +597,13 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(memorized_level); return MISCHIEF_MANAGED; } + #ifdef USE_RAMP_CONFIG // 4 clicks: configure this ramp mode else if (event == EV_4clicks) { push_state(ramp_config_state, 0); return MISCHIEF_MANAGED; } + #endif // hold: change brightness (brighter) else if (event == EV_click1_hold) { // ramp slower in discrete mode @@ -998,6 +1056,49 @@ uint8_t strobe_state(Event event, uint16_t arg) { #endif // ifdef USE_STROBE_STATE +#ifdef USE_BORING_STROBE_STATE +uint8_t boring_strobe_state(Event event, uint16_t arg) { + // police strobe and SOS, meh + // 'st' reduces ROM size by avoiding access to a volatile var + // (maybe I should just make it nonvolatile?) + uint8_t st = boring_strobe_type; + + if (event == EV_enter_state) { + return MISCHIEF_MANAGED; + } + // 1 click: off + else if (event == EV_1click) { + // reset to police strobe for next time + boring_strobe_type = 0; + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: rotate through strobe/flasher modes + else if (event == EV_2clicks) { + boring_strobe_type = (st + 1) % NUM_BORING_STROBES; + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + +void sos_blink(uint8_t num, uint8_t dah) { + #define DIT_LENGTH 200 + for (; num > 0; num--) { + set_level(memorized_level); + nice_delay_ms(DIT_LENGTH); + if (dah) { // dah is 3X as long as a dit + nice_delay_ms(DIT_LENGTH*2); + } + set_level(0); + // one "off" dit between blinks + nice_delay_ms(DIT_LENGTH); + } + // three "off" dits (or one "dah") between letters + nice_delay_ms(DIT_LENGTH*2); +} +#endif // ifdef USE_BORING_STROBE_STATE + + #ifdef USE_BATTCHECK uint8_t battcheck_state(Event event, uint16_t arg) { // 1 click: off @@ -1005,11 +1106,17 @@ uint8_t battcheck_state(Event event, uint16_t arg) { set_state(off_state, 0); return MISCHIEF_MANAGED; } - // 2 clicks: goodnight mode + #if defined(USE_GOODNIGHT_MODE) || defined(USE_BEACON_MODE) + // 2 clicks: next mode else if (event == EV_2clicks) { + #ifdef USE_GOODNIGHT_MODE set_state(goodnight_state, 0); + #elif defined(USE_BEACON_MODE) + set_state(beacon_state, 0); + #endif return MISCHIEF_MANAGED; } + #endif return EVENT_NOT_HANDLED; } #endif @@ -1022,11 +1129,13 @@ uint8_t tempcheck_state(Event event, uint16_t arg) { set_state(off_state, 0); return MISCHIEF_MANAGED; } + #if 0 // not part of a loop in this UI // 2 clicks: battcheck mode else if (event == EV_2clicks) { set_state(battcheck_state, 0); return MISCHIEF_MANAGED; } + #endif // 4 clicks: thermal config mode else if (event == EV_4clicks) { push_state(thermal_config_state, 0); @@ -1037,6 +1146,7 @@ uint8_t tempcheck_state(Event event, uint16_t arg) { #endif +#ifdef USE_BEACON_MODE uint8_t beacon_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { @@ -1061,8 +1171,10 @@ uint8_t beacon_state(Event event, uint16_t arg) { } return EVENT_NOT_HANDLED; } +#endif +#ifdef USE_GOODNIGHT_MODE #define GOODNIGHT_TICKS_PER_STEPDOWN (GOODNIGHT_TIME*TICKS_PER_SECOND*60L/GOODNIGHT_LEVEL) uint8_t goodnight_state(Event event, uint16_t arg) { static uint16_t ticks_since_stepdown = 0; @@ -1080,7 +1192,11 @@ uint8_t goodnight_state(Event event, uint16_t arg) { } // 2 clicks: beacon mode else if (event == EV_2clicks) { + #ifdef USE_BEACON_MODE set_state(beacon_state, 0); + #elif defined(USE_TEMPCHECK_MODE) + set_state(tempcheck_state, 0); + #endif return MISCHIEF_MANAGED; } // tick: step down (maybe) or off (maybe) @@ -1101,6 +1217,7 @@ uint8_t goodnight_state(Event event, uint16_t arg) { } return EVENT_NOT_HANDLED; } +#endif uint8_t lockout_state(Event event, uint16_t arg) { @@ -1438,6 +1555,7 @@ uint8_t config_state_base(Event event, uint16_t arg, return EVENT_HANDLED; } +#ifdef USE_RAMP_CONFIG void ramp_config_save() { // parse values uint8_t val; @@ -1469,6 +1587,7 @@ uint8_t ramp_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, num_config_steps, ramp_config_save); } +#endif // #ifdef USE_RAMP_CONFIG #ifdef USE_THERMAL_REGULATION @@ -1498,6 +1617,7 @@ uint8_t thermal_config_state(Event event, uint16_t arg) { #endif +#ifdef USE_BEACON_MODE void beacon_config_save() { // parse values uint8_t val = config_state_values[0]; @@ -1510,6 +1630,7 @@ uint8_t beacon_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, 1, beacon_config_save); } +#endif uint8_t number_entry_state(Event event, uint16_t arg) { @@ -1689,7 +1810,9 @@ void load_config() { #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_MUGGLE_MODE muggle_mode_active = eeprom[muggle_mode_active_e]; #endif @@ -1723,7 +1846,9 @@ void save_config() { #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_MUGGLE_MODE eeprom[muggle_mode_active_e] = muggle_mode_active; #endif @@ -1926,6 +2051,34 @@ void loop() { } #endif // #ifdef USE_STROBE_STATE + #ifdef USE_BORING_STROBE_STATE + if (state == boring_strobe_state) { + uint8_t st = boring_strobe_type; + + // police strobe + if (st == 0) { + // flash at 16 Hz then 8 Hz, 8 times each + for (uint8_t del=41; del<100; del+=41) { + for (uint8_t f=0; f<8; f++) { + set_level(STROBE_BRIGHTNESS); + nice_delay_ms(del >> 1); + set_level(0); + nice_delay_ms(del); + } + } + } + + // SOS + else if (st == 1) { + nice_delay_ms(1000); + sos_blink(3, 0); + sos_blink(3, 1); + sos_blink(3, 0); + nice_delay_ms(1000); + } + } + #endif // #ifdef USE_BORING_STROBE_STATE + #ifdef USE_BATTCHECK else if (state == battcheck_state) { battcheck(); @@ -1939,12 +2092,14 @@ void loop() { } #endif + #ifdef USE_BEACON_MODE else if (state == beacon_state) { set_level(memorized_level); nice_delay_ms(500); set_level(0); nice_delay_ms(((beacon_seconds) * 1000) - 500); } + #endif #ifdef USE_IDLE_MODE else { -- cgit v1.2.3 From 0554aef811ddc792a1b15c302f65d484bfa70ed9 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 12 Mar 2019 02:13:05 -0600 Subject: merged some (most) of ffui's changes back into anduril --- spaghetti-monster/anduril/anduril.c | 145 +++++++++++++++++++++++++- spaghetti-monster/fireflies-ui/fireflies-ui.c | 35 ++++++- 2 files changed, 171 insertions(+), 9 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 09c7927..5bbf39b 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -2,7 +2,7 @@ * Anduril: Narsil-inspired UI for SpaghettiMonster. * (Anduril is Aragorn's sword, the blade Narsil reforged) * - * Copyright (C) 2017 Selene ToyKeeper + * Copyright (C) 2017-2019 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 @@ -54,11 +54,25 @@ #define USE_LIGHTNING_MODE #define USE_CANDLE_MODE +// enable sunset (goodnight) mode +#define USE_GOODNIGHT_MODE +#define GOODNIGHT_TIME 60 // minutes (approximately) +#define GOODNIGHT_LEVEL 24 // ~11 lm + +// enable beacon mode +#define USE_BEACON_MODE + //Muggle mode for easy UI #define USE_MUGGLE_MODE -#define GOODNIGHT_TIME 60 // minutes (approximately) -#define GOODNIGHT_LEVEL 24 // ~11 lm +// make the ramps configurable by the user +#define USE_RAMP_CONFIG + +// boring strobes nobody really likes, but sometimes flashlight companies want +// (these replace the fun strobe group, +// so don't enable them at the same time as any of the above strobes) +//#define USE_POLICE_STROBE_MODE +//#define USE_SOS_MODE // dual-switch support (second switch is a tail clicky) //#define START_AT_MEMORIZED_LEVEL @@ -116,6 +130,10 @@ #define USE_STROBE_STATE #endif +#if defined(USE_POLICE_STROBE_MODE) || defined(USE_SOS_MODE) +#define USE_BORING_STROBE_STATE +#endif + // auto-detect how many eeprom bytes #define USE_EEPROM typedef enum { @@ -135,7 +153,9 @@ typedef enum { #ifdef USE_BIKE_FLASHER_MODE bike_flasher_brightness_e, #endif + #ifdef USE_BEACON_MODE beacon_seconds_e, + #endif #ifdef USE_MUGGLE_MODE muggle_mode_active_e, #endif @@ -173,11 +193,19 @@ uint8_t config_state_base(Event event, uint16_t arg, uint8_t config_state_values[MAX_CONFIG_VALUES]; // ramping mode and its related config mode uint8_t steady_state(Event event, uint16_t arg); +#ifdef USE_RAMP_CONFIG uint8_t ramp_config_state(Event event, uint16_t arg); +#endif // party and tactical strobes #ifdef USE_STROBE_STATE uint8_t strobe_state(Event event, uint16_t arg); #endif +#ifdef USE_BORING_STROBE_STATE +uint8_t boring_strobe_state(Event event, uint16_t arg); +volatile uint8_t boring_strobe_type = 0; +void sos_blink(uint8_t num, uint8_t dah); +#define NUM_BORING_STROBES 2 +#endif #ifdef USE_BATTCHECK uint8_t battcheck_state(Event event, uint16_t arg); #endif @@ -185,11 +213,15 @@ uint8_t battcheck_state(Event event, uint16_t arg); uint8_t tempcheck_state(Event event, uint16_t arg); uint8_t thermal_config_state(Event event, uint16_t arg); #endif +#ifdef USE_GOODNIGHT_MODE // 1-hour ramp down from low, then automatic off uint8_t goodnight_state(Event event, uint16_t arg); +#endif +#ifdef USE_BEACON_MODE // beacon mode and its related config mode uint8_t beacon_state(Event event, uint16_t arg); uint8_t beacon_config_state(Event event, uint16_t arg); +#endif // soft lockout #define MOON_DURING_LOCKOUT_MODE // if enabled, 2nd lockout click goes to the other ramp's floor level @@ -323,8 +355,10 @@ volatile uint8_t bike_flasher_brightness = MAX_1x7135; uint8_t triangle_wave(uint8_t phase); #endif +#ifdef USE_BEACON_MODE // beacon timing volatile uint8_t beacon_seconds = 2; +#endif uint8_t off_state(Event event, uint16_t arg) { @@ -424,6 +458,11 @@ uint8_t off_state(Event event, uint16_t arg) { set_state(strobe_state, 0); return MISCHIEF_MANAGED; } + #elif defined(USE_BORING_STROBE_STATE) + else if (event == EV_click3_hold) { + set_state(boring_strobe_state, 0); + return MISCHIEF_MANAGED; + } #endif // 4 clicks: soft lockout else if (event == EV_4clicks) { @@ -463,6 +502,13 @@ uint8_t off_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif + #ifdef USE_TENCLICK_THERMAL_CONFIG + // 10 clicks: thermal config mode + else if (event == EV_10clicks) { + push_state(thermal_config_state, 0); + return MISCHIEF_MANAGED; + } + #endif return EVENT_NOT_HANDLED; } @@ -541,11 +587,13 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(memorized_level); return MISCHIEF_MANAGED; } + #ifdef USE_RAMP_CONFIG // 4 clicks: configure this ramp mode else if (event == EV_4clicks) { push_state(ramp_config_state, 0); return MISCHIEF_MANAGED; } + #endif // hold: change brightness (brighter) else if (event == EV_click1_hold) { // ramp slower in discrete mode @@ -998,6 +1046,49 @@ uint8_t strobe_state(Event event, uint16_t arg) { #endif // ifdef USE_STROBE_STATE +#ifdef USE_BORING_STROBE_STATE +uint8_t boring_strobe_state(Event event, uint16_t arg) { + // police strobe and SOS, meh + // 'st' reduces ROM size by avoiding access to a volatile var + // (maybe I should just make it nonvolatile?) + uint8_t st = boring_strobe_type; + + if (event == EV_enter_state) { + return MISCHIEF_MANAGED; + } + // 1 click: off + else if (event == EV_1click) { + // reset to police strobe for next time + boring_strobe_type = 0; + set_state(off_state, 0); + return MISCHIEF_MANAGED; + } + // 2 clicks: rotate through strobe/flasher modes + else if (event == EV_2clicks) { + boring_strobe_type = (st + 1) % NUM_BORING_STROBES; + return MISCHIEF_MANAGED; + } + return EVENT_NOT_HANDLED; +} + +void sos_blink(uint8_t num, uint8_t dah) { + #define DIT_LENGTH 200 + for (; num > 0; num--) { + set_level(memorized_level); + nice_delay_ms(DIT_LENGTH); + if (dah) { // dah is 3X as long as a dit + nice_delay_ms(DIT_LENGTH*2); + } + set_level(0); + // one "off" dit between blinks + nice_delay_ms(DIT_LENGTH); + } + // three "off" dits (or one "dah") between letters + nice_delay_ms(DIT_LENGTH*2); +} +#endif // ifdef USE_BORING_STROBE_STATE + + #ifdef USE_BATTCHECK uint8_t battcheck_state(Event event, uint16_t arg) { // 1 click: off @@ -1037,6 +1128,7 @@ uint8_t tempcheck_state(Event event, uint16_t arg) { #endif +#ifdef USE_BEACON_MODE uint8_t beacon_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { @@ -1061,8 +1153,10 @@ uint8_t beacon_state(Event event, uint16_t arg) { } return EVENT_NOT_HANDLED; } +#endif +#ifdef USE_GOODNIGHT_MODE #define GOODNIGHT_TICKS_PER_STEPDOWN (GOODNIGHT_TIME*TICKS_PER_SECOND*60L/GOODNIGHT_LEVEL) uint8_t goodnight_state(Event event, uint16_t arg) { static uint16_t ticks_since_stepdown = 0; @@ -1101,6 +1195,7 @@ uint8_t goodnight_state(Event event, uint16_t arg) { } return EVENT_NOT_HANDLED; } +#endif uint8_t lockout_state(Event event, uint16_t arg) { @@ -1438,6 +1533,7 @@ uint8_t config_state_base(Event event, uint16_t arg, return EVENT_HANDLED; } +#ifdef USE_RAMP_CONFIG void ramp_config_save() { // parse values uint8_t val; @@ -1469,6 +1565,7 @@ uint8_t ramp_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, num_config_steps, ramp_config_save); } +#endif // #ifdef USE_RAMP_CONFIG #ifdef USE_THERMAL_REGULATION @@ -1495,9 +1592,10 @@ uint8_t thermal_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, 2, thermal_config_save); } -#endif +#endif // #ifdef USE_THERMAL_REGULATION +#ifdef USE_BEACON_MODE void beacon_config_save() { // parse values uint8_t val = config_state_values[0]; @@ -1510,6 +1608,7 @@ uint8_t beacon_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, 1, beacon_config_save); } +#endif // #ifdef USE_BEACON_MODE uint8_t number_entry_state(Event event, uint16_t arg) { @@ -1676,11 +1775,13 @@ uint8_t triangle_wave(uint8_t phase) { void load_config() { if (load_eeprom()) { ramp_style = eeprom[ramp_style_e]; + #ifdef USE_RAMP_CONFIG ramp_smooth_floor = eeprom[ramp_smooth_floor_e]; ramp_smooth_ceil = eeprom[ramp_smooth_ceil_e]; ramp_discrete_floor = eeprom[ramp_discrete_floor_e]; ramp_discrete_ceil = eeprom[ramp_discrete_ceil_e]; ramp_discrete_steps = eeprom[ramp_discrete_steps_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]; @@ -1689,7 +1790,9 @@ void load_config() { #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_MUGGLE_MODE muggle_mode_active = eeprom[muggle_mode_active_e]; #endif @@ -1710,11 +1813,13 @@ void load_config() { void save_config() { eeprom[ramp_style_e] = ramp_style; + #ifdef USE_RAMP_CONFIG eeprom[ramp_smooth_floor_e] = ramp_smooth_floor; eeprom[ramp_smooth_ceil_e] = ramp_smooth_ceil; eeprom[ramp_discrete_floor_e] = ramp_discrete_floor; eeprom[ramp_discrete_ceil_e] = ramp_discrete_ceil; eeprom[ramp_discrete_steps_e] = ramp_discrete_steps; + #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]; @@ -1723,7 +1828,9 @@ void save_config() { #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_MUGGLE_MODE eeprom[muggle_mode_active_e] = muggle_mode_active; #endif @@ -1926,6 +2033,34 @@ void loop() { } #endif // #ifdef USE_STROBE_STATE + #ifdef USE_BORING_STROBE_STATE + if (state == boring_strobe_state) { + uint8_t st = boring_strobe_type; + + // police strobe + if (st == 0) { + // flash at 16 Hz then 8 Hz, 8 times each + for (uint8_t del=41; del<100; del+=41) { + for (uint8_t f=0; f<8; f++) { + set_level(STROBE_BRIGHTNESS); + nice_delay_ms(del >> 1); + set_level(0); + nice_delay_ms(del); + } + } + } + + // SOS + else if (st == 1) { + nice_delay_ms(1000); + sos_blink(3, 0); + sos_blink(3, 1); + sos_blink(3, 0); + nice_delay_ms(1000); + } + } + #endif // #ifdef USE_BORING_STROBE_STATE + #ifdef USE_BATTCHECK else if (state == battcheck_state) { battcheck(); @@ -1939,12 +2074,14 @@ void loop() { } #endif + #ifdef USE_BEACON_MODE else if (state == beacon_state) { set_level(memorized_level); nice_delay_ms(500); set_level(0); nice_delay_ms(((beacon_seconds) * 1000) - 500); } + #endif #ifdef USE_IDLE_MODE else { diff --git a/spaghetti-monster/fireflies-ui/fireflies-ui.c b/spaghetti-monster/fireflies-ui/fireflies-ui.c index 5ad5ad0..ba30605 100644 --- a/spaghetti-monster/fireflies-ui/fireflies-ui.c +++ b/spaghetti-monster/fireflies-ui/fireflies-ui.c @@ -54,11 +54,25 @@ #define USE_LIGHTNING_MODE #define USE_CANDLE_MODE +// enable sunset (goodnight) mode +#define USE_GOODNIGHT_MODE +#define GOODNIGHT_TIME 60 // minutes (approximately) +#define GOODNIGHT_LEVEL 24 // ~11 lm + +// enable beacon mode +#define USE_BEACON_MODE + //Muggle mode for easy UI #define USE_MUGGLE_MODE -#define GOODNIGHT_TIME 60 // minutes (approximately) -#define GOODNIGHT_LEVEL 24 // ~11 lm +// make the ramps configurable by the user +#define USE_RAMP_CONFIG + +// boring strobes nobody really likes, but sometimes flashlight companies want +// (these replace the fun strobe group, +// so don't enable them at the same time as any of the above strobes) +//#define USE_POLICE_STROBE_MODE +//#define USE_SOS_MODE // dual-switch support (second switch is a tail clicky) //#define START_AT_MEMORIZED_LEVEL @@ -67,7 +81,7 @@ #include "tk.h" #include incfile(CONFIGFILE) -// Fireflies-specific configuration +///// Fireflies-specific configuration // disable ramp config #ifdef USE_RAMP_CONFIG #undef USE_RAMP_CONFIG @@ -107,6 +121,11 @@ #define USE_POLICE_STROBE_MODE #define USE_SOS_MODE +// thermal config mode on 10 clicks from off +#define USE_TENCLICK_THERMAL_CONFIG + +///// end Fireflies-specific configuration + // thermal properties, if not defined per-driver #ifndef MIN_THERM_STEPDOWN #define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to @@ -514,11 +533,13 @@ uint8_t off_state(Event event, uint16_t arg) { set_state(tempcheck_state, 0); return MISCHIEF_MANAGED; } + #ifdef USE_TENCLICK_THERMAL_CONFIG // 10 clicks: thermal config mode else if (event == EV_10clicks) { push_state(thermal_config_state, 0); return MISCHIEF_MANAGED; } + #endif return EVENT_NOT_HANDLED; } @@ -1614,7 +1635,7 @@ uint8_t thermal_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, 2, thermal_config_save); } -#endif +#endif // #ifdef USE_THERMAL_REGULATION #ifdef USE_BEACON_MODE @@ -1630,7 +1651,7 @@ uint8_t beacon_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, 1, beacon_config_save); } -#endif +#endif // #ifdef USE_BEACON_MODE uint8_t number_entry_state(Event event, uint16_t arg) { @@ -1797,11 +1818,13 @@ uint8_t triangle_wave(uint8_t phase) { void load_config() { if (load_eeprom()) { ramp_style = eeprom[ramp_style_e]; + #ifdef USE_RAMP_CONFIG ramp_smooth_floor = eeprom[ramp_smooth_floor_e]; ramp_smooth_ceil = eeprom[ramp_smooth_ceil_e]; ramp_discrete_floor = eeprom[ramp_discrete_floor_e]; ramp_discrete_ceil = eeprom[ramp_discrete_ceil_e]; ramp_discrete_steps = eeprom[ramp_discrete_steps_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]; @@ -1833,11 +1856,13 @@ void load_config() { void save_config() { eeprom[ramp_style_e] = ramp_style; + #ifdef USE_RAMP_CONFIG eeprom[ramp_smooth_floor_e] = ramp_smooth_floor; eeprom[ramp_smooth_ceil_e] = ramp_smooth_ceil; eeprom[ramp_discrete_floor_e] = ramp_discrete_floor; eeprom[ramp_discrete_ceil_e] = ramp_discrete_ceil; eeprom[ramp_discrete_steps_e] = ramp_discrete_steps; + #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]; -- cgit v1.2.3 From e326c6e86131afbb76f05f5f0ea565eae88f4dfb Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 12 Mar 2019 03:35:53 -0600 Subject: anduril: refactored pretty much all the blinky code, to put inner loops in their own functions (because it keeps the code cleaner) (also moved candle mode to its own pseudo-state, even though it cost about 24 bytes, because the code for strobe state was really messy with candle mode intertwined) --- spaghetti-monster/anduril/anduril.c | 519 ++++++++++++++++++++---------------- 1 file changed, 282 insertions(+), 237 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 5bbf39b..d25e88d 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -352,6 +352,7 @@ volatile uint8_t bike_flasher_brightness = MAX_1x7135; #endif #ifdef USE_CANDLE_MODE +uint8_t candle_mode_state(Event event, uint16_t arg); uint8_t triangle_wave(uint8_t phase); #endif @@ -838,30 +839,21 @@ uint8_t strobe_state(Event event, uint16_t arg) { // 'st' reduces ROM size by avoiding access to a volatile var // (maybe I should just make it nonvolatile?) strobe_mode_te st = strobe_type; + #ifdef USE_CANDLE_MODE - // FIXME: make candle variance magnitude a compile-time option, - // since 20 is sometimes too much or too little, - // depending on the driver type and ramp shape - //#define MAX_CANDLE_LEVEL (RAMP_SIZE-8-6-4) - #define MAX_CANDLE_LEVEL (RAMP_SIZE/2) - static uint8_t candle_wave1 = 0; - static uint8_t candle_wave2 = 0; - static uint8_t candle_wave3 = 0; - static uint8_t candle_wave2_speed = 0; - static uint8_t candle_wave2_depth = 7; - static uint8_t candle_wave3_depth = 4; - static uint8_t candle_mode_brightness = 24; - static uint8_t candle_mode_timer = 0; - #define TICKS_PER_CANDLE_MINUTE 4096 // about 65 seconds - #define MINUTES_PER_CANDLE_HALFHOUR 27 // ish + // pass all events to candle mode, when it's active + // (the code is in its own pseudo-state to keep things cleaner) + if (st == candle_mode_e) { + candle_mode_state(event, arg); + } #endif - if (event == EV_enter_state) { - #ifdef USE_CANDLE_MODE - candle_mode_timer = 0; // in case any time was left over from earlier - #endif + if (0) {} // placeholder + /* not used any more + else if (event == EV_enter_state) { return MISCHIEF_MANAGED; } + */ // 1 click: off else if (event == EV_1click) { set_state(off_state, 0); @@ -870,10 +862,6 @@ 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; - #ifdef USE_CANDLE_MODE - candle_mode_timer = 0; // in case any time was left over from earlier - #endif - //interrupt_nice_delays(); save_config(); return MISCHIEF_MANAGED; } @@ -898,14 +886,6 @@ uint8_t strobe_state(Event event, uint16_t arg) { // lightning has no adjustments //else if (st == lightning_storm_e) {} - // candle mode brighter - #ifdef USE_CANDLE_MODE - else if (st == candle_mode_e) { - if (candle_mode_brightness < MAX_CANDLE_LEVEL) - candle_mode_brightness ++; - } - #endif - // biking mode brighter #ifdef USE_BIKE_FLASHER_MODE else if (st == bike_flasher_e) { @@ -938,14 +918,6 @@ uint8_t strobe_state(Event event, uint16_t arg) { // lightning has no adjustments //else if (st == lightning_storm_e) {} - // candle mode dimmer - #ifdef USE_CANDLE_MODE - else if (st == candle_mode_e) { - if (candle_mode_brightness > 1) - candle_mode_brightness --; - } - #endif - // biking mode dimmer #ifdef USE_BIKE_FLASHER_MODE else if (st == bike_flasher_e) { @@ -963,87 +935,212 @@ uint8_t strobe_state(Event event, uint16_t arg) { save_config(); return MISCHIEF_MANAGED; } - #if defined(USE_CANDLE_MODE) + #if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) + // clock tick: bump the random seed + else if (event == EV_tick) { + pseudo_rand_seed += arg; + return MISCHIEF_MANAGED; + } + #endif + return EVENT_NOT_HANDLED; +} + +#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]; + // TODO: make tac strobe brightness configurable? + set_level(STROBE_BRIGHTNESS); + if (st == party_strobe_e) { // party strobe + if (del < 42) delay_zero(); + else nice_delay_ms(1); + } else { //tactical strobe + nice_delay_ms(del >> 1); + } + set_level(0); + nice_delay_ms(del); // no return check necessary on final delay +} +#endif + +#ifdef USE_LIGHTNING_MODE +inline void lightning_storm_iter() { + // one iteration of main loop() + int16_t brightness; + uint16_t rand_time; + + // turn the emitter on at a random level, + // for a random amount of time between 1ms and 32ms + //rand_time = 1 << (pseudo_rand() % 7); + rand_time = pseudo_rand() & 63; + brightness = 1 << (pseudo_rand() % 7); // 1, 2, 4, 8, 16, 32, 64 + brightness += 1 << (pseudo_rand() & 0x03); // 2 to 80 now + brightness += pseudo_rand() % brightness; // 2 to 159 now (w/ low bias) + if (brightness > MAX_LEVEL) brightness = MAX_LEVEL; + set_level(brightness); + nice_delay_ms(rand_time); + + // decrease the brightness somewhat more gradually, like lightning + uint8_t stepdown = brightness >> 3; + if (stepdown < 1) stepdown = 1; + while(brightness > 1) { + nice_delay_ms(rand_time); + brightness -= stepdown; + if (brightness < 0) brightness = 0; + set_level(brightness); + /* + if ((brightness < MAX_LEVEL/2) && (! (pseudo_rand() & 15))) { + brightness <<= 1; + set_level(brightness); + } + */ + if (! (pseudo_rand() & 3)) { + nice_delay_ms(rand_time); + set_level(brightness>>1); + } + } + + // turn the emitter off, + // for a random amount of time between 1ms and 8192ms + // (with a low bias) + rand_time = 1 << (pseudo_rand() % 13); + rand_time += pseudo_rand() % rand_time; + set_level(0); + nice_delay_ms(rand_time); // no return check necessary on final delay +} +#endif + +#ifdef USE_BIKE_FLASHER_MODE +inline void bike_flasher_iter() { + // one iteration of main loop() + uint8_t burst = 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); + nice_delay_ms(65); + } + nice_delay_ms(720); // no return check necessary on final delay +} +#endif + +#endif // ifdef USE_STROBE_STATE + +#ifdef USE_CANDLE_MODE +uint8_t candle_mode_state(Event event, uint16_t arg) { + // FIXME: make candle variance magnitude a compile-time option, + // since 20 is sometimes too much or too little, + // depending on the driver type and ramp shape + //#define MAX_CANDLE_LEVEL (RAMP_SIZE-8-6-4) + #define MAX_CANDLE_LEVEL (RAMP_SIZE/2) + static uint8_t candle_wave1 = 0; + static uint8_t candle_wave2 = 0; + static uint8_t candle_wave3 = 0; + static uint8_t candle_wave2_speed = 0; + static uint8_t candle_wave2_depth = 7; + static uint8_t candle_wave3_depth = 4; + static uint8_t candle_mode_brightness = 24; + static uint8_t candle_mode_timer = 0; + #define TICKS_PER_CANDLE_MINUTE 4096 // about 65 seconds + #define MINUTES_PER_CANDLE_HALFHOUR 27 // ish + + if (event == EV_enter_state) { + candle_mode_timer = 0; // in case any time was left over from earlier + return MISCHIEF_MANAGED; + } + // 2 clicks: cancel timer + else if (event == EV_2clicks) { + // parent state just rotated through strobe/flasher modes, + // so cancel timer... in case any time was left over from earlier + candle_mode_timer = 0; + return MISCHIEF_MANAGED; + } + // hold: change brightness (brighter) + else if (event == EV_click1_hold) { + if (candle_mode_brightness < MAX_CANDLE_LEVEL) + candle_mode_brightness ++; + return MISCHIEF_MANAGED; + } + // click, hold: change brightness (dimmer) + else if (event == EV_click2_hold) { + if (candle_mode_brightness > 1) + candle_mode_brightness --; + return MISCHIEF_MANAGED; + } // 3 clicks: add 30m to candle timer else if (event == EV_3clicks) { - // candle mode only - if (st == candle_mode_e) { - if (candle_mode_timer < (255 - MINUTES_PER_CANDLE_HALFHOUR)) { - // add 30m to the timer - candle_mode_timer += MINUTES_PER_CANDLE_HALFHOUR; - // blink to confirm - set_level(actual_level + 32); - delay_4ms(2); - } + if (candle_mode_timer < (255 - MINUTES_PER_CANDLE_HALFHOUR)) { + // add 30m to the timer + candle_mode_timer += MINUTES_PER_CANDLE_HALFHOUR; + // blink to confirm + set_level(actual_level + 32); + delay_4ms(2); } return MISCHIEF_MANAGED; } - #endif - #if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) - // clock tick: bump the random seed, adjust candle brightness + // clock tick: animate candle brightness else if (event == EV_tick) { - pseudo_rand_seed += arg; - - #ifdef USE_CANDLE_MODE - if (st == candle_mode_e) { - // self-timer dims the light during the final minute - uint8_t subtract = 0; - if (candle_mode_timer == 1) { - subtract = ((candle_mode_brightness+20) - * ((arg & (TICKS_PER_CANDLE_MINUTE-1)) >> 4)) - >> 8; - } - // we passed a minute mark, decrease timer if it's running - if ((arg & (TICKS_PER_CANDLE_MINUTE-1)) == (TICKS_PER_CANDLE_MINUTE - 1)) { - if (candle_mode_timer > 0) { - candle_mode_timer --; - //set_level(0); delay_4ms(2); - // if the timer ran out, shut off - if (! candle_mode_timer) { - set_state(off_state, 0); - } + // self-timer dims the light during the final minute + uint8_t subtract = 0; + if (candle_mode_timer == 1) { + subtract = ((candle_mode_brightness+20) + * ((arg & (TICKS_PER_CANDLE_MINUTE-1)) >> 4)) + >> 8; + } + // we passed a minute mark, decrease timer if it's running + if ((arg & (TICKS_PER_CANDLE_MINUTE-1)) == (TICKS_PER_CANDLE_MINUTE - 1)) { + if (candle_mode_timer > 0) { + candle_mode_timer --; + //set_level(0); delay_4ms(2); + // if the timer ran out, shut off + if (! candle_mode_timer) { + set_state(off_state, 0); } } - // 3-oscillator synth for a relatively organic pattern - uint8_t add; - add = ((triangle_wave(candle_wave1) * 8) >> 8) - + ((triangle_wave(candle_wave2) * candle_wave2_depth) >> 8) - + ((triangle_wave(candle_wave3) * candle_wave3_depth) >> 8); - int8_t brightness = candle_mode_brightness + add - subtract; - if (brightness < 0) { brightness = 0; } - set_level(brightness); - - // wave1: slow random LFO - if ((arg & 1) == 0) candle_wave1 += pseudo_rand() & 1; - // wave2: medium-speed erratic LFO - candle_wave2 += candle_wave2_speed; - // wave3: erratic fast wave - candle_wave3 += pseudo_rand() % 37; - // S&H on wave2 frequency to make it more erratic - if ((pseudo_rand() & 0b00111111) == 0) - candle_wave2_speed = pseudo_rand() % 13; - // downward sawtooth on wave2 depth to simulate stabilizing - if ((candle_wave2_depth > 0) && ((pseudo_rand() & 0b00111111) == 0)) - candle_wave2_depth --; - // random sawtooth retrigger - if ((pseudo_rand()) == 0) { - candle_wave2_depth = 7; - //candle_wave3_depth = 5; - candle_wave2 = 0; - } - // downward sawtooth on wave3 depth to simulate stabilizing - if ((candle_wave3_depth > 2) && ((pseudo_rand() & 0b00011111) == 0)) - candle_wave3_depth --; - if ((pseudo_rand() & 0b01111111) == 0) - candle_wave3_depth = 5; } - #endif + // 3-oscillator synth for a relatively organic pattern + uint8_t add; + add = ((triangle_wave(candle_wave1) * 8) >> 8) + + ((triangle_wave(candle_wave2) * candle_wave2_depth) >> 8) + + ((triangle_wave(candle_wave3) * candle_wave3_depth) >> 8); + int8_t brightness = candle_mode_brightness + add - subtract; + if (brightness < 0) { brightness = 0; } + set_level(brightness); + + // wave1: slow random LFO + if ((arg & 1) == 0) candle_wave1 += pseudo_rand() & 1; + // wave2: medium-speed erratic LFO + candle_wave2 += candle_wave2_speed; + // wave3: erratic fast wave + candle_wave3 += pseudo_rand() % 37; + // S&H on wave2 frequency to make it more erratic + if ((pseudo_rand() & 0b00111111) == 0) + candle_wave2_speed = pseudo_rand() % 13; + // downward sawtooth on wave2 depth to simulate stabilizing + if ((candle_wave2_depth > 0) && ((pseudo_rand() & 0b00111111) == 0)) + candle_wave2_depth --; + // random sawtooth retrigger + if ((pseudo_rand()) == 0) { + candle_wave2_depth = 7; + //candle_wave3_depth = 5; + candle_wave2 = 0; + } + // downward sawtooth on wave3 depth to simulate stabilizing + if ((candle_wave3_depth > 2) && ((pseudo_rand() & 0b00011111) == 0)) + candle_wave3_depth --; + if ((pseudo_rand() & 0b01111111) == 0) + candle_wave3_depth = 5; return MISCHIEF_MANAGED; } - #endif return EVENT_NOT_HANDLED; } -#endif // ifdef USE_STROBE_STATE + +uint8_t triangle_wave(uint8_t phase) { + uint8_t result = phase << 1; + if (phase > 127) result = 255 - result; + return result; +} +#endif // #ifdef USE_CANDLE_MODE #ifdef USE_BORING_STROBE_STATE @@ -1071,6 +1168,22 @@ uint8_t boring_strobe_state(Event event, uint16_t arg) { return EVENT_NOT_HANDLED; } +#ifdef USE_POLICE_STROBE_MODE +inline void police_strobe_iter() { + // one iteration of main loop() + // flash at 16 Hz then 8 Hz, 8 times each + for (uint8_t del=41; del<100; del+=41) { + for (uint8_t f=0; f<8; f++) { + set_level(STROBE_BRIGHTNESS); + nice_delay_ms(del >> 1); + set_level(0); + nice_delay_ms(del); + } + } +} +#endif + +#ifdef USE_SOS_MODE void sos_blink(uint8_t num, uint8_t dah) { #define DIT_LENGTH 200 for (; num > 0; num--) { @@ -1086,7 +1199,17 @@ void sos_blink(uint8_t num, uint8_t dah) { // three "off" dits (or one "dah") between letters nice_delay_ms(DIT_LENGTH*2); } -#endif // ifdef USE_BORING_STROBE_STATE + +inline void sos_mode_iter() { + // one iteration of main loop() + nice_delay_ms(1000); + sos_blink(3, 0); // S + sos_blink(3, 1); // O + sos_blink(3, 0); // S + nice_delay_ms(1000); +} +#endif // #ifdef USE_SOS_MODE +#endif // #ifdef USE_BORING_STROBE_STATE #ifdef USE_BATTCHECK @@ -1608,6 +1731,14 @@ uint8_t beacon_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, 1, beacon_config_save); } + +inline void beacon_mode_iter() { + // one iteration of main loop() + set_level(memorized_level); + nice_delay_ms(500); + set_level(0); + nice_delay_ms(((beacon_seconds) * 1000) - 500); +} #endif // #ifdef USE_BEACON_MODE @@ -1763,15 +1894,6 @@ void indicator_blink(uint8_t arg) { #endif -#ifdef USE_CANDLE_MODE -uint8_t triangle_wave(uint8_t phase) { - uint8_t result = phase << 1; - if (phase > 127) result = 255 - result; - return result; -} -#endif - - void load_config() { if (load_eeprom()) { ramp_style = eeprom[ramp_style_e]; @@ -1852,6 +1974,7 @@ void save_config_wl() { } #endif + void low_voltage() { StatePtr state = current_state; @@ -1936,127 +2059,51 @@ void loop() { if (0) {} #ifdef USE_STROBE_STATE - if (state == strobe_state) { + else if (state == strobe_state) { uint8_t st = strobe_type; - if (0) {} // placeholder - - // party / tactial strobe - #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) - #ifdef USE_TACTICAL_STROBE_MODE - else if (st <= tactical_strobe_e) { - #else - else if (st == party_strobe_e) { - #endif - uint8_t del = strobe_delays[st]; - // TODO: make tac strobe brightness configurable? - set_level(STROBE_BRIGHTNESS); - if (st == party_strobe_e) { // party strobe - if (del < 42) delay_zero(); - else nice_delay_ms(1); - } else { //tactical strobe - nice_delay_ms(del >> 1); - } - set_level(0); - nice_delay_ms(del); // no return check necessary on final delay - } - #endif - - // lightning storm - #ifdef USE_LIGHTNING_MODE - else if (st == lightning_storm_e) { - int16_t brightness; - uint16_t rand_time; - - // turn the emitter on at a random level, - // for a random amount of time between 1ms and 32ms - //rand_time = 1 << (pseudo_rand() % 7); - rand_time = pseudo_rand() & 63; - brightness = 1 << (pseudo_rand() % 7); // 1, 2, 4, 8, 16, 32, 64 - brightness += 1 << (pseudo_rand() & 0x03); // 2 to 80 now - brightness += pseudo_rand() % brightness; // 2 to 159 now (w/ low bias) - if (brightness > MAX_LEVEL) brightness = MAX_LEVEL; - set_level(brightness); - nice_delay_ms(rand_time); - - // decrease the brightness somewhat more gradually, like lightning - uint8_t stepdown = brightness >> 3; - if (stepdown < 1) stepdown = 1; - while(brightness > 1) { - nice_delay_ms(rand_time); - brightness -= stepdown; - if (brightness < 0) brightness = 0; - set_level(brightness); - /* - if ((brightness < MAX_LEVEL/2) && (! (pseudo_rand() & 15))) { - brightness <<= 1; - set_level(brightness); - } - */ - if (! (pseudo_rand() & 3)) { - nice_delay_ms(rand_time); - set_level(brightness>>1); - } - } - - // turn the emitter off, - // for a random amount of time between 1ms and 8192ms - // (with a low bias) - rand_time = 1 << (pseudo_rand() % 13); - rand_time += pseudo_rand() % rand_time; - set_level(0); - nice_delay_ms(rand_time); // no return check necessary on final delay - } - #endif + switch(st) { + #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) + #ifdef USE_PARTY_STROBE_MODE + case party_strobe_e: + #endif + #ifdef USE_TACTICAL_STROBE_MODE + case tactical_strobe_e: + #endif + party_tactical_strobe_mode_iter(st); + break; + #endif - // candle mode - #ifdef USE_CANDLE_MODE - // this NOP should get compiled out - else if (st == candle_mode_e) {} - #endif + #ifdef USE_LIGHTNING_MODE + case lightning_storm_e: + lightning_storm_iter(); + break; + #endif - // bike flasher - #ifdef USE_BIKE_FLASHER_MODE - else if (st == bike_flasher_e) { - uint8_t burst = 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); - nice_delay_ms(65); - } - nice_delay_ms(720); // no return check necessary on final delay + #ifdef USE_BIKE_FLASHER_MODE + case bike_flasher_e: + bike_flasher_iter(); + break; + #endif } - #endif } #endif // #ifdef USE_STROBE_STATE #ifdef USE_BORING_STROBE_STATE - if (state == boring_strobe_state) { - uint8_t st = boring_strobe_type; - - // police strobe - if (st == 0) { - // flash at 16 Hz then 8 Hz, 8 times each - for (uint8_t del=41; del<100; del+=41) { - for (uint8_t f=0; f<8; f++) { - set_level(STROBE_BRIGHTNESS); - nice_delay_ms(del >> 1); - set_level(0); - nice_delay_ms(del); - } - } - } + else if (state == boring_strobe_state) { + switch(boring_strobe_type) { + #ifdef USE_POLICE_STROBE_MODE + case 0: // police strobe + police_strobe_iter(); + break; + #endif - // SOS - else if (st == 1) { - nice_delay_ms(1000); - sos_blink(3, 0); - sos_blink(3, 1); - sos_blink(3, 0); - nice_delay_ms(1000); + #ifdef USE_SOS_MODE + default: // SOS + sos_mode_iter(); + break; + #endif } } #endif // #ifdef USE_BORING_STROBE_STATE @@ -2066,23 +2113,21 @@ void loop() { battcheck(); } #endif + + #ifdef USE_BEACON_MODE + else if (state == beacon_state) { + beacon_mode_iter(); + } + #endif + #ifdef USE_THERMAL_REGULATION - // TODO: blink out therm_ceil during thermal_config_state + // TODO: blink out therm_ceil during thermal_config_state? else if (state == tempcheck_state) { blink_num(temperature>>1); nice_delay_ms(1000); } #endif - #ifdef USE_BEACON_MODE - else if (state == beacon_state) { - set_level(memorized_level); - nice_delay_ms(500); - set_level(0); - nice_delay_ms(((beacon_seconds) * 1000) - 500); - } - #endif - #ifdef USE_IDLE_MODE else { // doze until next clock tick -- cgit v1.2.3 From 6cf59ea2a2bee60d81f0445c233bfd4b9e20d732 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 12 Mar 2019 03:41:09 -0600 Subject: fixed build error when only one of the two main strobes was enabled --- spaghetti-monster/anduril/anduril.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index d25e88d..fa4508e 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -951,12 +951,18 @@ inline void party_tactical_strobe_mode_iter(uint8_t st) { uint8_t del = strobe_delays[st]; // TODO: make tac strobe brightness configurable? set_level(STROBE_BRIGHTNESS); - if (st == party_strobe_e) { // party strobe + if (0) {} // placeholde0 + #ifdef USE_PARTY_STROBE_MODE + else if (st == party_strobe_e) { // party strobe if (del < 42) delay_zero(); else nice_delay_ms(1); - } else { //tactical strobe + } + #endif + #ifdef USE_TACTICAL_STROBE_MODE + else { //tactical strobe nice_delay_ms(del >> 1); } + #endif set_level(0); nice_delay_ms(del); // no return check necessary on final delay } -- cgit v1.2.3 From 891aa1c0f10c170e034d08ae1d654d2878f3d762 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 12 Mar 2019 03:45:35 -0600 Subject: merged anduril refactor changes into fireflies-ui --- spaghetti-monster/fireflies-ui/fireflies-ui.c | 525 ++++++++++++++------------ 1 file changed, 288 insertions(+), 237 deletions(-) diff --git a/spaghetti-monster/fireflies-ui/fireflies-ui.c b/spaghetti-monster/fireflies-ui/fireflies-ui.c index ba30605..6402a9d 100644 --- a/spaghetti-monster/fireflies-ui/fireflies-ui.c +++ b/spaghetti-monster/fireflies-ui/fireflies-ui.c @@ -396,6 +396,7 @@ volatile uint8_t bike_flasher_brightness = MAX_1x7135; #endif #ifdef USE_CANDLE_MODE +uint8_t candle_mode_state(Event event, uint16_t arg); uint8_t triangle_wave(uint8_t phase); #endif @@ -869,30 +870,21 @@ uint8_t strobe_state(Event event, uint16_t arg) { // 'st' reduces ROM size by avoiding access to a volatile var // (maybe I should just make it nonvolatile?) strobe_mode_te st = strobe_type; + #ifdef USE_CANDLE_MODE - // FIXME: make candle variance magnitude a compile-time option, - // since 20 is sometimes too much or too little, - // depending on the driver type and ramp shape - //#define MAX_CANDLE_LEVEL (RAMP_SIZE-8-6-4) - #define MAX_CANDLE_LEVEL (RAMP_SIZE/2) - static uint8_t candle_wave1 = 0; - static uint8_t candle_wave2 = 0; - static uint8_t candle_wave3 = 0; - static uint8_t candle_wave2_speed = 0; - static uint8_t candle_wave2_depth = 7; - static uint8_t candle_wave3_depth = 4; - static uint8_t candle_mode_brightness = 24; - static uint8_t candle_mode_timer = 0; - #define TICKS_PER_CANDLE_MINUTE 4096 // about 65 seconds - #define MINUTES_PER_CANDLE_HALFHOUR 27 // ish + // pass all events to candle mode, when it's active + // (the code is in its own pseudo-state to keep things cleaner) + if (st == candle_mode_e) { + candle_mode_state(event, arg); + } #endif - if (event == EV_enter_state) { - #ifdef USE_CANDLE_MODE - candle_mode_timer = 0; // in case any time was left over from earlier - #endif + if (0) {} // placeholder + /* not used any more + else if (event == EV_enter_state) { return MISCHIEF_MANAGED; } + */ // 1 click: off else if (event == EV_1click) { set_state(off_state, 0); @@ -901,10 +893,6 @@ 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; - #ifdef USE_CANDLE_MODE - candle_mode_timer = 0; // in case any time was left over from earlier - #endif - //interrupt_nice_delays(); save_config(); return MISCHIEF_MANAGED; } @@ -929,14 +917,6 @@ uint8_t strobe_state(Event event, uint16_t arg) { // lightning has no adjustments //else if (st == lightning_storm_e) {} - // candle mode brighter - #ifdef USE_CANDLE_MODE - else if (st == candle_mode_e) { - if (candle_mode_brightness < MAX_CANDLE_LEVEL) - candle_mode_brightness ++; - } - #endif - // biking mode brighter #ifdef USE_BIKE_FLASHER_MODE else if (st == bike_flasher_e) { @@ -969,14 +949,6 @@ uint8_t strobe_state(Event event, uint16_t arg) { // lightning has no adjustments //else if (st == lightning_storm_e) {} - // candle mode dimmer - #ifdef USE_CANDLE_MODE - else if (st == candle_mode_e) { - if (candle_mode_brightness > 1) - candle_mode_brightness --; - } - #endif - // biking mode dimmer #ifdef USE_BIKE_FLASHER_MODE else if (st == bike_flasher_e) { @@ -994,87 +966,218 @@ uint8_t strobe_state(Event event, uint16_t arg) { save_config(); return MISCHIEF_MANAGED; } - #if defined(USE_CANDLE_MODE) + #if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) + // clock tick: bump the random seed + else if (event == EV_tick) { + pseudo_rand_seed += arg; + return MISCHIEF_MANAGED; + } + #endif + return EVENT_NOT_HANDLED; +} + +#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]; + // TODO: make tac strobe brightness configurable? + set_level(STROBE_BRIGHTNESS); + if (0) {} // placeholde0 + #ifdef USE_PARTY_STROBE_MODE + else if (st == party_strobe_e) { // party strobe + if (del < 42) delay_zero(); + else nice_delay_ms(1); + } + #endif + #ifdef USE_TACTICAL_STROBE_MODE + else { //tactical strobe + nice_delay_ms(del >> 1); + } + #endif + set_level(0); + nice_delay_ms(del); // no return check necessary on final delay +} +#endif + +#ifdef USE_LIGHTNING_MODE +inline void lightning_storm_iter() { + // one iteration of main loop() + int16_t brightness; + uint16_t rand_time; + + // turn the emitter on at a random level, + // for a random amount of time between 1ms and 32ms + //rand_time = 1 << (pseudo_rand() % 7); + rand_time = pseudo_rand() & 63; + brightness = 1 << (pseudo_rand() % 7); // 1, 2, 4, 8, 16, 32, 64 + brightness += 1 << (pseudo_rand() & 0x03); // 2 to 80 now + brightness += pseudo_rand() % brightness; // 2 to 159 now (w/ low bias) + if (brightness > MAX_LEVEL) brightness = MAX_LEVEL; + set_level(brightness); + nice_delay_ms(rand_time); + + // decrease the brightness somewhat more gradually, like lightning + uint8_t stepdown = brightness >> 3; + if (stepdown < 1) stepdown = 1; + while(brightness > 1) { + nice_delay_ms(rand_time); + brightness -= stepdown; + if (brightness < 0) brightness = 0; + set_level(brightness); + /* + if ((brightness < MAX_LEVEL/2) && (! (pseudo_rand() & 15))) { + brightness <<= 1; + set_level(brightness); + } + */ + if (! (pseudo_rand() & 3)) { + nice_delay_ms(rand_time); + set_level(brightness>>1); + } + } + + // turn the emitter off, + // for a random amount of time between 1ms and 8192ms + // (with a low bias) + rand_time = 1 << (pseudo_rand() % 13); + rand_time += pseudo_rand() % rand_time; + set_level(0); + nice_delay_ms(rand_time); // no return check necessary on final delay +} +#endif + +#ifdef USE_BIKE_FLASHER_MODE +inline void bike_flasher_iter() { + // one iteration of main loop() + uint8_t burst = 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); + nice_delay_ms(65); + } + nice_delay_ms(720); // no return check necessary on final delay +} +#endif + +#endif // ifdef USE_STROBE_STATE + +#ifdef USE_CANDLE_MODE +uint8_t candle_mode_state(Event event, uint16_t arg) { + // FIXME: make candle variance magnitude a compile-time option, + // since 20 is sometimes too much or too little, + // depending on the driver type and ramp shape + //#define MAX_CANDLE_LEVEL (RAMP_SIZE-8-6-4) + #define MAX_CANDLE_LEVEL (RAMP_SIZE/2) + static uint8_t candle_wave1 = 0; + static uint8_t candle_wave2 = 0; + static uint8_t candle_wave3 = 0; + static uint8_t candle_wave2_speed = 0; + static uint8_t candle_wave2_depth = 7; + static uint8_t candle_wave3_depth = 4; + static uint8_t candle_mode_brightness = 24; + static uint8_t candle_mode_timer = 0; + #define TICKS_PER_CANDLE_MINUTE 4096 // about 65 seconds + #define MINUTES_PER_CANDLE_HALFHOUR 27 // ish + + if (event == EV_enter_state) { + candle_mode_timer = 0; // in case any time was left over from earlier + return MISCHIEF_MANAGED; + } + // 2 clicks: cancel timer + else if (event == EV_2clicks) { + // parent state just rotated through strobe/flasher modes, + // so cancel timer... in case any time was left over from earlier + candle_mode_timer = 0; + return MISCHIEF_MANAGED; + } + // hold: change brightness (brighter) + else if (event == EV_click1_hold) { + if (candle_mode_brightness < MAX_CANDLE_LEVEL) + candle_mode_brightness ++; + return MISCHIEF_MANAGED; + } + // click, hold: change brightness (dimmer) + else if (event == EV_click2_hold) { + if (candle_mode_brightness > 1) + candle_mode_brightness --; + return MISCHIEF_MANAGED; + } // 3 clicks: add 30m to candle timer else if (event == EV_3clicks) { - // candle mode only - if (st == candle_mode_e) { - if (candle_mode_timer < (255 - MINUTES_PER_CANDLE_HALFHOUR)) { - // add 30m to the timer - candle_mode_timer += MINUTES_PER_CANDLE_HALFHOUR; - // blink to confirm - set_level(actual_level + 32); - delay_4ms(2); - } + if (candle_mode_timer < (255 - MINUTES_PER_CANDLE_HALFHOUR)) { + // add 30m to the timer + candle_mode_timer += MINUTES_PER_CANDLE_HALFHOUR; + // blink to confirm + set_level(actual_level + 32); + delay_4ms(2); } return MISCHIEF_MANAGED; } - #endif - #if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) - // clock tick: bump the random seed, adjust candle brightness + // clock tick: animate candle brightness else if (event == EV_tick) { - pseudo_rand_seed += arg; - - #ifdef USE_CANDLE_MODE - if (st == candle_mode_e) { - // self-timer dims the light during the final minute - uint8_t subtract = 0; - if (candle_mode_timer == 1) { - subtract = ((candle_mode_brightness+20) - * ((arg & (TICKS_PER_CANDLE_MINUTE-1)) >> 4)) - >> 8; - } - // we passed a minute mark, decrease timer if it's running - if ((arg & (TICKS_PER_CANDLE_MINUTE-1)) == (TICKS_PER_CANDLE_MINUTE - 1)) { - if (candle_mode_timer > 0) { - candle_mode_timer --; - //set_level(0); delay_4ms(2); - // if the timer ran out, shut off - if (! candle_mode_timer) { - set_state(off_state, 0); - } + // self-timer dims the light during the final minute + uint8_t subtract = 0; + if (candle_mode_timer == 1) { + subtract = ((candle_mode_brightness+20) + * ((arg & (TICKS_PER_CANDLE_MINUTE-1)) >> 4)) + >> 8; + } + // we passed a minute mark, decrease timer if it's running + if ((arg & (TICKS_PER_CANDLE_MINUTE-1)) == (TICKS_PER_CANDLE_MINUTE - 1)) { + if (candle_mode_timer > 0) { + candle_mode_timer --; + //set_level(0); delay_4ms(2); + // if the timer ran out, shut off + if (! candle_mode_timer) { + set_state(off_state, 0); } } - // 3-oscillator synth for a relatively organic pattern - uint8_t add; - add = ((triangle_wave(candle_wave1) * 8) >> 8) - + ((triangle_wave(candle_wave2) * candle_wave2_depth) >> 8) - + ((triangle_wave(candle_wave3) * candle_wave3_depth) >> 8); - int8_t brightness = candle_mode_brightness + add - subtract; - if (brightness < 0) { brightness = 0; } - set_level(brightness); - - // wave1: slow random LFO - if ((arg & 1) == 0) candle_wave1 += pseudo_rand() & 1; - // wave2: medium-speed erratic LFO - candle_wave2 += candle_wave2_speed; - // wave3: erratic fast wave - candle_wave3 += pseudo_rand() % 37; - // S&H on wave2 frequency to make it more erratic - if ((pseudo_rand() & 0b00111111) == 0) - candle_wave2_speed = pseudo_rand() % 13; - // downward sawtooth on wave2 depth to simulate stabilizing - if ((candle_wave2_depth > 0) && ((pseudo_rand() & 0b00111111) == 0)) - candle_wave2_depth --; - // random sawtooth retrigger - if ((pseudo_rand()) == 0) { - candle_wave2_depth = 7; - //candle_wave3_depth = 5; - candle_wave2 = 0; - } - // downward sawtooth on wave3 depth to simulate stabilizing - if ((candle_wave3_depth > 2) && ((pseudo_rand() & 0b00011111) == 0)) - candle_wave3_depth --; - if ((pseudo_rand() & 0b01111111) == 0) - candle_wave3_depth = 5; } - #endif + // 3-oscillator synth for a relatively organic pattern + uint8_t add; + add = ((triangle_wave(candle_wave1) * 8) >> 8) + + ((triangle_wave(candle_wave2) * candle_wave2_depth) >> 8) + + ((triangle_wave(candle_wave3) * candle_wave3_depth) >> 8); + int8_t brightness = candle_mode_brightness + add - subtract; + if (brightness < 0) { brightness = 0; } + set_level(brightness); + + // wave1: slow random LFO + if ((arg & 1) == 0) candle_wave1 += pseudo_rand() & 1; + // wave2: medium-speed erratic LFO + candle_wave2 += candle_wave2_speed; + // wave3: erratic fast wave + candle_wave3 += pseudo_rand() % 37; + // S&H on wave2 frequency to make it more erratic + if ((pseudo_rand() & 0b00111111) == 0) + candle_wave2_speed = pseudo_rand() % 13; + // downward sawtooth on wave2 depth to simulate stabilizing + if ((candle_wave2_depth > 0) && ((pseudo_rand() & 0b00111111) == 0)) + candle_wave2_depth --; + // random sawtooth retrigger + if ((pseudo_rand()) == 0) { + candle_wave2_depth = 7; + //candle_wave3_depth = 5; + candle_wave2 = 0; + } + // downward sawtooth on wave3 depth to simulate stabilizing + if ((candle_wave3_depth > 2) && ((pseudo_rand() & 0b00011111) == 0)) + candle_wave3_depth --; + if ((pseudo_rand() & 0b01111111) == 0) + candle_wave3_depth = 5; return MISCHIEF_MANAGED; } - #endif return EVENT_NOT_HANDLED; } -#endif // ifdef USE_STROBE_STATE + +uint8_t triangle_wave(uint8_t phase) { + uint8_t result = phase << 1; + if (phase > 127) result = 255 - result; + return result; +} +#endif // #ifdef USE_CANDLE_MODE #ifdef USE_BORING_STROBE_STATE @@ -1102,6 +1205,22 @@ uint8_t boring_strobe_state(Event event, uint16_t arg) { return EVENT_NOT_HANDLED; } +#ifdef USE_POLICE_STROBE_MODE +inline void police_strobe_iter() { + // one iteration of main loop() + // flash at 16 Hz then 8 Hz, 8 times each + for (uint8_t del=41; del<100; del+=41) { + for (uint8_t f=0; f<8; f++) { + set_level(STROBE_BRIGHTNESS); + nice_delay_ms(del >> 1); + set_level(0); + nice_delay_ms(del); + } + } +} +#endif + +#ifdef USE_SOS_MODE void sos_blink(uint8_t num, uint8_t dah) { #define DIT_LENGTH 200 for (; num > 0; num--) { @@ -1117,7 +1236,17 @@ void sos_blink(uint8_t num, uint8_t dah) { // three "off" dits (or one "dah") between letters nice_delay_ms(DIT_LENGTH*2); } -#endif // ifdef USE_BORING_STROBE_STATE + +inline void sos_mode_iter() { + // one iteration of main loop() + nice_delay_ms(1000); + sos_blink(3, 0); // S + sos_blink(3, 1); // O + sos_blink(3, 0); // S + nice_delay_ms(1000); +} +#endif // #ifdef USE_SOS_MODE +#endif // #ifdef USE_BORING_STROBE_STATE #ifdef USE_BATTCHECK @@ -1651,6 +1780,14 @@ uint8_t beacon_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, 1, beacon_config_save); } + +inline void beacon_mode_iter() { + // one iteration of main loop() + set_level(memorized_level); + nice_delay_ms(500); + set_level(0); + nice_delay_ms(((beacon_seconds) * 1000) - 500); +} #endif // #ifdef USE_BEACON_MODE @@ -1806,15 +1943,6 @@ void indicator_blink(uint8_t arg) { #endif -#ifdef USE_CANDLE_MODE -uint8_t triangle_wave(uint8_t phase) { - uint8_t result = phase << 1; - if (phase > 127) result = 255 - result; - return result; -} -#endif - - void load_config() { if (load_eeprom()) { ramp_style = eeprom[ramp_style_e]; @@ -1895,6 +2023,7 @@ void save_config_wl() { } #endif + void low_voltage() { StatePtr state = current_state; @@ -1979,127 +2108,51 @@ void loop() { if (0) {} #ifdef USE_STROBE_STATE - if (state == strobe_state) { + else if (state == strobe_state) { uint8_t st = strobe_type; - if (0) {} // placeholder - - // party / tactial strobe - #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) - #ifdef USE_TACTICAL_STROBE_MODE - else if (st <= tactical_strobe_e) { - #else - else if (st == party_strobe_e) { - #endif - uint8_t del = strobe_delays[st]; - // TODO: make tac strobe brightness configurable? - set_level(STROBE_BRIGHTNESS); - if (st == party_strobe_e) { // party strobe - if (del < 42) delay_zero(); - else nice_delay_ms(1); - } else { //tactical strobe - nice_delay_ms(del >> 1); - } - set_level(0); - nice_delay_ms(del); // no return check necessary on final delay - } - #endif - - // lightning storm - #ifdef USE_LIGHTNING_MODE - else if (st == lightning_storm_e) { - int16_t brightness; - uint16_t rand_time; - - // turn the emitter on at a random level, - // for a random amount of time between 1ms and 32ms - //rand_time = 1 << (pseudo_rand() % 7); - rand_time = pseudo_rand() & 63; - brightness = 1 << (pseudo_rand() % 7); // 1, 2, 4, 8, 16, 32, 64 - brightness += 1 << (pseudo_rand() & 0x03); // 2 to 80 now - brightness += pseudo_rand() % brightness; // 2 to 159 now (w/ low bias) - if (brightness > MAX_LEVEL) brightness = MAX_LEVEL; - set_level(brightness); - nice_delay_ms(rand_time); - - // decrease the brightness somewhat more gradually, like lightning - uint8_t stepdown = brightness >> 3; - if (stepdown < 1) stepdown = 1; - while(brightness > 1) { - nice_delay_ms(rand_time); - brightness -= stepdown; - if (brightness < 0) brightness = 0; - set_level(brightness); - /* - if ((brightness < MAX_LEVEL/2) && (! (pseudo_rand() & 15))) { - brightness <<= 1; - set_level(brightness); - } - */ - if (! (pseudo_rand() & 3)) { - nice_delay_ms(rand_time); - set_level(brightness>>1); - } - } - - // turn the emitter off, - // for a random amount of time between 1ms and 8192ms - // (with a low bias) - rand_time = 1 << (pseudo_rand() % 13); - rand_time += pseudo_rand() % rand_time; - set_level(0); - nice_delay_ms(rand_time); // no return check necessary on final delay - } - #endif + switch(st) { + #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) + #ifdef USE_PARTY_STROBE_MODE + case party_strobe_e: + #endif + #ifdef USE_TACTICAL_STROBE_MODE + case tactical_strobe_e: + #endif + party_tactical_strobe_mode_iter(st); + break; + #endif - // candle mode - #ifdef USE_CANDLE_MODE - // this NOP should get compiled out - else if (st == candle_mode_e) {} - #endif + #ifdef USE_LIGHTNING_MODE + case lightning_storm_e: + lightning_storm_iter(); + break; + #endif - // bike flasher - #ifdef USE_BIKE_FLASHER_MODE - else if (st == bike_flasher_e) { - uint8_t burst = 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); - nice_delay_ms(65); - } - nice_delay_ms(720); // no return check necessary on final delay + #ifdef USE_BIKE_FLASHER_MODE + case bike_flasher_e: + bike_flasher_iter(); + break; + #endif } - #endif } #endif // #ifdef USE_STROBE_STATE #ifdef USE_BORING_STROBE_STATE - if (state == boring_strobe_state) { - uint8_t st = boring_strobe_type; - - // police strobe - if (st == 0) { - // flash at 16 Hz then 8 Hz, 8 times each - for (uint8_t del=41; del<100; del+=41) { - for (uint8_t f=0; f<8; f++) { - set_level(STROBE_BRIGHTNESS); - nice_delay_ms(del >> 1); - set_level(0); - nice_delay_ms(del); - } - } - } + else if (state == boring_strobe_state) { + switch(boring_strobe_type) { + #ifdef USE_POLICE_STROBE_MODE + case 0: // police strobe + police_strobe_iter(); + break; + #endif - // SOS - else if (st == 1) { - nice_delay_ms(1000); - sos_blink(3, 0); - sos_blink(3, 1); - sos_blink(3, 0); - nice_delay_ms(1000); + #ifdef USE_SOS_MODE + default: // SOS + sos_mode_iter(); + break; + #endif } } #endif // #ifdef USE_BORING_STROBE_STATE @@ -2109,23 +2162,21 @@ void loop() { battcheck(); } #endif + + #ifdef USE_BEACON_MODE + else if (state == beacon_state) { + beacon_mode_iter(); + } + #endif + #ifdef USE_THERMAL_REGULATION - // TODO: blink out therm_ceil during thermal_config_state + // TODO: blink out therm_ceil during thermal_config_state? else if (state == tempcheck_state) { blink_num(temperature>>1); nice_delay_ms(1000); } #endif - #ifdef USE_BEACON_MODE - else if (state == beacon_state) { - set_level(memorized_level); - nice_delay_ms(500); - set_level(0); - nice_delay_ms(((beacon_seconds) * 1000) - 500); - } - #endif - #ifdef USE_IDLE_MODE else { // doze until next clock tick -- cgit v1.2.3 From 8362deff89f567de28ee2dd961a2805994f75c61 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 12 Mar 2019 04:05:49 -0600 Subject: merged anduril updates into rampingios --- spaghetti-monster/anduril/anduril.c | 2 +- spaghetti-monster/fireflies-ui/fireflies-ui.c | 2 +- spaghetti-monster/rampingios/rampingiosv3.c | 85 +++++++++++++++++++++++---- 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index fa4508e..30a0780 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -1282,7 +1282,7 @@ uint8_t beacon_state(Event event, uint16_t arg) { } return EVENT_NOT_HANDLED; } -#endif +#endif // #ifdef USE_BEACON_MODE #ifdef USE_GOODNIGHT_MODE diff --git a/spaghetti-monster/fireflies-ui/fireflies-ui.c b/spaghetti-monster/fireflies-ui/fireflies-ui.c index 6402a9d..fa0b160 100644 --- a/spaghetti-monster/fireflies-ui/fireflies-ui.c +++ b/spaghetti-monster/fireflies-ui/fireflies-ui.c @@ -1321,7 +1321,7 @@ uint8_t beacon_state(Event event, uint16_t arg) { } return EVENT_NOT_HANDLED; } -#endif +#endif // #ifdef USE_BEACON_MODE #ifdef USE_GOODNIGHT_MODE diff --git a/spaghetti-monster/rampingios/rampingiosv3.c b/spaghetti-monster/rampingios/rampingiosv3.c index 399bcf0..c6886e7 100644 --- a/spaghetti-monster/rampingios/rampingiosv3.c +++ b/spaghetti-monster/rampingios/rampingiosv3.c @@ -1,7 +1,7 @@ /* * RampingIOS V3: FSM-based version of RampingIOS V2 UI, with upgrades. * - * Copyright (C) 2018 Selene ToyKeeper + * Copyright (C) 2018-2019 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 @@ -26,6 +26,7 @@ // parameters for this defined below or per-driver #define USE_THERMAL_REGULATION #define DEFAULT_THERM_CEIL 45 // try not to get hotter than this +#define USE_TENCLICK_THERMAL_CONFIG // ten clicks from off -> thermal config mode // short blip when crossing from "click" to "hold" from off // (helps the user hit moon mode exactly, instead of holding too long @@ -46,6 +47,12 @@ //#define BATTCHECK_8bars // FIXME: breaks build //#define BATTCHECK_4bars // FIXME: breaks build +// enable beacon mode +#define USE_BEACON_MODE + +// make the ramps configurable by the user +#define USE_RAMP_CONFIG + /***** specific settings for known driver types *****/ #include "tk.h" #include incfile(CONFIGFILE) @@ -109,7 +116,9 @@ uint8_t config_state_base(Event event, uint16_t arg, uint8_t config_state_values[MAX_CONFIG_VALUES]; // ramping mode and its related config mode uint8_t steady_state(Event event, uint16_t arg); +#ifdef USE_RAMP_CONFIG uint8_t ramp_config_state(Event event, uint16_t arg); +#endif #ifdef USE_BATTCHECK uint8_t battcheck_state(Event event, uint16_t arg); #endif @@ -117,11 +126,15 @@ uint8_t battcheck_state(Event event, uint16_t arg); uint8_t tempcheck_state(Event event, uint16_t arg); uint8_t thermal_config_state(Event event, uint16_t arg); #endif +#ifdef USE_BEACON_MODE // beacon mode and its related config mode uint8_t beacon_state(Event event, uint16_t arg); uint8_t beacon_config_state(Event event, uint16_t arg); +#endif // soft lockout #define MOON_DURING_LOCKOUT_MODE +// if enabled, 2nd lockout click goes to the other ramp's floor level +//#define LOCKOUT_MOON_FANCY uint8_t lockout_state(Event event, uint16_t arg); // momentary / signalling mode uint8_t momentary_state(Event event, uint16_t arg); @@ -201,8 +214,10 @@ uint8_t nearest_level(int16_t target); uint8_t target_level = 0; #endif +#ifdef USE_BEACON_MODE // beacon timing volatile uint8_t beacon_seconds = 2; +#endif uint8_t off_state(Event event, uint16_t arg) { @@ -321,11 +336,13 @@ uint8_t off_state(Event event, uint16_t arg) { set_state(beacon_state, 0); return MISCHIEF_MANAGED; } + #ifdef USE_TENCLICK_THERMAL_CONFIG // 10 clicks: thermal config mode else if (event == EV_10clicks) { push_state(thermal_config_state, 0); return MISCHIEF_MANAGED; } + #endif return EVENT_NOT_HANDLED; } @@ -401,11 +418,13 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(memorized_level); return MISCHIEF_MANAGED; } + #ifdef USE_RAMP_CONFIG // 4 clicks: configure this ramp mode else if (event == EV_4clicks) { push_state(ramp_config_state, 0); return MISCHIEF_MANAGED; } + #endif // hold: change brightness (brighter) else if (event == EV_click1_hold) { // ramp slower in discrete mode @@ -669,6 +688,7 @@ uint8_t tempcheck_state(Event event, uint16_t arg) { #endif +#ifdef USE_BEACON_MODE uint8_t beacon_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { @@ -684,6 +704,7 @@ uint8_t beacon_state(Event event, uint16_t arg) { } return EVENT_NOT_HANDLED; } +#endif // #ifdef USE_BEACON_MODE uint8_t lockout_state(Event event, uint16_t arg) { @@ -696,6 +717,13 @@ uint8_t lockout_state(Event event, uint16_t arg) { uint8_t lvl = ramp_smooth_floor; if (ramp_discrete_floor < lvl) lvl = ramp_discrete_floor; set_level(lvl); + #elif defined(LOCKOUT_MOON_FANCY) + uint8_t levels[] = { ramp_smooth_floor, ramp_discrete_floor }; + if ((event & 0x0f) == 2) { + set_level(levels[ramp_style^1]); + } else { + set_level(levels[ramp_style]); + } #else // Use moon from current ramp set_level(nearest_level(1)); @@ -858,6 +886,7 @@ uint8_t config_state_base(Event event, uint16_t arg, return EVENT_HANDLED; } +#ifdef USE_RAMP_CONFIG void ramp_config_save() { // parse values uint8_t val; @@ -889,6 +918,7 @@ uint8_t ramp_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, num_config_steps, ramp_config_save); } +#endif // #ifdef USE_RAMP_CONFIG #ifdef USE_THERMAL_REGULATION @@ -915,9 +945,10 @@ uint8_t thermal_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, 2, thermal_config_save); } -#endif +#endif // #ifdef USE_THERMAL_REGULATION +#ifdef USE_BEACON_MODE void beacon_config_save() { // parse values uint8_t val = config_state_values[0]; @@ -931,6 +962,15 @@ uint8_t beacon_config_state(Event event, uint16_t arg) { 1, beacon_config_save); } +inline void beacon_mode_iter() { + // one iteration of main loop() + set_level(memorized_level); + nice_delay_ms(500); + set_level(0); + nice_delay_ms(((beacon_seconds) * 1000) - 500); +} +#endif // #ifdef USE_BEACON_MODE + uint8_t number_entry_state(Event event, uint16_t arg) { static uint8_t value; @@ -1063,12 +1103,23 @@ void blink_confirm(uint8_t num) { #if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) // beacon-like mode for the indicator LED void indicator_blink(uint8_t arg) { + #ifdef USE_FANCIER_BLINKING_INDICATOR + + // fancy blink, set off/low/high levels here: + uint8_t seq[] = {0, 1, 2, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0}; + indicator_led(seq[arg & 15]); + + #else // basic blink, 1/8th duty cycle + if (! (arg & 7)) { indicator_led(2); } else { indicator_led(0); } + + #endif } #endif @@ -1076,12 +1127,16 @@ void indicator_blink(uint8_t arg) { void load_config() { if (load_eeprom()) { ramp_style = eeprom[0]; + #ifdef USE_RAMP_CONFIG ramp_smooth_floor = eeprom[1]; ramp_smooth_ceil = eeprom[2]; ramp_discrete_floor = eeprom[3]; ramp_discrete_ceil = eeprom[4]; ramp_discrete_steps = eeprom[5]; + #endif + #ifdef USE_BEACON_MODE beacon_seconds = eeprom[6]; + #endif #ifdef USE_THERMAL_REGULATION therm_ceil = eeprom[EEPROM_BYTES_BASE]; therm_cal_offset = eeprom[EEPROM_BYTES_BASE+1]; @@ -1094,12 +1149,16 @@ void load_config() { void save_config() { eeprom[0] = ramp_style; + #ifdef USE_RAMP_CONFIG eeprom[1] = ramp_smooth_floor; eeprom[2] = ramp_smooth_ceil; eeprom[3] = ramp_discrete_floor; eeprom[4] = ramp_discrete_ceil; eeprom[5] = ramp_discrete_steps; + #endif + #ifdef USE_BEACON_MODE eeprom[6] = beacon_seconds; + #endif #ifdef USE_THERMAL_REGULATION eeprom[EEPROM_BYTES_BASE ] = therm_ceil; eeprom[EEPROM_BYTES_BASE+1] = therm_cal_offset; @@ -1114,8 +1173,12 @@ void save_config() { void low_voltage() { StatePtr state = current_state; + // TODO: turn off aux LED(s) when power is really low + + if (0) {} // placeholder + // in normal mode, step down or turn off - if (state == steady_state) { + else if (state == steady_state) { if (actual_level > 1) { uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); set_level(lvl); @@ -1161,21 +1224,21 @@ void loop() { battcheck(); } #endif + + #ifdef USE_BEACON_MODE + else if (state == beacon_state) { + beacon_mode_iter(); + } + #endif + #ifdef USE_THERMAL_REGULATION - // TODO: blink out therm_ceil during thermal_config_state + // TODO: blink out therm_ceil during thermal_config_state? else if (state == tempcheck_state) { blink_num(temperature>>1); nice_delay_ms(1000); } #endif - else if (state == beacon_state) { - set_level(memorized_level); - nice_delay_ms(500); - set_level(0); - nice_delay_ms(((beacon_seconds) * 1000) - 500); - } - #ifdef USE_IDLE_MODE else { // doze until next clock tick -- cgit v1.2.3 From ef752306f1766973f234be31c8d41cb586908f23 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 12 Mar 2019 04:38:40 -0600 Subject: don't use eeprom for ramp config if ramp config isn't enabled --- spaghetti-monster/anduril/anduril.c | 2 ++ spaghetti-monster/fireflies-ui/fireflies-ui.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 30a0780..f92b8f9 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -138,11 +138,13 @@ #define USE_EEPROM typedef enum { ramp_style_e, + #ifdef USE_RAMP_CONFIG ramp_smooth_floor_e, ramp_smooth_ceil_e, ramp_discrete_floor_e, ramp_discrete_ceil_e, ramp_discrete_steps_e, + #endif #ifdef USE_STROBE_STATE strobe_type_e, #endif diff --git a/spaghetti-monster/fireflies-ui/fireflies-ui.c b/spaghetti-monster/fireflies-ui/fireflies-ui.c index fa0b160..0fc2a1d 100644 --- a/spaghetti-monster/fireflies-ui/fireflies-ui.c +++ b/spaghetti-monster/fireflies-ui/fireflies-ui.c @@ -182,11 +182,13 @@ #define USE_EEPROM typedef enum { ramp_style_e, + #ifdef USE_RAMP_CONFIG ramp_smooth_floor_e, ramp_smooth_ceil_e, ramp_discrete_floor_e, ramp_discrete_ceil_e, ramp_discrete_steps_e, + #endif #ifdef USE_STROBE_STATE strobe_type_e, #endif -- cgit v1.2.3 From 4e15dced6d2274dcb0c6b952eb4d22bf51af422e Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 12 Mar 2019 04:39:42 -0600 Subject: configured Fireflies-EDC-Thrower discrete ramp better, updated meta info --- spaghetti-monster/fireflies-ui/cfg-ff-edc-thrower.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/fireflies-ui/cfg-ff-edc-thrower.h b/spaghetti-monster/fireflies-ui/cfg-ff-edc-thrower.h index 752afe2..31be0ef 100644 --- a/spaghetti-monster/fireflies-ui/cfg-ff-edc-thrower.h +++ b/spaghetti-monster/fireflies-ui/cfg-ff-edc-thrower.h @@ -8,9 +8,9 @@ #undef RAMP_SMOOTH_CEIL #define RAMP_SMOOTH_CEIL 130 -// 10, 28, 46, 65, 83, 101, 120 (83 is highest regulated) +// 36, 83, 130 (83 is highest regulated) #undef RAMP_DISCRETE_FLOOR -#define RAMP_DISCRETE_FLOOR 20 +#define RAMP_DISCRETE_FLOOR 36 #undef RAMP_DISCRETE_CEIL #define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL #undef RAMP_DISCRETE_STEPS -- cgit v1.2.3 From 7599d9827a94f199c170298b97b482faaf19520e Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 18 Mar 2019 03:00:56 -0600 Subject: added Emisar D18 config (not final) --- hwdef-Emisar_D18.h | 51 ++++++++++++++++++++++++++++++ spaghetti-monster/anduril/cfg-emisar-d18.h | 38 ++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 hwdef-Emisar_D18.h create mode 100644 spaghetti-monster/anduril/cfg-emisar-d18.h diff --git a/hwdef-Emisar_D18.h b/hwdef-Emisar_D18.h new file mode 100644 index 0000000..638dadb --- /dev/null +++ b/hwdef-Emisar_D18.h @@ -0,0 +1,51 @@ +#ifndef HWDEF_EMISAR_D18_H +#define HWDEF_EMISAR_D18_H + +/* Emisar D18 (FET+13+1) driver layout + * ---- + * Reset -|1 8|- VCC + * eswitch -|2 7|- aux LED? + * FET -|3 6|- 13x7135 + * GND -|4 5|- 1x7135 + * ---- + */ + +#define PWM_CHANNELS 3 + +#ifndef SWITCH_PIN +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt +#endif + +#ifndef PWM1_PIN +#define PWM1_PIN PB0 // pin 5, 1x7135 PWM +#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 +#endif +#ifndef PWM2_PIN +#define PWM2_PIN PB1 // pin 6, 7x7135 PWM +#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 +#endif +#ifndef PWM3_PIN +#define PWM3_PIN PB4 // pin 3, FET PWM +#define PWM3_LVL OCR1B // OCR1B is the output compare register for PB4 +#endif + +#ifndef AUXLED_PIN +#define AUXLED_PIN PB2 // pin 7 +#endif +#define ADC_PRSCL 0x06 // clk/64 + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V +#endif + +//#define TEMP_DIDR ADC4D +#define TEMP_CHANNEL 0b00001111 + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + +#define LAYOUT_DEFINED + +#endif diff --git a/spaghetti-monster/anduril/cfg-emisar-d18.h b/spaghetti-monster/anduril/cfg-emisar-d18.h new file mode 100644 index 0000000..5171dba --- /dev/null +++ b/spaghetti-monster/anduril/cfg-emisar-d18.h @@ -0,0 +1,38 @@ +// Emisar FET+13+1 config options for Anduril +#include "hwdef-Emisar_D18.h" + +// front-facing aux LEDs +#define USE_INDICATOR_LED +//#define USE_INDICATOR_LED_WHILE_RAMPING +// enable blinking indicator LED while off +#define TICK_DURING_STANDBY +#define STANDBY_TICK_SPEED 3 // every 0.128 s +#define USE_FANCIER_BLINKING_INDICATOR +// off mode: low (1) +// lockout: blinking (3) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) + +// Emisar wanted a shortcut to this +#define USE_TENCLICK_THERMAL_CONFIG + + +// FW3A 1x7135 ramp: +// ../../bin/level_calc.py cube 1 65 7135 1 0.8 150 +// ... mixed with this: +// ../../../bin/level_calc.py ninth 3 150 7135 1 2.5 150 7135 1 1 1600 FET 1 10 5265 +#define RAMP_LENGTH 150 +#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,5,6,8,9,11,13,14,16,18,20,22,25,27,29,32,34,37,40,43,46,49,53,56,60,63,67,71,76,80,85,89,94,100,105,110,116,122,128,135,142,148,156,163,171,179,187,196,205,214,224,234,244,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,10,16,21,27,33,39,46,52,59,66,74,81,89,97,105,114,123,132,142,151,162,172,183,194,205,217,229,242,255 +#define MAX_1x7135 65 +#define MAX_Nx7135 120 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 5 + +// start at ~1500 lm, not ~150 lm +#define DEFAULT_LEVEL MAX_Nx7135 + +// stop panicking at about 4.9A or ~1750 lm +#define THERM_FASTER_LEVEL MAX_Nx7135 +// optional, makes initial turbo step-down faster so first peak isn't as hot +#define THERM_HARD_TURBO_DROP -- cgit v1.2.3 From de0c7eadd70220d29ab6a332d0c47b80c91985c8 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 18 Mar 2019 04:06:37 -0600 Subject: made mid-ramp blinks more configurable per build target (allows for 1 or 2 mid-ramp blinks, at arbitrary levels, but it defaults to the old behavior at power channel boundaries) also merged anduril updates into rampingios --- spaghetti-monster/anduril/anduril.c | 39 +++++++++++++++++------- spaghetti-monster/anduril/cfg-blf-gt.h | 2 +- spaghetti-monster/anduril/cfg-ff-pl47.h | 2 +- spaghetti-monster/anduril/cfg-ff-rot66.h | 2 +- spaghetti-monster/anduril/cfg-sofirn-sp36.h | 4 +-- spaghetti-monster/rampingios/rampingiosv3.c | 46 +++++++++++++++++++++-------- 6 files changed, 66 insertions(+), 29 deletions(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index a9ae959..93f8c16 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -33,7 +33,7 @@ // or too short) #define MOON_TIMING_HINT // short blips while ramping -#define BLINK_AT_CHANNEL_BOUNDARIES +#define BLINK_AT_RAMP_MIDDLE //#define BLINK_AT_RAMP_FLOOR #define BLINK_AT_RAMP_CEILING //#define BLINK_AT_STEPS // whenever a discrete ramp mode is passed in smooth mode @@ -275,6 +275,23 @@ void save_config_wl(); #define RAMP_DISCRETE_STEPS 7 #endif +// mile marker(s) partway up the ramp +// default: blink only at border between regulated and FET +#ifdef BLINK_AT_RAMP_MIDDLE + #if PWM_CHANNELS >= 3 + #ifndef BLINK_AT_RAMP_MIDDLE_1 + #define BLINK_AT_RAMP_MIDDLE_1 MAX_Nx7135 + #ifndef BLINK_AT_RAMP_MIDDLE_2 + #define BLINK_AT_RAMP_MIDDLE_2 MAX_1x7135 + #endif + #endif + #else + #ifndef BLINK_AT_RAMP_MIDDLE_1 + #define BLINK_AT_RAMP_MIDDLE_1 MAX_1x7135 + #endif + #endif +#endif + // brightness control #ifndef DEFAULT_LEVEL #define DEFAULT_LEVEL MAX_1x7135 @@ -619,15 +636,15 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_THERMAL_REGULATION target_level = memorized_level; #endif - #if defined(BLINK_AT_RAMP_CEILING) || defined(BLINK_AT_CHANNEL_BOUNDARIES) + #if defined(BLINK_AT_RAMP_CEILING) || defined(BLINK_AT_RAMP_MIDDLE) // only blink once for each threshold if ((memorized_level != actual_level) && ( 0 // for easier syntax below - #ifdef BLINK_AT_CHANNEL_BOUNDARIES - || (memorized_level == MAX_1x7135) - #if PWM_CHANNELS >= 3 - || (memorized_level == MAX_Nx7135) + #ifdef BLINK_AT_RAMP_MIDDLE_1 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_1) #endif + #ifdef BLINK_AT_RAMP_MIDDLE_2 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_2) #endif #ifdef BLINK_AT_RAMP_CEILING || (memorized_level == mode_max) @@ -684,15 +701,15 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_THERMAL_REGULATION target_level = memorized_level; #endif - #if defined(BLINK_AT_RAMP_FLOOR) || defined(BLINK_AT_CHANNEL_BOUNDARIES) + #if defined(BLINK_AT_RAMP_FLOOR) || defined(BLINK_AT_RAMP_MIDDLE) // only blink once for each threshold if ((memorized_level != actual_level) && ( 0 // for easier syntax below - #ifdef BLINK_AT_CHANNEL_BOUNDARIES - || (memorized_level == MAX_1x7135) - #if PWM_CHANNELS >= 3 - || (memorized_level == MAX_Nx7135) + #ifdef BLINK_AT_RAMP_MIDDLE_1 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_1) #endif + #ifdef BLINK_AT_RAMP_MIDDLE_2 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_2) #endif #ifdef BLINK_AT_RAMP_FLOOR || (memorized_level == mode_min) diff --git a/spaghetti-monster/anduril/cfg-blf-gt.h b/spaghetti-monster/anduril/cfg-blf-gt.h index b8f4d6d..6a74bbc 100644 --- a/spaghetti-monster/anduril/cfg-blf-gt.h +++ b/spaghetti-monster/anduril/cfg-blf-gt.h @@ -9,8 +9,8 @@ #define TICK_DURING_STANDBY // don't blink during ramp, it's irrelevant and annoying on this light -#undef BLINK_AT_CHANNEL_BOUNDARIES #undef BLINK_AT_RAMP_CEILING +#undef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_FLOOR //#undef USE_SET_LEVEL_GRADUALLY diff --git a/spaghetti-monster/anduril/cfg-ff-pl47.h b/spaghetti-monster/anduril/cfg-ff-pl47.h index 8e21013..f9c8974 100644 --- a/spaghetti-monster/anduril/cfg-ff-pl47.h +++ b/spaghetti-monster/anduril/cfg-ff-pl47.h @@ -65,6 +65,6 @@ #define THERM_HARD_TURBO_DROP // don't do this -#undef BLINK_AT_CHANNEL_BOUNDARIES +#undef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_CEILING diff --git a/spaghetti-monster/anduril/cfg-ff-rot66.h b/spaghetti-monster/anduril/cfg-ff-rot66.h index 78d7f66..6073ce0 100644 --- a/spaghetti-monster/anduril/cfg-ff-rot66.h +++ b/spaghetti-monster/anduril/cfg-ff-rot66.h @@ -42,6 +42,6 @@ #define THERM_HARD_TURBO_DROP // don't do this -#undef BLINK_AT_CHANNEL_BOUNDARIES +#undef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_CEILING diff --git a/spaghetti-monster/anduril/cfg-sofirn-sp36.h b/spaghetti-monster/anduril/cfg-sofirn-sp36.h index 1150a62..494a263 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-sp36.h +++ b/spaghetti-monster/anduril/cfg-sofirn-sp36.h @@ -16,8 +16,8 @@ // don't blink during the ramp; the button LED brightness is sufficient // to indicate which power channel(s) are being used -#ifdef BLINK_AT_CHANNEL_BOUNDARIES -#undef BLINK_AT_CHANNEL_BOUNDARIES +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE #endif #ifdef BLINK_AT_RAMP_CEILING #undef BLINK_AT_RAMP_CEILING diff --git a/spaghetti-monster/rampingios/rampingiosv3.c b/spaghetti-monster/rampingios/rampingiosv3.c index c6886e7..e4eb2fa 100644 --- a/spaghetti-monster/rampingios/rampingiosv3.c +++ b/spaghetti-monster/rampingios/rampingiosv3.c @@ -33,7 +33,7 @@ // or too short) #define MOON_TIMING_HINT // short blips while ramping -#define BLINK_AT_CHANNEL_BOUNDARIES +#define BLINK_AT_RAMP_MIDDLE //#define BLINK_AT_RAMP_FLOOR #define BLINK_AT_RAMP_CEILING //#define BLINK_AT_STEPS // whenever a discrete ramp mode is passed in smooth mode @@ -177,8 +177,28 @@ void save_config(); #define RAMP_DISCRETE_STEPS 7 #endif +// mile marker(s) partway up the ramp +// default: blink only at border between regulated and FET +#ifdef BLINK_AT_RAMP_MIDDLE + #if PWM_CHANNELS >= 3 + #ifndef BLINK_AT_RAMP_MIDDLE_1 + #define BLINK_AT_RAMP_MIDDLE_1 MAX_Nx7135 + #ifndef BLINK_AT_RAMP_MIDDLE_2 + #define BLINK_AT_RAMP_MIDDLE_2 MAX_1x7135 + #endif + #endif + #else + #ifndef BLINK_AT_RAMP_MIDDLE_1 + #define BLINK_AT_RAMP_MIDDLE_1 MAX_1x7135 + #endif + #endif +#endif + // brightness control -uint8_t memorized_level = MAX_1x7135; +#ifndef DEFAULT_LEVEL +#define DEFAULT_LEVEL MAX_1x7135 +#endif +uint8_t memorized_level = DEFAULT_LEVEL; // smooth vs discrete ramping volatile uint8_t ramp_style = 0; // 0 = smooth, 1 = discrete volatile uint8_t ramp_smooth_floor = RAMP_SMOOTH_FLOOR; @@ -262,7 +282,7 @@ uint8_t off_state(Event event, uint16_t arg) { // let the user know they can let go now to stay at moon uint8_t temp = actual_level; set_level(0); - delay_4ms(2); + delay_4ms(3); set_level(temp); } else #endif @@ -444,15 +464,15 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_THERMAL_REGULATION target_level = memorized_level; #endif - #if defined(BLINK_AT_RAMP_CEILING) || defined(BLINK_AT_CHANNEL_BOUNDARIES) + #if defined(BLINK_AT_RAMP_CEILING) || defined(BLINK_AT_RAMP_MIDDLE) // only blink once for each threshold if ((memorized_level != actual_level) && ( 0 // for easier syntax below - #ifdef BLINK_AT_CHANNEL_BOUNDARIES - || (memorized_level == MAX_1x7135) - #if PWM_CHANNELS >= 3 - || (memorized_level == MAX_Nx7135) + #ifdef BLINK_AT_RAMP_MIDDLE_1 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_1) #endif + #ifdef BLINK_AT_RAMP_MIDDLE_2 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_2) #endif #ifdef BLINK_AT_RAMP_CEILING || (memorized_level == mode_max) @@ -506,15 +526,15 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_THERMAL_REGULATION target_level = memorized_level; #endif - #if defined(BLINK_AT_RAMP_FLOOR) || defined(BLINK_AT_CHANNEL_BOUNDARIES) + #if defined(BLINK_AT_RAMP_FLOOR) || defined(BLINK_AT_RAMP_MIDDLE) // only blink once for each threshold if ((memorized_level != actual_level) && ( 0 // for easier syntax below - #ifdef BLINK_AT_CHANNEL_BOUNDARIES - || (memorized_level == MAX_1x7135) - #if PWM_CHANNELS >= 3 - || (memorized_level == MAX_Nx7135) + #ifdef BLINK_AT_RAMP_MIDDLE_1 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_1) #endif + #ifdef BLINK_AT_RAMP_MIDDLE_2 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_2) #endif #ifdef BLINK_AT_RAMP_FLOOR || (memorized_level == mode_min) -- cgit v1.2.3 From 6e645f9f442493e55b00ce801a8d8e1219833198 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 18 Mar 2019 04:07:47 -0600 Subject: adjusted Emisar D18 ramp shape and other config options --- spaghetti-monster/anduril/cfg-emisar-d18.h | 34 ++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-emisar-d18.h b/spaghetti-monster/anduril/cfg-emisar-d18.h index 5171dba..bba846f 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d18.h +++ b/spaghetti-monster/anduril/cfg-emisar-d18.h @@ -16,23 +16,31 @@ #define USE_TENCLICK_THERMAL_CONFIG -// FW3A 1x7135 ramp: -// ../../bin/level_calc.py cube 1 65 7135 1 0.8 150 -// ... mixed with this: -// ../../../bin/level_calc.py ninth 3 150 7135 1 2.5 150 7135 1 1 1600 FET 1 10 5265 +// level_calc.py ninth 3 150 7135 1 2.0 130.2 7135 1 1 2203.62 FET 1 10 12000 +// (designed to make 1x hit at level 55, and Nx hit at level 110) #define RAMP_LENGTH 150 -#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,5,6,8,9,11,13,14,16,18,20,22,25,27,29,32,34,37,40,43,46,49,53,56,60,63,67,71,76,80,85,89,94,100,105,110,116,122,128,135,142,148,156,163,171,179,187,196,205,214,224,234,244,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,10,16,21,27,33,39,46,52,59,66,74,81,89,97,105,114,123,132,142,151,162,172,183,194,205,217,229,242,255 -#define MAX_1x7135 65 -#define MAX_Nx7135 120 -#define HALFSPEED_LEVEL 14 +#define PWM1_LEVELS 1,1,2,2,3,3,4,5,5,6,7,8,9,10,11,13,14,15,17,19,21,22,25,27,29,32,35,38,41,44,48,52,56,60,65,70,76,81,87,94,101,108,116,124,133,142,152,163,174,185,198,211,225,239,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,4,5,6,7,9,10,12,13,15,17,18,20,22,24,26,29,31,34,36,39,42,45,48,52,55,59,63,67,71,76,80,85,90,96,101,107,113,120,126,133,140,148,156,164,172,181,191,200,210,221,232,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,6,10,13,16,19,23,27,30,34,39,43,47,52,57,62,67,72,78,84,90,96,103,109,116,123,131,138,146,155,163,172,181,191,201,211,221,232,243,255 +#define MAX_1x7135 55 +#define MAX_Nx7135 110 +#define HALFSPEED_LEVEL 16 #define QUARTERSPEED_LEVEL 5 -// start at ~1500 lm, not ~150 lm +// start at ~2000 lm after battery change, not ~150 lm (at Emisar's request) #define DEFAULT_LEVEL MAX_Nx7135 -// stop panicking at about 4.9A or ~1750 lm -#define THERM_FASTER_LEVEL MAX_Nx7135 +// higher floor than default, and stop at highest regulated level +#define RAMP_DISCRETE_FLOOR 20 +#define RAMP_DISCRETE_CEIL MAX_Nx7135 +#define RAMP_DISCRETE_STEPS 7 + +// only blink at max regulated level and ceiling +#define BLINK_AT_RAMP_MIDDLE +#define BLINK_AT_RAMP_MIDDLE_1 MAX_Nx7135 +#define BLINK_AT_RAMP_CEILING + +// stop panicking at about ~30% power or ~3600 lm +#define THERM_FASTER_LEVEL 120 // optional, makes initial turbo step-down faster so first peak isn't as hot #define THERM_HARD_TURBO_DROP -- cgit v1.2.3 From 9a203920f936ff3b7fd5c4548095fe6663571a5f Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 26 Mar 2019 11:47:07 -0600 Subject: added seventh-root shape to level_calc.py --- bin/level_calc.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/level_calc.py b/bin/level_calc.py index c903800..7635595 100755 --- a/bin/level_calc.py +++ b/bin/level_calc.py @@ -5,7 +5,7 @@ from __future__ import print_function import math interactive = False -# supported shapes: ninth, fifth, cube, square, log_e, log_2 +# supported shapes: ninth, seventh, fifth, cube, square, log_e, log_2 #ramp_shape = 'cube' @@ -14,7 +14,7 @@ def main(args): """ # Get parameters from the user questions_main = [ - (str, 'ramp_shape', 'cube', 'Ramp shape? [cube, square, fifth, ninth, log_e, log_2]'), + (str, 'ramp_shape', 'cube', 'Ramp shape? [cube, square, fifth, seventh, ninth, log_e, log_2]'), (int, 'num_channels', 1, 'How many power channels?'), (int, 'num_levels', 4, 'How many total levels do you want?'), ] @@ -169,6 +169,7 @@ def get_value(text, default, args): shapes = dict( ninth = (lambda x: x**9, lambda x: math.pow(x, 1/9.0)), + seventh= (lambda x: x**7, lambda x: math.pow(x, 1/7.0)), fifth = (lambda x: x**5, lambda x: math.pow(x, 1/5.0)), cube = (lambda x: x**3, lambda x: math.pow(x, 1/3.0)), square = (lambda x: x**2, lambda x: math.pow(x, 1/2.0)), -- cgit v1.2.3 From f4d0a69d866556fc1f66d723cf9f19163ed2bcec Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 26 Mar 2019 11:47:38 -0600 Subject: tweaked D18 ramp (03-18a version) --- spaghetti-monster/anduril/cfg-emisar-d18.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-emisar-d18.h b/spaghetti-monster/anduril/cfg-emisar-d18.h index bba846f..a9a5d4e 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d18.h +++ b/spaghetti-monster/anduril/cfg-emisar-d18.h @@ -20,8 +20,8 @@ // (designed to make 1x hit at level 55, and Nx hit at level 110) #define RAMP_LENGTH 150 #define PWM1_LEVELS 1,1,2,2,3,3,4,5,5,6,7,8,9,10,11,13,14,15,17,19,21,22,25,27,29,32,35,38,41,44,48,52,56,60,65,70,76,81,87,94,101,108,116,124,133,142,152,163,174,185,198,211,225,239,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,4,5,6,7,9,10,12,13,15,17,18,20,22,24,26,29,31,34,36,39,42,45,48,52,55,59,63,67,71,76,80,85,90,96,101,107,113,120,126,133,140,148,156,164,172,181,191,200,210,221,232,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,6,10,13,16,19,23,27,30,34,39,43,47,52,57,62,67,72,78,84,90,96,103,109,116,123,131,138,146,155,163,172,181,191,201,211,221,232,243,255 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,33,36,38,41,43,46,49,53,56,59,63,67,71,75,79,84,89,94,99,104,110,116,122,129,135,143,150,158,166,174,183,192,201,211,222,232,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,8,11,15,18,21,25,28,32,36,40,45,49,54,58,63,69,74,79,85,91,97,104,110,117,124,132,139,147,156,164,173,182,191,201,211,222,232,243,255 #define MAX_1x7135 55 #define MAX_Nx7135 110 #define HALFSPEED_LEVEL 16 -- cgit v1.2.3 From 81bfb809ed4fcec12ae96b07e826c78e14d019a0 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 26 Mar 2019 11:49:23 -0600 Subject: updated D18 config to 03-21 version --- spaghetti-monster/anduril/cfg-emisar-d18.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-emisar-d18.h b/spaghetti-monster/anduril/cfg-emisar-d18.h index a9a5d4e..fcea43a 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d18.h +++ b/spaghetti-monster/anduril/cfg-emisar-d18.h @@ -16,22 +16,22 @@ #define USE_TENCLICK_THERMAL_CONFIG -// level_calc.py ninth 3 150 7135 1 2.0 130.2 7135 1 1 2203.62 FET 1 10 12000 -// (designed to make 1x hit at level 55, and Nx hit at level 110) +// level_calc.py seventh 3 150 7135 1 1.4 117.99 7135 6 1 1706.86 FET 3 10 13000 +// (designed to make 1x hit at level 50, and Nx hit at level 100) #define RAMP_LENGTH 150 -#define PWM1_LEVELS 1,1,2,2,3,3,4,5,5,6,7,8,9,10,11,13,14,15,17,19,21,22,25,27,29,32,35,38,41,44,48,52,56,60,65,70,76,81,87,94,101,108,116,124,133,142,152,163,174,185,198,211,225,239,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,33,36,38,41,43,46,49,53,56,59,63,67,71,75,79,84,89,94,99,104,110,116,122,129,135,143,150,158,166,174,183,192,201,211,222,232,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,8,11,15,18,21,25,28,32,36,40,45,49,54,58,63,69,74,79,85,91,97,104,110,117,124,132,139,147,156,164,173,182,191,201,211,222,232,243,255 -#define MAX_1x7135 55 -#define MAX_Nx7135 110 -#define HALFSPEED_LEVEL 16 -#define QUARTERSPEED_LEVEL 5 +#define PWM1_LEVELS 1,1,2,2,3,4,4,5,6,7,8,9,10,11,15,16,18,20,22,24,26,28,30,33,36,39,43,47,51,56,61,66,72,78,85,92,99,107,116,125,135,145,156,168,180,194,208,222,238,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,10,11,13,14,16,18,19,21,23,26,28,30,33,35,38,41,44,47,51,54,58,62,66,70,75,79,84,90,95,101,106,112,119,126,133,140,147,155,164,172,181,190,200,210,221,232,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,9,11,13,15,18,20,23,25,28,31,34,37,40,44,47,51,54,58,62,66,70,75,79,84,89,94,99,104,110,115,121,127,134,140,147,154,161,168,176,183,191,200,208,217,226,235,245,255 +#define MAX_1x7135 50 +#define MAX_Nx7135 100 +#define HALFSPEED_LEVEL 15 +#define QUARTERSPEED_LEVEL 6 // start at ~2000 lm after battery change, not ~150 lm (at Emisar's request) #define DEFAULT_LEVEL MAX_Nx7135 // higher floor than default, and stop at highest regulated level -#define RAMP_DISCRETE_FLOOR 20 +#define RAMP_DISCRETE_FLOOR 25 #define RAMP_DISCRETE_CEIL MAX_Nx7135 #define RAMP_DISCRETE_STEPS 7 @@ -40,7 +40,7 @@ #define BLINK_AT_RAMP_MIDDLE_1 MAX_Nx7135 #define BLINK_AT_RAMP_CEILING -// stop panicking at about ~30% power or ~3600 lm -#define THERM_FASTER_LEVEL 120 +// stop panicking at about ~40% power or ~5000 lm +#define THERM_FASTER_LEVEL 125 // optional, makes initial turbo step-down faster so first peak isn't as hot #define THERM_HARD_TURBO_DROP -- cgit v1.2.3