188.33.14
by Selene ToyKeeper
switched the rest of FSM + Anduril to use SPDX license headers |
1 |
// candle-mode.c: Candle mode for Anduril.
|
2 |
// Copyright (C) 2017-2023 Selene ToyKeeper
|
|
3 |
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
4 |
#pragma once
|
|
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
5 |
|
6 |
#include "candle-mode.h" |
|
188.22.28
by Selene Scriven
moved sunset bump from 3C to 4H, fixed candle sunset behavior (was overflowing / wrapping around) |
7 |
|
188.22.27
by Selene Scriven
replaced "goodnight / sunset mode" with sunset timer, which works in both candle mode and regular ramp mode |
8 |
#ifdef USE_SUNSET_TIMER
|
9 |
#include "sunset-timer.h" |
|
10 |
#endif
|
|
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
11 |
|
12 |
uint8_t candle_mode_state(Event event, uint16_t arg) { |
|
13 |
static int8_t ramp_direction = 1; |
|
188.33.2
by Selene ToyKeeper
refactor progress checkpoint ... got Sofirn LT1S Pro and Emisar D4v2 working |
14 |
#define MAX_CANDLE_LEVEL (MAX_LEVEL-CANDLE_AMPLITUDE-15)
|
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
15 |
static uint8_t candle_wave1 = 0; |
16 |
static uint8_t candle_wave2 = 0; |
|
17 |
static uint8_t candle_wave3 = 0; |
|
18 |
static uint8_t candle_wave2_speed = 0; |
|
19 |
// these should add up to 100
|
|
20 |
#define CANDLE_WAVE1_MAXDEPTH 30
|
|
21 |
#define CANDLE_WAVE2_MAXDEPTH 45
|
|
22 |
#define CANDLE_WAVE3_MAXDEPTH 25
|
|
23 |
static const uint8_t candle_wave1_depth = CANDLE_WAVE1_MAXDEPTH * CANDLE_AMPLITUDE / 100; |
|
24 |
static uint8_t candle_wave2_depth = CANDLE_WAVE2_MAXDEPTH * CANDLE_AMPLITUDE / 100; |
|
25 |
static uint8_t candle_wave3_depth = CANDLE_WAVE3_MAXDEPTH * CANDLE_AMPLITUDE / 100; |
|
26 |
static uint8_t candle_mode_brightness = 24; |
|
188.22.27
by Selene Scriven
replaced "goodnight / sunset mode" with sunset timer, which works in both candle mode and regular ramp mode |
27 |
|
28 |
#ifdef USE_SUNSET_TIMER
|
|
29 |
// let the candle "burn out" and shut itself off
|
|
30 |
// if the user told it to
|
|
31 |
// cache this in case it changes when the timer is called
|
|
32 |
uint8_t sunset_active = sunset_timer; |
|
33 |
// clock tick
|
|
34 |
sunset_timer_state(event, arg); |
|
35 |
// if the timer just expired, shut off
|
|
36 |
if (sunset_active && (! sunset_timer)) { |
|
37 |
set_state(off_state, 0); |
|
188.33.66
by Selene ToyKeeper
Removed references to Harry Potter, |
38 |
return EVENT_HANDLED; |
188.22.27
by Selene Scriven
replaced "goodnight / sunset mode" with sunset timer, which works in both candle mode and regular ramp mode |
39 |
}
|
40 |
#endif // ifdef USE_SUNSET_TIMER |
|
41 |
||
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
42 |
|
43 |
if (event == EV_enter_state) { |
|
44 |
ramp_direction = 1; |
|
188.33.66
by Selene ToyKeeper
Removed references to Harry Potter, |
45 |
return EVENT_HANDLED; |
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
46 |
}
|
188.22.27
by Selene Scriven
replaced "goodnight / sunset mode" with sunset timer, which works in both candle mode and regular ramp mode |
47 |
#ifdef USE_SUNSET_TIMER
|
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
48 |
// 2 clicks: cancel timer
|
49 |
else if (event == EV_2clicks) { |
|
50 |
// parent state just rotated through strobe/flasher modes,
|
|
51 |
// so cancel timer... in case any time was left over from earlier
|
|
188.22.27
by Selene Scriven
replaced "goodnight / sunset mode" with sunset timer, which works in both candle mode and regular ramp mode |
52 |
sunset_timer = 0; |
188.33.66
by Selene ToyKeeper
Removed references to Harry Potter, |
53 |
return EVENT_HANDLED; |
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
54 |
}
|
188.22.27
by Selene Scriven
replaced "goodnight / sunset mode" with sunset timer, which works in both candle mode and regular ramp mode |
55 |
#endif // ifdef USE_SUNSET_TIMER |
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
56 |
// hold: change brightness (brighter)
|
57 |
else if (event == EV_click1_hold) { |
|
58 |
// ramp away from extremes
|
|
59 |
if (! arg) { |
|
60 |
if (candle_mode_brightness >= MAX_CANDLE_LEVEL) { ramp_direction = -1; } |
|
61 |
else if (candle_mode_brightness <= 1) { ramp_direction = 1; } |
|
62 |
}
|
|
63 |
// change brightness, but not too far
|
|
64 |
candle_mode_brightness += ramp_direction; |
|
65 |
if (candle_mode_brightness < 1) candle_mode_brightness = 1; |
|
66 |
else if (candle_mode_brightness > MAX_CANDLE_LEVEL) candle_mode_brightness = MAX_CANDLE_LEVEL; |
|
188.33.66
by Selene ToyKeeper
Removed references to Harry Potter, |
67 |
return EVENT_HANDLED; |
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
68 |
}
|
69 |
// reverse ramp direction on hold release
|
|
70 |
else if (event == EV_click1_hold_release) { |
|
71 |
ramp_direction = -ramp_direction; |
|
188.33.66
by Selene ToyKeeper
Removed references to Harry Potter, |
72 |
return EVENT_HANDLED; |
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
73 |
}
|
74 |
// click, hold: change brightness (dimmer)
|
|
75 |
else if (event == EV_click2_hold) { |
|
76 |
ramp_direction = 1; |
|
77 |
if (candle_mode_brightness > 1) |
|
78 |
candle_mode_brightness --; |
|
188.33.66
by Selene ToyKeeper
Removed references to Harry Potter, |
79 |
return EVENT_HANDLED; |
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
80 |
}
|
81 |
// clock tick: animate candle brightness
|
|
82 |
else if (event == EV_tick) { |
|
83 |
// un-reverse after 1 second
|
|
188.28.7
by Selene Scriven
reduced length of auto-reverse timing window from ~1000 ms to ~660ms, because it was too fast |
84 |
if (arg == AUTO_REVERSE_TIME) ramp_direction = 1; |
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
85 |
|
86 |
// 3-oscillator synth for a relatively organic pattern
|
|
87 |
uint8_t add; |
|
88 |
add = ((triangle_wave(candle_wave1) * candle_wave1_depth) >> 8) |
|
89 |
+ ((triangle_wave(candle_wave2) * candle_wave2_depth) >> 8) |
|
90 |
+ ((triangle_wave(candle_wave3) * candle_wave3_depth) >> 8); |
|
188.22.28
by Selene Scriven
moved sunset bump from 3C to 4H, fixed candle sunset behavior (was overflowing / wrapping around) |
91 |
uint16_t brightness = candle_mode_brightness + add; |
92 |
||
93 |
// self-timer dims the light during the final minute
|
|
94 |
#ifdef USE_SUNSET_TIMER
|
|
95 |
if (1 == sunset_timer) { |
|
96 |
brightness = brightness |
|
97 |
* ((TICKS_PER_MINUTE>>5) - (sunset_ticks>>5)) |
|
98 |
/ (TICKS_PER_MINUTE>>5); |
|
99 |
}
|
|
100 |
#endif // ifdef USE_SUNSET_TIMER |
|
101 |
||
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
102 |
set_level(brightness); |
103 |
||
104 |
// wave1: slow random LFO
|
|
105 |
// TODO: make wave slower and more erratic?
|
|
106 |
if ((arg & 1) == 0) candle_wave1 += pseudo_rand() & 1; |
|
107 |
// wave2: medium-speed erratic LFO
|
|
108 |
candle_wave2 += candle_wave2_speed; |
|
109 |
// wave3: erratic fast wave
|
|
110 |
candle_wave3 += pseudo_rand() % 37; |
|
111 |
// S&H on wave2 frequency to make it more erratic
|
|
112 |
if ((pseudo_rand() & 0b00111111) == 0) |
|
113 |
candle_wave2_speed = pseudo_rand() % 13; |
|
114 |
// downward sawtooth on wave2 depth to simulate stabilizing
|
|
115 |
if ((candle_wave2_depth > 0) && ((pseudo_rand() & 0b00111111) == 0)) |
|
116 |
candle_wave2_depth --; |
|
117 |
// random sawtooth retrigger
|
|
118 |
if (pseudo_rand() == 0) { |
|
119 |
// random amplitude
|
|
120 |
//candle_wave2_depth = 2 + (pseudo_rand() % ((CANDLE_WAVE2_MAXDEPTH * CANDLE_AMPLITUDE / 100) - 2));
|
|
121 |
candle_wave2_depth = pseudo_rand() % (CANDLE_WAVE2_MAXDEPTH * CANDLE_AMPLITUDE / 100); |
|
122 |
//candle_wave3_depth = 5;
|
|
123 |
candle_wave2 = 0; |
|
124 |
}
|
|
125 |
// downward sawtooth on wave3 depth to simulate stabilizing
|
|
126 |
if ((candle_wave3_depth > 2) && ((pseudo_rand() & 0b00011111) == 0)) |
|
127 |
candle_wave3_depth --; |
|
128 |
if ((pseudo_rand() & 0b01111111) == 0) |
|
129 |
// random amplitude
|
|
130 |
//candle_wave3_depth = 2 + (pseudo_rand() % ((CANDLE_WAVE3_MAXDEPTH * CANDLE_AMPLITUDE / 100) - 2));
|
|
131 |
candle_wave3_depth = pseudo_rand() % (CANDLE_WAVE3_MAXDEPTH * CANDLE_AMPLITUDE / 100); |
|
188.33.66
by Selene ToyKeeper
Removed references to Harry Potter, |
132 |
return EVENT_HANDLED; |
188.22.20
by Selene Scriven
moved candle mode to its own file, since it's kinda big |
133 |
}
|
134 |
return EVENT_NOT_HANDLED; |
|
135 |
}
|
|
136 |