Lamp-Da 0.1
A compact lantern project
Loading...
Searching...
No Matches
group_type.hpp
Go to the documentation of this file.
1#ifndef MODE_GROUP_H
2#define MODE_GROUP_H
3
9#include <cstdint>
10#include <utility>
11#include <optional>
12#include <tuple>
13#include <array>
14
16
21
22namespace lampda::modes {
23
25template<typename AllModes> static constexpr bool verifyGroup()
26{
27 constexpr bool inheritsFromBasicMode = details::allOf<AllModes>::inheritsFromBasicMode;
28 static_assert(inheritsFromBasicMode, "All modes must inherit from modes::BasicMode!");
29
30 constexpr bool stateDefaultConstructible = details::allOf<AllModes>::stateDefaultConstructible;
31 static_assert(stateDefaultConstructible, "All states must be default constructible!");
32
33 bool acc = false;
34 acc |= !inheritsFromBasicMode;
35 acc |= !stateDefaultConstructible;
36 return acc;
37}
38
40template<typename AllModes, bool earlyFail = verifyGroup<AllModes>()> struct GroupTy
41{
42 // tuple helper
43 using SelfTy = GroupTy<AllModes>;
44 using AllModesTy = AllModes;
45 using AllStatesTy = details::StateTyFrom<AllModes>;
46 static constexpr uint8_t nbModes {std::tuple_size_v<AllModesTy>};
47
48 // last mode index must not collide with modes::store::noModeIndex
49 static_assert(nbModes < 32, "Maximum of 31 modes has been exceeded.");
50
51 template<uint8_t Idx> using ModeAtRaw = std::tuple_element_t<Idx, AllModesTy>;
52 template<uint8_t Idx> using ModeAt = std::conditional_t<!earlyFail, ModeAtRaw<Idx>, BasicMode>;
53
54 // required to support group-level context
55 using HasAnyMode = details::anyOf<AllModesTy, earlyFail>;
56 static constexpr bool hasSunsetAnimation = HasAnyMode::hasSunsetAnimation;
57 static constexpr bool hasBrightCallback = HasAnyMode::hasBrightCallback;
58 static constexpr bool hasSystemCallbacks = HasAnyMode::hasSystemCallbacks;
59 static constexpr bool requireUserThread = HasAnyMode::requireUserThread;
60 static constexpr bool hasCustomRamp = HasAnyMode::hasCustomRamp;
61 static constexpr bool hasButtonCustomUI = HasAnyMode::hasButtonCustomUI;
62
63 // useful for runtime tests of mode properties
64 static constexpr auto everySunsetCallback = HasAnyMode::everySunsetCallback;
65 static constexpr auto everyBrightCallback = HasAnyMode::everyBrightCallback;
66 static constexpr auto everySystemCallbacks = HasAnyMode::everySystemCallbacks;
67 static constexpr auto everyRequireUserThread = HasAnyMode::everyRequireUserThread;
68 static constexpr auto everyCustomRamp = HasAnyMode::everyCustomRamp;
69 static constexpr auto everyButtonCustomUI = HasAnyMode::everyButtonCustomUI;
70
71 // constructors
72 GroupTy() = delete;
73 GroupTy(const GroupTy&) = delete;
74 GroupTy& operator=(const GroupTy&) = delete;
75
77 template<typename CallBack> static void LMBD_INLINE dispatch_mode(auto& ctx, CallBack&& cb)
78 {
79 uint8_t modeId = ctx.get_active_mode(nbModes);
80
81 details::unroll<nbModes>([&](auto Idx) LMBD_INLINE {
82 if (Idx == modeId)
83 {
84 cb(context_as<ModeAt<Idx>>(ctx));
85 }
86 });
87 }
88
90 template<bool systemCallbacksOnly, typename CallBack> static void LMBD_INLINE foreach_mode(auto& ctx, CallBack&& cb)
91 {
92 if constexpr (systemCallbacksOnly)
93 {
94 details::unroll<nbModes>([&](auto Idx) LMBD_INLINE {
95 if constexpr (ModeAt<Idx>::hasSystemCallbacks)
96 {
97 cb(context_as<ModeAt<Idx>>(ctx));
98 }
99 });
100 }
101 else
102 {
103 details::unroll<nbModes>([&](auto Idx) LMBD_INLINE {
104 cb(context_as<ModeAt<Idx>>(ctx));
105 });
106 }
107 }
108
109 //
110 // store
111 //
112
113 // persistent values
114 enum class Store : uint16_t
115 {
116 rampMemory,
117 indexMemory
118 };
119
120 static constexpr uint32_t storeId = modes::store::derivateStoreId<modes::store::hash("GroupTyStoreId"), AllModesTy>;
121
122 //
123 // state
124 //
125
126 struct StateTy
127 {
128 AllStatesTy modeStates;
129 std::array<uint8_t, nbModes> customRampMemory;
130 std::array<uint8_t, nbModes> customIndexMemory;
131
133 void LMBD_INLINE save_ramps(auto& ctx, uint8_t modeId)
134 {
135 assert(modeId < nbModes);
136 if constexpr (ctx.hasCustomRamp)
137 {
138 ctx.state.customRampMemory[modeId] = ctx.get_active_custom_ramp();
139 ctx.state.customIndexMemory[modeId] = ctx.get_active_custom_index();
140 }
141 }
142
144 void LMBD_INLINE load_ramps(auto& ctx, uint8_t modeId)
145 {
146 assert(modeId < nbModes);
147 if constexpr (ctx.hasCustomRamp)
148 {
149 ctx.set_active_custom_ramp(ctx.state.customRampMemory[modeId]);
150 ctx.set_active_custom_index(ctx.state.customIndexMemory[modeId]);
151 }
152 }
153 };
154
156 template<typename Mode> static auto* LMBD_INLINE getStateOf(auto& manager)
157 {
158 using StateTy = typename Mode::StateTy;
159 using OptionalTy = std::optional<StateTy>;
160
161 StateTy* substate = nullptr;
162 details::unroll<nbModes>([&](auto Idx) LMBD_INLINE {
163 using ModeHere = ModeAt<Idx>;
164 constexpr bool isHere = std::is_same_v<ModeHere, Mode>;
165
166 if constexpr (isHere)
167 {
168 auto* state = manager.template getStateGroupOf<SelfTy>();
169 if (state)
170 {
171 OptionalTy& opt = std::get<OptionalTy>(state->modeStates);
172 if (!opt.has_value())
173 {
174 opt.emplace(); // all StateTy must be default-contructible :)
175 }
176
177 StateTy& stateHere = *opt;
178 substate = &stateHere;
179 }
180 }
181 });
182
183 assert(substate != nullptr && "this should not have happened!");
184 return substate;
185 }
186
187 //
188 // navigation
189 //
190
192 static constexpr bool isGroupManager = false;
194 static constexpr bool isModeManager = true;
195
197 static void next_mode(auto& ctx)
198 {
199 uint8_t modeIdBefore = ctx.get_active_mode(nbModes);
200 ctx.set_active_mode(modeIdBefore + 1, nbModes);
201 }
202
204 static void enter_mode(auto& ctx)
205 {
206 // restore brigthness before entering a mode
207 ctx.lamp.setBrightness(logic::brightness::get_saved_brightness(), false, false, true);
208
209 // set ramps if they exist
210 uint8_t modeIdAfter = ctx.get_active_mode(nbModes);
211 ctx.state.load_ramps(ctx, modeIdAfter);
212
213 // start new mode we switched to
214 dispatch_mode(ctx, [](auto mode) {
215 mode.on_enter_mode();
216 });
217 }
218
220 static void quit_mode(auto& ctx)
221 {
222 // save ramps if they exist
223 uint8_t modeIdBefore = ctx.get_active_mode(nbModes);
224 // save ramps if they exist
225 ctx.state.save_ramps(ctx, modeIdBefore);
226
227 // start new mode we switched to
228 dispatch_mode(ctx, [](auto mode) {
229 mode.on_exit_mode();
230 });
231 }
232
233 //
234 // all the callbacks
235 //
236
238 static void loop(auto& ctx)
239 {
240 dispatch_mode(ctx, [](auto mode) {
241 mode.loop();
242 });
243 }
244
246 static void sunset_update(auto& ctx, float progress)
247 {
248 dispatch_mode(ctx, [&](auto mode) {
249 mode.sunset_update(progress);
250 });
251 }
252
254 static void brightness_update(auto& ctx, brightness_t brightness)
255 {
256 dispatch_mode(ctx, [&](auto mode) {
257 mode.brightness_update(brightness);
258 });
259 }
260
262 static void custom_ramp_update(auto& ctx, uint8_t rampValue)
263 {
264 dispatch_mode(ctx, [&](auto mode) {
265 mode.custom_ramp_update(rampValue);
266 });
267 }
268
270 static bool custom_click(auto& ctx, uint8_t nbClick)
271 {
272 bool retVal = false;
273 dispatch_mode(ctx, [&](auto mode) {
274 retVal = mode.custom_click(nbClick);
275 });
276 return retVal;
277 }
278
280 static bool custom_hold(auto& ctx, uint8_t nbClickAndHold, bool isEndOfHoldEvent, uint32_t holdDuration)
281 {
282 bool retVal = false;
283 dispatch_mode(ctx, [&](auto mode) {
284 retVal = mode.custom_hold(nbClickAndHold, isEndOfHoldEvent, holdDuration);
285 });
286 return retVal;
287 }
288
290 static void power_on_sequence(auto& ctx)
291 {
292 foreach_mode<true>(ctx, [](auto mode) {
293 mode.power_on_sequence();
294 });
295 }
296
298 static void power_off_sequence(auto& ctx)
299 {
300 foreach_mode<true>(ctx, [](auto mode) {
301 mode.power_off_sequence();
302 });
303 }
304
306 static void write_parameters(auto& ctx)
307 {
308 foreach_mode<true>(ctx, [](auto mode) {
309 mode.write_parameters();
310 });
311 }
312
314 static void read_parameters(auto& ctx)
315 {
316 foreach_mode<true>(ctx, [](auto mode) {
317 mode.read_parameters();
318 });
319 }
320
322 static void user_thread(auto& ctx)
323 {
324 dispatch_mode(ctx, [](auto mode) {
325 mode.user_thread();
326 });
327 }
328};
329
335template<typename... Modes> using GroupFor = GroupTy<std::tuple<Modes...>>;
336
337} // namespace lampda::modes
338
339#endif
Define assertions helpers.
ContextTy and associated definitions.
modes::ManagerFor and associated definitions
Basic interface types to implement custom user modes.
brightness_t get_saved_brightness()
Return the saved brightness level. This shoudl be the prefered option in all computations.
Definition: brightness_handle.cpp:64
Contains basic interface types to implement custom user modes.
Definition: control_fixed_modes.hpp:12
GroupTy< std::tuple< Modes... > > GroupFor
Group together many different modes::BasicMode.
Definition: group_type.hpp:335
static auto context_as(auto &ctx)
Bind provided context to another modes::BasicMode.
Definition: context_type.hpp:25
void brightness_update(const brightness_t brightness)
Called when the system changes the LED strip brightness.
Definition: default_behavior.hpp:56
void user_thread()
Called at each tick of the secondary thread.
Definition: default_behavior.hpp:159
void read_parameters()
Called when system wants to read parameters from filesystem.
Definition: default_behavior.hpp:93
void power_on_sequence()
Called when the system powers on (must be non blocking function!)
Definition: default_behavior.hpp:31
void write_parameters()
Called when system wants to write parameters to filesystem.
Definition: default_behavior.hpp:87
void power_off_sequence()
Called when the system powers off (must be non blocking function!)
Definition: default_behavior.hpp:42
void loop()
Called at each tick of the main loop.
Definition: default_behavior.hpp:139
uint16_t brightness_t
Define the type of the brightness parameters.
Definition: constants.h:147
Definition: group_type.hpp:127
std::array< uint8_t, nbModes > customIndexMemory
Store the active index for each mode.
Definition: group_type.hpp:130
std::array< uint8_t, nbModes > customRampMemory
Store the ramp value for each mode.
Definition: group_type.hpp:129
AllStatesTy modeStates
Store the current group state.
Definition: group_type.hpp:128
void LMBD_INLINE save_ramps(auto &ctx, uint8_t modeId)
If a mode signaled that it has a ramp, save it.
Definition: group_type.hpp:133
void LMBD_INLINE load_ramps(auto &ctx, uint8_t modeId)
If a mode signaled that it has a ramp, load it.
Definition: group_type.hpp:144
Define templated tools to analyze the manager objects.