BaptisteHudyma / Lamp-Da

An embedded program to control an indexable color strip wrapped around a cylinder. Based on Seed nRF52840 Sense module
GNU General Public License v3.0
2 stars 1 forks source link

Introduce a "mode manager" to abstract software from hardware #36

Closed deuxksix closed 9 hours ago

deuxksix commented 1 day ago

This is two contributions:

  1. one that expand simulator to support most of the user/functions.h behaviors
  2. one that rewrites all the "indexable" modes using a "mode manager" -- see user/indexable_functions.cpp

This goes towards separating the software from the hardware and is thus fully testable with make simulator

(note that the simulator uses the space bar as lamp button interaction)


There is some preliminary documentation written, but not exhaustive:

2024-11-14_18-36 2024-11-14_18-30 2024-11-14_18-30_1

The overall abstraction, is that each mode have callbacks defined in a similar fashion to user/functions.h:

#ifndef MY_CUSTOM_MODE_H
#define MY_CUSTOM_MODE_H

struct [MyCustomMode](https://github.com/BaptisteHudyma/Lamp-Da/compare/structMyCustomMode.html) : public [modes::FullMode](https://github.com/BaptisteHudyma/Lamp-Da/compare/structmodes_1_1FullMode.html) {

  static void loop(auto& ctx) { }
  static void reset(auto& ctx) { }

  // only if hasBrightCallback
  static void brightness_update(auto& ctx, uint8_t brightness) { }

  // only if hasCustomRamp
  static void custom_ramp_update(auto& ctx, uint8_t rampValue) { }

  // only if hasButtonCustomUI
  static bool custom_click(auto& ctx, uint8_t nbClick) {
    return false;
  }

  static bool custom_hold(auto& ctx,
                          uint8_t nbClickAndHold,
                          bool isEndOfHoldEvent,
                          uint32_t holdDuration) {
    return false;
  }

  // only if hasSystemCallbacks
  static void power_on_sequence(auto& ctx) { }
  static void power_off_sequence(auto& ctx) { }
  static void read_parameters(auto& ctx) { }
  static void write_parameters(auto& ctx) { }

  // only if requireUserThread
  static void user_thread(auto& ctx) { }

  // keep only if customized
  struct StateTy { };

  // keep only the ones you need (= true)
  static constexpr bool hasBrightCallback = false;
  static constexpr bool hasCustomRamp = false;
  static constexpr bool hasButtonCustomUI = false;
  static constexpr bool hasSystemCallbacks = false;
  static constexpr bool requireUserThread = false;
}

#endif

This enable short definitions of modes, such as:

/// Rainbow fixed colors ramp mode
struct RainbowMode : public modes::FullMode {
  static void loop(auto& ctx) {
    const float index = ctx.get_active_custom_ramp();
    const float hue = (index / 256.f) * 360.f;
    uint32_t color = utils::hue_to_rgb_sinus(hue);

    ctx.fill(color);
  }
};

Modes to be listed inside a « mode group » as in the example below:

using FixedModes = modes::GroupFor<
  fixed::KelvinMode,
  fixed::RainbowMode
>;

Groups to be listed inside a global « mode manager » as in the example below:

#include "src/modes/default/fixed_modes.h"
#include "src/modes/legacy/legacy_modes.h"

using ManagerTy = modes::ManagerFor<
    modes::FixedModes,
    modes::legacy::CalmModes,
    modes::legacy::PartyModes
  >;

Which is used to implement user/indexable_functions.cpp callbacks.


As feature, there is new user actions such as:

There is also late-initialization of StateTy state structure of modes, meaning it is build only on the first instantiation of the mode (and not on the initialization of the program).


There is still on-going works, to be completed in further pull requests:

deuxksix commented 11 hours ago

pushed requested changes

deuxksix commented 10 hours ago

have refactored new .h into new .hpp files to highlight their unholy C++ nature

BaptisteHudyma commented 9 hours ago

This is great work, thanks a lot. I will apply this to the constant and cct types