Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 23 additions & 19 deletions firmware/patternflow/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,33 +78,37 @@ constexpr float EULER = 2.71828182845904523536f;
// pattern with PFCanvas::setFrame(). See README.md.
// Running a non-stock panel? Please report how it went, working or not:
// https://github.com/engmung/Patternflow/issues/224
#define PANEL_GEOM_128x64_SINGLE 1 // one 128×64 module (stock)
#define PANEL_GEOM_64x64_SINGLE 2 // one 64×64 module
#define PANEL_GEOM_64x64_CHAIN2 3 // two 64×64 modules daisy-chained → 128×64
//
// The ids and the sizes come from shared/constants.json, which the site
// reads too.
#include "src/core_shared.h"
#define PANEL_GEOM_128x64_SINGLE PF_SHARED_PANEL_GEOM_128x64_SINGLE // one 128×64 module (stock)
#define PANEL_GEOM_64x64_SINGLE PF_SHARED_PANEL_GEOM_64x64_SINGLE // one 64×64 module
#define PANEL_GEOM_64x64_CHAIN2 PF_SHARED_PANEL_GEOM_64x64_CHAIN2 // two 64×64 modules daisy-chained → 128×64

// #define PANEL_GEOMETRY PANEL_GEOM_64x64_CHAIN2
#ifndef PANEL_GEOMETRY
#define PANEL_GEOMETRY PANEL_GEOM_128x64_SINGLE
#define PANEL_GEOMETRY PF_SHARED_PANEL_GEOM_DEFAULT
#endif

#if PANEL_GEOMETRY == PANEL_GEOM_64x64_SINGLE
#define PANEL_PHYS_W 64
#define PANEL_PHYS_H 64
#define PANEL_CHAIN 1
#define PANEL_RES_W 64
#define PANEL_RES_H 64
#define PANEL_PHYS_W PF_SHARED_PANEL_GEOM_64x64_SINGLE_PHYS_W
#define PANEL_PHYS_H PF_SHARED_PANEL_GEOM_64x64_SINGLE_PHYS_H
#define PANEL_CHAIN PF_SHARED_PANEL_GEOM_64x64_SINGLE_CHAIN
#define PANEL_RES_W PF_SHARED_PANEL_GEOM_64x64_SINGLE_RES_W
#define PANEL_RES_H PF_SHARED_PANEL_GEOM_64x64_SINGLE_RES_H
#elif PANEL_GEOMETRY == PANEL_GEOM_64x64_CHAIN2
#define PANEL_PHYS_W 64
#define PANEL_PHYS_H 64
#define PANEL_CHAIN 2
#define PANEL_RES_W 128
#define PANEL_RES_H 64
#define PANEL_PHYS_W PF_SHARED_PANEL_GEOM_64x64_CHAIN2_PHYS_W
#define PANEL_PHYS_H PF_SHARED_PANEL_GEOM_64x64_CHAIN2_PHYS_H
#define PANEL_CHAIN PF_SHARED_PANEL_GEOM_64x64_CHAIN2_CHAIN
#define PANEL_RES_W PF_SHARED_PANEL_GEOM_64x64_CHAIN2_RES_W
#define PANEL_RES_H PF_SHARED_PANEL_GEOM_64x64_CHAIN2_RES_H
#else
#define PANEL_PHYS_W 128
#define PANEL_PHYS_H 64
#define PANEL_CHAIN 1
#define PANEL_RES_W 128
#define PANEL_RES_H 64
#define PANEL_PHYS_W PF_SHARED_PANEL_GEOM_128x64_SINGLE_PHYS_W
#define PANEL_PHYS_H PF_SHARED_PANEL_GEOM_128x64_SINGLE_PHYS_H
#define PANEL_CHAIN PF_SHARED_PANEL_GEOM_128x64_SINGLE_CHAIN
#define PANEL_RES_W PF_SHARED_PANEL_GEOM_128x64_SINGLE_RES_W
#define PANEL_RES_H PF_SHARED_PANEL_GEOM_128x64_SINGLE_RES_H
#endif

#if PANEL_RES_W != (PANEL_PHYS_W * PANEL_CHAIN)
Expand Down
7 changes: 5 additions & 2 deletions firmware/patternflow/net_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
#include "patternflow_secrets.h"
#endif

#include "src/core_shared.h"

// ── Wi-Fi ────────────────────────────────────────────────────────────
// Whether the panel has a radio at all. 0 makes a USB-only instrument:
// everything network-side (console, OTA, every feature that dials out)
Expand Down Expand Up @@ -190,7 +192,8 @@
// it into virtual knob deltas (applyLaneMotion), so EVERY encoder-driven
// pattern reacts with no per-pattern code. This is how many knob clicks a
// full 0..1 swing maps to. Higher = stronger response. No per-frame clamp,
// so the value tracks without lag.
// so the value tracks without lag. The default is a parameter's whole range,
// two turns of 24 detents (src/core_shared.h).
//
// The old name is honoured below because a firmware built elsewhere may
// already set it in its overrides.h, and a rename that silently ignores
Expand All @@ -199,6 +202,6 @@
#ifdef PF_AUDIO_VIRTUAL_KNOB_SCALE
#define PF_LANE_MOTION_SCALE PF_AUDIO_VIRTUAL_KNOB_SCALE
#else
#define PF_LANE_MOTION_SCALE 48.0f
#define PF_LANE_MOTION_SCALE ((float)(PF_SHARED_DETENTS_PER_TURN * PF_SHARED_TURNS_PER_FULL_RANGE))
#endif
#endif
2 changes: 1 addition & 1 deletion firmware/patternflow/patternflow.ino
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ bool updateDirty = false;
// loop() draws it. -1 when nothing is being received.
volatile int uploadPctShown = -1;

const uint32_t MODE_HOLD_MS = 1000;
const uint32_t MODE_HOLD_MS = PF_SHARED_LONG_PRESS_MS;
const uint32_t BRIGHTNESS_IDLE_MS = 5000;
// How long the value has to be still before it is written to NVS - the
// console's slider sends a step for every pixel of a drag.
Expand Down
9 changes: 6 additions & 3 deletions firmware/patternflow/src/core_bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@

#include <Arduino.h>
#include "core_encoders.h" // InputFrame
#include "core_shared.h"

// The wire scale of an absolute channel: 0..PF_BUS_MAX, integer. Everything
// that writes the bus — MQTT param/1..4, POST /api/params, a .pfs cue, a MIDI
// CC — speaks this scale, and the site's Director bakes to it
// (BUS_WIRE_MAX in web/src/lib/pattern/controls.ts). abi/pf_params.h clamps
// to the same literal and cannot be changed to this name: the ABI is frozen.
#define PF_BUS_MAX 1000
// The number is BUS_MAX in shared/constants.json, and check:shared holds the
// ABI's literal to it.
#define PF_BUS_MAX PF_SHARED_BUS_MAX

namespace PatternflowBus {

Expand Down Expand Up @@ -87,9 +90,9 @@ inline void applyRemoteParam(int index, long value) {
if (diff != 0) {
const int32_t acc =
__atomic_add_fetch(&clickResidual[index], (int32_t)diff, __ATOMIC_RELAXED);
const int32_t d = acc / 10; // truncates toward zero, both signs
const int32_t d = acc / PF_SHARED_BUS_UNITS_PER_CLICK; // truncates toward zero, both signs
if (d != 0) {
__atomic_fetch_sub(&clickResidual[index], d * 10, __ATOMIC_RELAXED);
__atomic_fetch_sub(&clickResidual[index], d * PF_SHARED_BUS_UNITS_PER_CLICK, __ATOMIC_RELAXED);
__atomic_fetch_add(&pendingDelta[index], d, __ATOMIC_RELAXED);
}
}
Expand Down
13 changes: 9 additions & 4 deletions firmware/patternflow/src/core_encoders.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <Arduino.h>
#include <Preferences.h>
#include "config.h"
#include "core_shared.h"

volatile long encPos[4] = {0, 0, 0, 0}; // sub-steps; 4 per detent
volatile uint8_t encState[4] = {0, 0, 0, 0}; // last ACCEPTED (A<<1)|B
Expand Down Expand Up @@ -73,7 +74,9 @@ void IRAM_ATTR isr4() { handleEncoder(3, ENC4_A, ENC4_B); }
// (namespace "pf_knobs"), set from the /knobs page (core_knobs_http.h).
inline bool knobInvert[4] = {INVERT_ENCODER != 0, INVERT_ENCODER != 0,
INVERT_ENCODER != 0, INVERT_ENCODER != 0};
inline int knobSubSteps[4] = {4, 4, 4, 4}; // edges per click: 4, 2 or 1
// Edges per click: 4, 2 or 1.
inline int knobSubSteps[4] = {PF_SHARED_EDGES_PER_DETENT, PF_SHARED_EDGES_PER_DETENT,
PF_SHARED_EDGES_PER_DETENT, PF_SHARED_EDGES_PER_DETENT};
// A settings change must not move a knob. The click count carries on from
// where it was, counting the edges since the change in the new direction
// and at the new size, so the frame's delta stays zero across a save.
Expand All @@ -86,7 +89,9 @@ inline long getClicks(int idx) {
return knobClickBase[idx] + rel / knobSubSteps[idx];
}

inline int clampSubSteps(int v) { return (v == 1 || v == 2 || v == 4) ? v : 4; }
inline int clampSubSteps(int v) {
return (v == 1 || v == 2 || v == 4) ? v : PF_SHARED_EDGES_PER_DETENT;
}

// Call on the frame task (the frame reads the same counters).
inline void setKnobSettings(int idx, bool invert, int subSteps) {
Expand Down Expand Up @@ -140,7 +145,7 @@ struct Button {
bool pressed() {
bool cur = digitalRead(pin);
uint32_t now = millis();
if (cur != lastState && (now - lastChangeMs) > 50) {
if (cur != lastState && (now - lastChangeMs) > PF_SHARED_BUTTON_DEBOUNCE_MS) {
lastState = cur;
lastChangeMs = now;
if (cur == LOW) {
Expand All @@ -166,7 +171,7 @@ struct Button {
return c;
}

bool longPressed(uint32_t threshold = 1000) {
bool longPressed(uint32_t threshold = PF_SHARED_LONG_PRESS_MS) {
if (!isDown()) return false;
uint32_t now = millis();
if (!longPressFired && (now - pressStartMs) > threshold) {
Expand Down
3 changes: 2 additions & 1 deletion firmware/toolchain/check_midi.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ def main():
compiler, env = compiler_environment()
with tempfile.TemporaryDirectory(prefix='patternflow-midi-') as directory:
work = Path(directory)
for name in ('features/midi/core_midi.h', 'features/midi/midi_queue.h', 'src/core_bus.h'):
for name in ('features/midi/core_midi.h', 'features/midi/midi_queue.h', 'src/core_bus.h',
'src/core_shared.h'):
dest = work / name
dest.parent.mkdir(parents=True, exist_ok=True)
dest.write_bytes((ROOT / 'firmware/patternflow' / name).read_bytes())
Expand Down
Loading