Lamp-Da 0.1
A compact lantern project
Loading...
Searching...
No Matches
indexable_behavior.hpp
Go to the documentation of this file.
1
5#ifndef INDEXABLE_BEHAVIOR_MANAGER_H
6#define INDEXABLE_BEHAVIOR_MANAGER_H
7
9
10//
11// note: this code is included as-is by:
12// - user/indexable_functions.h
13//
14
15#include <cstdint>
16namespace lampda::user {
17
18bool button_clicked_default(const uint8_t clicks)
19{
20 // Handle default common behavior
22 {
23 // some event is already handled
24 return true;
25 }
26
27 auto manager = get_context();
28
29 switch (clicks)
30 {
31 case 2: // 2 clicks: next mode
32 {
33 if (manager.state.isInFavoriteMockGroup)
34 {
35 // if in favorite, next favorite
36 manager.state.lastFavoriteStep += 1;
37 // sanity check, if it fails, quit favorites
38 manager.state.isInFavoriteMockGroup = manager.jump_to_favorite(manager.state.lastFavoriteStep, false);
39 }
40 else
41 {
42 if (manager.state.isLastScrollAGroupChange and manager.lamp.now - manager.state.lastScrollStopped < 2000)
43 {
44 // last action was a group change & timer did not run out yet:
45 // change group
46 manager.next_group();
47
48 // prevent further jumps
49 manager.state.isLastScrollAGroupChange = false;
50 }
51 else
52 {
53 // else: just change mode
54 manager.next_mode();
55 }
56 }
57#ifdef LMBD_SIMULATION
58 {
59 int _groupId = manager.get_active_group();
60 int _modeId = manager.get_active_mode();
61 fprintf(stderr, "group %d *mode %d\n", _groupId, _modeId);
62 if (manager.everySunsetCallback[_groupId][_modeId])
63 fprintf(stderr, " - hasSunsetAnimation\n");
64 if (manager.everyBrightCallback[_groupId][_modeId])
65 fprintf(stderr, " - hasBrightCallback\n");
66 if (manager.everyCustomRamp[_groupId][_modeId])
67 fprintf(stderr, " - hasCustomRamp\n");
68 if (manager.state.rampHandler.animEffect)
69 fprintf(stderr, " - has anim effect\n");
70 if (manager.everyRequireUserThread[_groupId][_modeId])
71 fprintf(stderr, " - requireUserThread\n");
72 if (manager.everySystemCallbacks[_groupId][_modeId])
73 fprintf(stderr, " - hasSystemCallbacks\n");
74 if (manager.everyButtonCustomUI[_groupId][_modeId])
75 fprintf(stderr, " - hasButtonCustomUI\n");
76 }
77#endif
78
79 return true;
80 }
81
82 case 3: // 3 clicks: next group or quit favorite group
83 {
84 if (manager.state.isInFavoriteMockGroup)
85 {
86#ifdef LMBD_SIMULATION
87 fprintf(stderr, "Exit fake favorite group\n");
88#endif
89 // reset favorite indicator
90 manager.state.isInFavoriteMockGroup = false;
91 // return to previous state
92 manager.set_active_group(manager.state.beforeFavoriteGroupIndex);
93 manager.set_active_mode(manager.state.beforeFavoriteModeIndex);
94
95 // blip to indicate favorite mode exit
96 manager.blip(250);
97 }
98 else
99 {
100 // true next group
101 manager.next_group();
102 }
103
104#ifdef LMBD_SIMULATION
105 {
106 int _groupId = manager.get_active_group();
107 int _modeId = manager.get_active_mode();
108 fprintf(stderr, "group %d *mode %d\n", _groupId, _modeId);
109 if (manager.everySunsetCallback[_groupId][_modeId])
110 fprintf(stderr, " - hasSunsetAnimation\n");
111 if (manager.everyBrightCallback[_groupId][_modeId])
112 fprintf(stderr, " - hasBrightCallback\n");
113 if (manager.everyCustomRamp[_groupId][_modeId])
114 fprintf(stderr, " - hasCustomRamp\n");
115 if (manager.state.rampHandler.animEffect)
116 fprintf(stderr, " - has anim effect\n");
117 if (manager.everyRequireUserThread[_groupId][_modeId])
118 fprintf(stderr, " - requireUserThread\n");
119 if (manager.everySystemCallbacks[_groupId][_modeId])
120 fprintf(stderr, " - hasSystemCallbacks\n");
121 if (manager.everyButtonCustomUI[_groupId][_modeId])
122 fprintf(stderr, " - hasButtonCustomUI\n");
123 }
124#endif
125 return true;
126 }
127
128 case 4: // 4 clicks: jump to favorite
129 {
130 if (not manager.state.isInFavoriteMockGroup)
131 {
132 // jump and save last used mode
133 if (manager.jump_to_favorite(manager.state.lastFavoriteStep, true))
134 {
135 manager.state.isInFavoriteMockGroup = true;
136 // blip to indicate favorite mode enter
137 manager.blip(250);
138 }
139 }
140#ifdef LMBD_SIMULATION
141 {
142 int _groupId = manager.get_active_group();
143 int _modeId = manager.get_active_mode();
144 fprintf(stderr, "group %d *mode %d\n", _groupId, _modeId);
145 if (manager.everySunsetCallback[_groupId][_modeId])
146 fprintf(stderr, " - hasSunsetAnimation\n");
147 if (manager.everyBrightCallback[_groupId][_modeId])
148 fprintf(stderr, " - hasBrightCallback\n");
149 if (manager.everyCustomRamp[_groupId][_modeId])
150 fprintf(stderr, " - hasCustomRamp\n");
151 if (manager.state.rampHandler.animEffect)
152 fprintf(stderr, " - has anim effect\n");
153 if (manager.everyRequireUserThread[_groupId][_modeId])
154 fprintf(stderr, " - requireUserThread\n");
155 if (manager.everySystemCallbacks[_groupId][_modeId])
156 fprintf(stderr, " - hasSystemCallbacks\n");
157 if (manager.everyButtonCustomUI[_groupId][_modeId])
158 fprintf(stderr, " - hasButtonCustomUI\n");
159 }
160#endif
161 return true;
162 }
163 }
164
165 return false;
166}
167
168bool button_hold_default(const uint8_t clicks, const bool isEndOfHoldEvent, const uint32_t holdDuration)
169{
170 // Handle default common behavior
171 if (default_behaviors::button_hold(clicks, isEndOfHoldEvent, holdDuration))
172 {
173 // some event is already handled
174 return true;
175 }
176
177 auto manager = get_context();
178 auto& rampHandler = manager.state.rampHandler;
179
180 switch (clicks)
181 {
182 case 4: // 4 click+hold: configure favorite
183 {
184 if (not isEndOfHoldEvent)
185 {
186 // lock to prevent addition of favorite from favorite & if we are deleting favorites
187 // the second case can happen when the user delete all favorites
188 if (not manager.state.isInFavoriteMockGroup && not manager.state.isInDeleteFavorite)
189 {
190 // no new favorite in favorite
191 manager.animate_favorite_pick(holdDuration, 1500);
192 }
193 else
194 {
195 // remove current favorite
196 manager.animate_favorite_delete(holdDuration, 2000);
197 }
198 }
199 else
200 {
201 manager.state.isInDeleteFavorite = false;
202 }
203 return true;
204 }
205
206 case 6: // 6 click+hold: scroll across modes and group
207 {
208 // no scroll in favorite
209 if (not manager.state.isInFavoriteMockGroup)
210 {
211 // register end of scroll
212 if (isEndOfHoldEvent)
213 {
214 // update release time
215 manager.state.lastScrollStopped = manager.lamp.now;
216 }
217 else
218 {
219 manager.handle_scroll_modes(holdDuration);
220 }
221 }
222 return true;
223 }
224
225 default:
226 break;
227 }
228 return false;
229}
230
231namespace __private_elk {
232
238void handle_pattern_select_command(const uint8_t patternIndex, const uint32_t requestedColor = 0)
239{
240 // ignore if not on
242 return;
243
244 // get manager and execute a mode or group change
245 auto manager = get_context();
246 if (manager.get_hidden_groups_count() <= 0)
247 {
248 platform::lampda_print("Cannot use bluetooth control without an hidden bluetooth group");
249 return;
250 }
251
252 const auto bluetoothGroup = manager.template get_group_id_of_mode<modes::bluetooth::ColorControlMode>();
253 if (bluetoothGroup < 0)
254 {
255 platform::lampda_print("Cannot find the bluetooth group and modes");
256 return;
257 }
258
259 const auto availableModes = manager.get_modes_count();
260 if (availableModes <= patternIndex)
261 {
262 platform::lampda_print("Unimplemented pattern id %d", patternIndex);
263 return;
264 }
265
266 manager.set_active_group(bluetoothGroup);
267 manager.set_active_mode(patternIndex);
268
269 // sanity check
270 const int trueIndex = manager.template get_mode_id<modes::bluetooth::ColorControlMode>();
271 assert(trueIndex == 0 && "Bluetooth group should have the programmable color output as the first group index");
272
273 // handle special programmable group mode
274 if (patternIndex == 0)
275 {
276 auto& modeState = manager.template get_state_of_mode<modes::bluetooth::ColorControlMode>();
277 modeState.color = requestedColor;
278 }
279}
280
281} // namespace __private_elk
282
283void handle_elk_command(const utils::ELK::Package& elkControlCommand)
284{
285 // Handle default common behavior
286 if (default_behaviors::handle_elk_command(elkControlCommand))
287 {
288 // some event is already handled
289 return;
290 }
291
292 switch (elkControlCommand.type)
293 {
295 {
296 const uint32_t color =
297 elkControlCommand.data[0] << 16 | elkControlCommand.data[1] << 8 | elkControlCommand.data[2];
298 __private_elk::handle_pattern_select_command(0, color);
299 break;
300 }
302 {
303 __private_elk::handle_pattern_select_command(elkControlCommand.data[0] + 1);
304 break;
305 }
306 // unhandled
307 default:
308 {
309 platform::lampda_print("Unsupported ELK message type");
310 break;
311 }
312 }
313}
314
315} // namespace lampda::user
316
317#endif
Define assertions helpers.
void handle_pattern_select_command(const uint8_t patternIndex, const uint32_t requestedColor=0)
Handle a pattern change command.
Definition: indexable_behavior.hpp:238
bool is_in_output_state()
return true if the system is in output mode
Definition: behavior.cpp:137
void lampda_print(const char *format,...)
Definition: print.cpp:43
bool button_hold(const uint8_t clicks, const bool isEndOfHoldEvent, const uint32_t holdDuration)
must be called by the lampda::user::button_hold_default
Definition: default_behavior.hpp:197
bool button_clicked(const uint8_t clicks)
must be called by the lampda::user::button_clicked_default
Definition: default_behavior.hpp:172
Contains code handling custom user mode functions for indexable strips.
Definition: default_behavior.hpp:15
bool button_clicked_default(const uint8_t)
Called to handle button click events for default user mode behaviors.
Definition: indexable_behavior.hpp:18
bool button_hold_default(const uint8_t, const bool, const uint32_t)
Called to handle button click+hold events for user mode behaviors.
Definition: indexable_behavior.hpp:168
void handle_elk_command(const utils::ELK::Package &elkControlCommand)
Handle a ELK BLE package.
Definition: indexable_behavior.hpp:283
@ PATTERN_SELECT
select a display pattern in a list
@ COLOR_SELECT
set output as a target color
Definition: elk_decoder.h:33