1
// lockout-mode.c: Lockout mode for Anduril.
2
// Copyright (C) 2017-2023 Selene ToyKeeper
3
// SPDX-License-Identifier: GPL-3.0-or-later
7
#include "lockout-mode.h"
9
uint8_t lockout_state(Event event, uint16_t arg) {
10
#ifdef USE_MOON_DURING_LOCKOUT_MODE
11
// momentary(ish) moon mode during lockout
12
// button is being held
13
#ifdef USE_AUX_RGB_LEDS
14
// don't turn on during RGB aux LED configuration
15
if (event == EV_click7_hold) { set_level(0); } else
17
if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) {
19
// click, hold: highest floor (or manual mem level)
20
uint8_t lvl = cfg.ramp_floors[0];
21
if (1 == (event & 0x0f)) { // first click
22
if (cfg.ramp_floors[1] < lvl) lvl = cfg.ramp_floors[1];
23
} else { // 2nd click or later
24
if (cfg.ramp_floors[1] > lvl) lvl = cfg.ramp_floors[1];
25
#ifdef USE_MANUAL_MEMORY
26
if (cfg.manual_memory) lvl = cfg.manual_memory;
31
// button was released
32
else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) {
35
#endif // ifdef USE_MOON_DURING_LOCKOUT_MODE
37
// regular event handling
38
// conserve power while locked out
39
// (allow staying awake long enough to exit, but otherwise
40
// be persistent about going back to sleep every few seconds
41
// even if the user keeps pressing the button)
42
if (event == EV_enter_state) {
44
#ifdef USE_INDICATOR_LED
45
// redundant, sleep tick does the same thing
46
// indicator_led_update(cfg.indicator_led_mode >> 2, 0);
47
#elif defined(USE_AUX_RGB_LEDS)
48
rgb_led_update(cfg.rgb_led_lockout_mode, 0);
52
else if (event == EV_tick) {
53
if (arg > HOLD_TIMEOUT) {
55
#ifdef USE_INDICATOR_LED
56
// redundant, sleep tick does the same thing
57
//indicator_led_update(cfg.indicator_led_mode >> 2, arg);
58
#elif defined(USE_AUX_RGB_LEDS)
59
rgb_led_update(cfg.rgb_led_lockout_mode, arg);
65
#if defined(TICK_DURING_STANDBY) && (defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS))
66
else if (event == EV_sleep_tick) {
67
if (ticks_since_on < 255) ticks_since_on ++;
68
#ifdef USE_MANUAL_MEMORY_TIMER
69
// reset to manual memory level when timer expires
70
if (cfg.manual_memory &&
71
(arg >= (cfg.manual_memory_timer * SLEEP_TICKS_PER_MINUTE))) {
72
manual_memory_restore();
75
#if defined(USE_INDICATOR_LED)
76
indicator_led_update(cfg.indicator_led_mode >> 2, arg);
77
#elif defined(USE_AUX_RGB_LEDS)
78
rgb_led_update(cfg.rgb_led_lockout_mode, arg);
84
// 3 clicks: exit and turn off
85
else if (event == EV_3clicks) {
87
set_state(off_state, 0);
91
// 4 clicks: exit and turn on
92
else if (event == EV_4clicks) {
93
#if defined(USE_MANUAL_MEMORY) && !defined(USE_MANUAL_MEMORY_TIMER)
94
// this clause probably isn't used by any configs any more
95
// but is included just in case someone configures it this way
96
if (cfg.manual_memory)
97
set_state(steady_state, cfg.manual_memory);
100
set_state(steady_state, memorized_level);
101
return EVENT_HANDLED;
104
// 4 clicks, but hold last: exit and start at floor
105
else if (event == EV_click4_hold) {
108
// reset button sequence to avoid activating anything in ramp mode
110
// ... and back to ramp mode
111
set_state(steady_state, 1);
112
return EVENT_HANDLED;
115
// 5 clicks: exit and turn on at ceiling level
116
else if (event == EV_5clicks) {
117
set_state(steady_state, MAX_LEVEL);
118
return EVENT_HANDLED;
121
#if NUM_CHANNEL_MODES > 1
122
// 3H: next channel mode
123
else if (event == EV_click3_hold) {
124
if (0 == (arg % TICKS_PER_SECOND)) {
125
// pretend the user clicked 3 times to change channels
126
return channel_mode_state(EV_3clicks, 0);
131
////////// Every action below here is blocked in the (non-Extended) Simple UI //////////
133
#if defined(USE_SIMPLE_UI) && !defined(USE_EXTENDED_SIMPLE_UI)
134
if (cfg.simple_ui_active) {
135
return EVENT_NOT_HANDLED;
137
#endif // if simple UI but not extended simple UI
139
#if defined(USE_INDICATOR_LED)
140
// 7 clicks: rotate through indicator LED modes (lockout mode)
141
else if (event == EV_7clicks) {
142
#if defined(USE_INDICATOR_LED)
143
uint8_t mode = cfg.indicator_led_mode >> 2;
144
#ifdef TICK_DURING_STANDBY
145
mode = (mode + 1) & 3;
147
mode = (mode + 1) % 3;
149
#ifdef INDICATOR_LED_SKIP_LOW
150
if (mode == 1) { mode ++; }
152
cfg.indicator_led_mode = (mode << 2) + (cfg.indicator_led_mode & 0x03);
153
// redundant, sleep tick does the same thing
154
//indicator_led_update(cfg.indicator_led_mode >> 2, arg);
155
#elif defined(USE_AUX_RGB_LEDS)
158
return EVENT_HANDLED;
160
#elif defined(USE_AUX_RGB_LEDS)
161
// 7 clicks: change RGB aux LED pattern
162
else if (event == EV_7clicks) {
163
uint8_t mode = (cfg.rgb_led_lockout_mode >> 4) + 1;
164
mode = mode % RGB_LED_NUM_PATTERNS;
165
cfg.rgb_led_lockout_mode = (mode << 4) | (cfg.rgb_led_lockout_mode & 0x0f);
166
rgb_led_update(cfg.rgb_led_lockout_mode, 0);
169
return EVENT_HANDLED;
171
// 7H: change RGB aux LED color
172
else if (event == EV_click7_hold) {
173
setting_rgb_mode_now = 1;
174
if (0 == (arg & 0x3f)) {
175
uint8_t mode = (cfg.rgb_led_lockout_mode & 0x0f) + 1;
176
mode = mode % RGB_LED_NUM_COLORS;
177
cfg.rgb_led_lockout_mode = mode | (cfg.rgb_led_lockout_mode & 0xf0);
180
rgb_led_update(cfg.rgb_led_lockout_mode, arg);
181
return EVENT_HANDLED;
183
// 7H, release: save new color
184
else if (event == EV_click7_hold_release) {
185
setting_rgb_mode_now = 0;
187
return EVENT_HANDLED;
191
#if defined(USE_EXTENDED_SIMPLE_UI) && defined(USE_SIMPLE_UI)
192
////////// Every action below here is blocked in the Extended Simple UI //////////
193
if (cfg.simple_ui_active) {
194
return EVENT_NOT_HANDLED;
196
#endif // if extended simple UI
199
// 10H: configure the autolock option
200
else if (event == EV_click10_hold) {
201
push_state(autolock_config_state, 0);
202
return EVENT_HANDLED;
206
return EVENT_NOT_HANDLED;
210
// set the auto-lock timer to N minutes, where N is the number of clicks
211
void autolock_config_save(uint8_t step, uint8_t value) {
212
cfg.autolock_time = value;
215
uint8_t autolock_config_state(Event event, uint16_t arg) {
216
return config_state_base(event, arg, 1, autolock_config_save);
218
#endif // #ifdef USE_AUTOLOCK