Skip to content

ControlModule

Source: ControlModule.h

ControlModule

class ControlModule
src/core/system/ControlModule.h:48

Inherits: MoonModule, ListSource

Puts the device into a named state, and is where anything wanting to do that will live.

Its first capability is presets: a preset is a file, saving writes one, selecting reads it. Top-level by necessity, since a preset reaches across the containers it captures from. Not to be confused with the light presets module, a library of fixture wirings. That is a profile, where this is a device state.

Public Methods

inline void addSurface(ControlSurface * s) : Attach a surface.

inline void resendTo(ControlSurface * s) : Push EVERY value to one surface, whatever the mirror last sent.

inline void removeSurface(ControlSurface * s) : Detach.

inline void applyEncoderDelta(uint8_t index, int8_t delta) : A TURN, not a position.

inline void setTouched(SurfaceControl kind, uint8_t index, bool held) : A hand is on this control.

inline void mirrorToSurfaces() : Push changed values to every attached surface.

virtual inline void tick1s() override : The once-a-second tick for housekeeping, which by default ticks the children.

virtual inline void defineControls() override : Declare the strip, the switches, the encoders, the faders, the pads and the save form, in that order: the declaration order is the render order.

virtual inline void setup() override : Take the surface seat, ensure the folder, and scan what is already in it.

virtual inline void onControlChanged(const char * controlName) override : save writes the current state; a fader drives whatever it targets; the rest is an assignment.

virtual inline uint8_t listRowCount() const override : How many presets the folder holds.

virtual inline void writeListRow(JsonSink & sink, uint8_t row) const override : Append one preset's row: its name, what it carries, and which roles it holds now.

virtual inline void writeListRowDetail(JsonSink & sink, uint8_t row) const override : The expanded row:

inline uint8_t roleOf(uint8_t row) const : The one role this preset carries, or kCaptureCount if the file names none or several.

inline bool isLookOnly(uint8_t row) const : Whether this preset is a pure look, which with one role each means its role is Effects.

inline const char * presetName(uint8_t row) const : The preset's name, or null for an out-of-range row.

inline uint8_t presetCount() const : How many presets are on the device.

inline uint32_t presetsRevision() const : Monotonic revision of the preset SET, bumped by every save, delete, rename and rescan.

inline bool applyLookByName(const char * name) : Apply a LOOK by name.

inline const char * currentLook() const : The look applied most recently, or "" when none is.

virtual inline bool isEditableList() const override : Editable, since a pad is renamed and deleted from the surface.

virtual inline bool persistsList() const override : The preset FOLDER is the state; rescan() rebuilds these rows at setup.

virtual inline bool listAsPads() const override : Presets are triggered far more than they are edited, so the rows render as a grid of pads:

virtual inline uint8_t listGridCols() const override : The surface's shape.

virtual inline uint8_t listGridRows() const override : How many rows the surface renders.

virtual inline bool deleteListRow(uint32_t id) override : Deleting a row deletes the file.

inline const char * surfaceTarget(uint8_t index) const : A fader drives its target through Scheduler::setControl, the same domain-neutral primitive.

inline const char * switchTarget(uint8_t index) const : What a switch drives, as "Module.control", or null when it drives nothing yet.

inline const char * encoderTarget(uint8_t index) const : What an encoder drives, as "Module.control", or null when it drives nothing yet.

inline void driveSwitch(uint8_t index) : Drives whatever switchTarget declares.

inline void followTargets() : Read every bound control back, so a surface FOLLOWS what it drives.

inline bool pullTarget(SurfaceControl kind, uint8_t index, uint8_t & value) : One control's read-back.

inline void driveSurface(SurfaceControl kind, uint8_t index) : Write a surface control's value onto whatever it targets.

inline void driveFader(uint8_t index) : Write one fader's value onto whatever it targets.

inline void driveEncoder(uint8_t index) : Write one encoder's value onto whatever it targets.

inline void writeStrip(const char * fmt, ...) : Put text on the display strip, and start its five-second life.

inline void settleStrip() : Settle the strip once nothing has happened for a while:

inline void showOnStrip(const char * module, const char * control, uint8_t value) : Write the last change onto the strip, an option's name rather than its index.

virtual inline bool moveListRow(uint32_t id, uint8_t to) override : Reorder:

virtual inline bool setListRowField(uint32_t id, const char * field, const char * valueJson) override : The row's editable fields carry the two actions a preset row needs.

Public Static Attributes

constexpr const char * kPresetDir = "/.config/presets" : Where the preset files live.

constexpr uint8_t kGridCols = 8 : The surface is a fixed grid, so a pad has a POSITION rather than a place in a list:

constexpr uint8_t kGridRows = 8 : How many rows the pad grid has.

constexpr uint8_t kMaxPresets = * : How many presets the grid holds, which is every cell.

constexpr uint8_t kMaxNameLen = 32 : The longest preset name, which becomes a file name.

constexpr const char * kCapturable = {"Layouts", "Effects", "Drivers", "Services"} : The top-level subtrees a preset can carry.

constexpr const char * kCaptureRole = {"layout", "effects", "driver", "service"} : What each capturable subtree covers, named after the CONTAINER rather than after a module.

constexpr uint8_t kCaptureCount = sizeof() / sizeof([0])

constexpr uint8_t kEffectsRole = 1 : Index of "Effects" within kCapturable, the role a pure look occupies.

constexpr uint8_t kFaderCount = 8 : How many faders the bank shows.

constexpr uint8_t kEncoderCount = 8 : A row of rotary encoders above the pads, mirroring where both the X-Touch and the QCon put.

constexpr uint8_t kSwitchCount = 8 : The switch row.

constexpr uint32_t kStripHoldMs = 5000 : How long the strip holds what it was told, before falling back to the device's name.

Public Static Methods

static inline ControlModule * active() : The boot ControlModule (exactly one exists).

static inline const ControlDescriptor * findControl(const char * moduleName, const char * controlName) : A target control's descriptor, for its type and bounds.

static inline const char * deviceName() : The device's name, read through the control system rather than by reaching into SystemModule:

static inline bool paletteNameAt(uintptr_t optionsFn, uint8_t index, char * out, size_t outLen) : Write the last thing that happened onto the display strip.

More info

The three banks read as one desk

Switches, encoders and faders are declared in that order, and the declaration order is the render order. The preset grid sits after them rather than between. Eight rows of pads pushed the faders off the bottom of the card, so reaching them meant scrolling past the bank they belong with.

What a preset captures

One top-level subtree, recorded in the file, so applying one is never a surprise. That choice decides portability, a look carrying nothing about the hardware. So a look applies on any board, where a driver preset carries pins and is specific.

Why files

One file per preset, with free-form names. Deleting one is deleting a file, and backing them up is copying a folder. Numbered slots would have bought a fixed grid at the cost of both. The bytes inside are what the persistence engine writes, so restore reuses that engine.