JMT Prop Addons

Optional ProffieOS extensions for chassis, charging, gestures, and favorites

JMT Prop Addons is a collection of optional ProffieOS extensions. The included wrapper layers new behavior on top of the saber_fett263_buttons prop without modifying that prop or any core ProffieOS source. The original files stay untouched. The goal is to add features to an already excellent prop while preserving everything that makes it work.

Each feature is opt-in via a #define. Charge detection, chassis detection, gesture-based preset switching while the chassis is removed, blade ID-based blade detect (OS8+), and a favorites system can be enabled independently or combined as needed. Nothing activates unless you explicitly enable it in a config.

Easiest path: use JMT Studio's Add JMT Features button on any installed ProffieOS version. The wrapper, helper headers, and config entries are placed for you and stay in sync with future updates.

Setup

Add this include inside your config's CONFIG_PROP block. The wrapper internally defines saber_fett263_buttons as its base, so this line replaces your existing prop include. Only one prop can be active in a build, so leaving another #include "props/..." in place will cause a compile error.

#ifdef CONFIG_PROP
#include "../props/jmt_fett263_wrapper.h"
#endif

From there, opt into any feature below by adding its #define to your config. All defines and tunables are listed inside each feature.

Optional: enable Style Add-ons

If any of your blade styles use ChargeFullPropF or PixelRelay (see Style Add-ons), add the matching include inside your config's CONFIG_PRESETS block. These must be processed after the prop include so the shared symbols are available. Add only the includes for the add-ons your styles actually use.

#ifdef CONFIG_PRESETS
#include "../functions/charge_full_prop.h"
#include "../styles/pixel_relay.h"
#endif

Using these with JMT Studio's Style Library

When you add a blade style that references ChargeFullPropF or PixelRelay through JMT Studio's Style Library, Studio writes the style entry inside an #ifdef guard keyed to the matching add-on header. A missing include silently skips the wrapped entries instead of breaking your build. The includes above are what activate them. This also means a Style Library shared across users on older ProffieOS versions or older add-on releases will not error out; entries that depend on a not-yet-installed add-on simply do not compile in until the matching include is present.

Files included with the addons

JMT Studio's Add JMT Features button places these files for you in the right directories. It does not edit your config, so the #include lines above still need to be added by hand. If you are installing manually from GitHub, make sure each file lives in the directory shown.

Features

Chassis Detection Detect when the chassis is removed or inserted, with optional swing-to-ignite suppression.
Enable #define CHASSIS_DETECT_PIN <pin> (or use the BladeID range alternative below)

Adds chassis-presence detection to the prop. State changes play chassisin.wav or chassisout.wav and cancel any pending favorite-reset hold action (if enabled). While the chassis is out and the saber is off, swing-to-ignite is suppressed so the saber will not light up just from being handled. Twist on/off remains available if enabled, or may be naturally suppressed by blade-detect behavior depending on the install.

Wiring options

Two mutually exclusive ways to detect the chassis. Both produce identical downstream behavior: same sounds, same gesture gating, same wake handling.

1. Dedicated detect pin. The original method. Uses a free GPIO pin on the board, wired to a contact that closes when the chassis is inserted.

  • Default (active LOW): uses INPUT_PULLUP. Chassis detected when the pin is shorted to GND.
  • Active HIGH: add #define CHASSIS_DETECT_PIN_HIGH. Requires an external pulldown so the pin sits LOW when no chassis is present.

2. BladeID resistance (no detect pin). Reuses the existing BladeID line and saves a physical wire. Detection comes from the BladeID resistance reading instead of a dedicated pin.

#define JMT_CHASSIS_DETECT_RANGE <min>,<max>

When the raw BladeID reading falls inside the configured range, the wrapper treats the chassis as OUT. Requires ENABLE_POWER_FOR_ID, BLADE_ID_SCAN_MILLIS, and BLADE_ID_TIMES. Latency is one BladeID scan cycle (scan-driven, not edge-triggered).

The range must not overlap any BladeConfig ohm entry. How it relates to NO_BLADE_ID_RANGE depends on how blade presence is detected on this build:

  • BladeID-based blade detect (JMT_BLADE_DETECT): NO_BLADE_ID_RANGE is the standard OS macro that classifies "no blade present" readings. The chassis-detect range typically sits as a subset inside it, carving out the chassis-OUT portion. The wrapper handles the OS's no-blade remapping internally.
  • Wired blade detect (BLADE_DETECT_PIN): blade presence comes from the pin, so NO_BLADE_ID_RANGE is not required for this feature. The chassis-detect range just needs to sit above the highest in-chassis BladeID reading you will see.
Important: the range detects chassis OUT, not chassis IN

Chassis IN has two valid BladeID readings (the blade's own resistance with a blade in, or the chassis-only resistance with no blade in), which sit far apart. Detecting OUT is simpler because open-circuit gives one expected reading zone. Anything outside the configured range is treated as chassis IN by absence, which is also the safer fallback if a reading drifts unexpectedly.

Tuning the BladeID range

Measure your specific saber's chassis-out (open-circuit), chassis-in-no-blade (chassis resistance only), and the BladeID reading of each blade you plan to use. Do not guess. Open-circuit is the most variable reading; pad generously on the high end.

JMT_CHASSIS_DETECT_RANGE defines the band the wrapper treats as chassis OUT (literal min, max):

  • Min: above the highest non-chassis-out reading. In practice that is chassis-in-no-blade, since blade-in readings normally sit lower. Anything below this min is treated as chassis IN by absence.
  • Max: generously above the chassis-out reading. Open-circuit readings drift due to capacitance, board layout, and ambient noise. If the saber has ever measured X on chassis-out, set max to X plus 20 to 30 percent.

If you are also configuring NO_BLADE_ID_RANGE (the typical BladeID-based blade-detect build):

  • Min: a bit below the chassis-in-no-blade reading. A small pad is fine; the chassis-in reading is the stable one.
  • Max: match the upper bound of JMT_CHASSIS_DETECT_RANGE. A reading higher than this max falls outside the no-blade band, the OS treats it as a mystery blade, and the chassis state can flip erratically.
Example (NO_BLADE_ID_RANGE and JMT_CHASSIS_DETECT_RANGE)
#define NO_BLADE_ID_RANGE 20000, 400000
#define JMT_CHASSIS_DETECT_RANGE 40000, 400000

Your specific values will depend on your hardware. JMT_CHASSIS_DETECT_RANGE marks the chassis-OUT band, not chassis-IN: anything below it counts as chassis present. In this build chassis-in-no-blade is around 22848, so NO_BLADE_ID_RANGE starts at 20000 to include it, and JMT_CHASSIS_DETECT_RANGE starts at 40000 to leave clean buffer above that before chassis-OUT begins. The shared upper bound (400000) absorbs open-circuit drift.

Options

  • JMT_CHASSIS_WAKE: wake motion detection on chassis state change. Helpful if the board is in a deep idle state.

SD card sounds

Place chassisin.wav and chassisout.wav in your saber's common/ folder on the SD card. You can use any compatible WAVs, or preview and grab the defaults below.

Pin-based detection includes a fixed 30ms software debounce. BladeID-based detection is scan-driven with latency equal to BLADE_ID_SCAN_MILLIS. No tuning is normally required for the pin method; the BladeID method needs the range tuning above.

Charge Detection Hardware-level detection of when the saber is plugged in to a charger.
Enable #define CHARGE_DETECT_PIN <pin>

Required for all charge-related features below. When the charger is detected the prop plays chargebegin.wav, cancels any pending favorite reset, and prevents normal MOTION_TIMEOUT / IDLE_OFF_TIME behavior (if enabled) while charging so charge styles remain active and visible.

A silent boot-time sync prevents chargebegin.wav from playing if charge detect is already active at startup.

Two global flags are tracked and declared extern in common/charge_state.h:

  • g_charging: true while the charger is detected. Available to prop and config code.
  • g_charge_full: true once the battery has been at full for the configured dwell time. Blade styles can react to this via the bundled ChargeFullPropF helper (see Style Helpers).

SD card sound

Place chargebegin.wav in your saber's common/ folder on the SD card. The wrapper does not install this for you. You can use any compatible WAV, or preview and grab the default below.

Active LOW input using INPUT_PULLUP with fixed 30ms debounce.

Charge Full Tracking Reliable detection of when the battery has reached a stable full-charge state.
Enable Automatic when CHARGE_DETECT_PIN is defined

Monitors battery level and determines when charging is considered complete. Uses two thresholds and a dwell timer to avoid rapid full/not-full toggling near 100%. Drives the g_charge_full global, which blade styles can consume via the included ChargeFullPropF style helper (see Style Helpers).

Tunables(32768 scale - 0–100%)

MacroDefaultMeaning
CHARGE_FULL_ENTER32700Level required before full-charge dwell timing begins
CHARGE_FULL_EXIT32000Drop-out threshold. Must be below ENTER.
CHARGE_FULL_DWELL_MS30000How long ENTER must be held before declaring full

When charging is no longer detected, the full state and dwell timer are cleared immediately.

Charge Complete Announcement Play a sound effect when the battery reaches full charge.
Enable #define JMT_CHARGE_COMPLETE_ANNOUNCE

Plays chargecomplete.wav once when g_charge_full first becomes true (see Charge Full Tracking for the timing). Resets when charging is no longer detected, allowing the next charge cycle to announce again.

SD card sound

Place chargecomplete.wav in your saber's common/ folder on the SD card. You can use any compatible WAV, or preview and grab the default below.

Requires: CHARGE_DETECT_PIN.

Charge Button Lockout Disable button input while charging so a bumped button cannot ignite a docked saber.
Enable #define JMT_CHARGE_LOCKOUT

While charging is active, this feature suppresses nearly all button events. The single exception is BUTTON_POWER, which announces battery level instead of igniting the saber (rate limited to once every 300ms).

If BLADE_DETECT_PIN is defined, blade-detect events are also ignored during charging so blade-detect events cannot trigger behaviors while charging.

Requires: CHARGE_DETECT_PIN.

Recommendation: also enable FETT263_SAVE_GESTURE_OFF so prior gesture state is fully preserved across a charge cycle. The build will succeed without it, but a warning is emitted.

Charge Style Preset Switch to a dedicated charging preset when charging, then reboot when no longer charging.
Enable #define JMT_CHARGE_STYLE_PRESET

Treats the last preset in your preset array as a dedicated charge preset. When charging is detected, this feature switches to that preset and triggers EFFECT_BOOT. When no longer charging, the board reboots.

Why a full reboot on unplug?

Normal preset switching does not re-run ProffieOS startup behavior such as font scanning, motion initialization, and boot effects. Rebooting guarantees a clean post-charge state and avoids subtle inconsistencies in motion and audio.

Tip: consistent boot audio

Charge-preset entry and unplug-reboot both play a boot sound. ProffieOS uses the font's boot.wav if present, falling back to font.wav otherwise. To give every font a dedicated boot sound, place a generic boot.wav in your saber's common/ folder. Fonts without their own will use it instead of falling back to font.wav.

Bonus behavior

If a user manually navigates and lands on the charge preset while not charging, this feature detects scroll direction and skips past it. The charge preset cannot be selected as a normal preset.

Requires: CHARGE_DETECT_PIN.

Roll-to-Change-Preset Preset navigation for removable chassis builds where buttons are inaccessible.
Enable #define JMT_ROLL_PRESETS

Designed primarily for removable chassis setups handled outside the hilt. While the chassis is out and the saber is not ignited, rolling it forward or backward through a large rotation changes the preset.

With the chassis held roughly horizontal (within ±7° of level), the feature captures a baseline roll and watches for large rotations. A positive roll delta beyond 170° advances to the next preset; a negative roll delta beyond 170° selects the previous preset. The baseline resets after each trigger so successive flips continue scrolling through presets.

Roll direction

  • Forward roll: emitter toward the left hand, speaker toward the right hand, rolling away from the user.
  • Reverse roll: opposite direction.

The threshold is intentionally set slightly below 180° so a full flip gesture remains reliable without requiring an exact angle boundary.

Active only when: saber not ignited and chassis removed.

Requires: CHASSIS_DETECT_PIN.

Mutually exclusive with: JMT_FLICK_PRESETS.

Flick-to-Change-Preset Pose-driven preset navigation for unconventional hilt geometry.
Enable #define JMT_FLICK_PRESETS

Designed primarily for removable chassis setups where presets must be changed without button access, but full roll gestures feel awkward or unnatural due to hilt shape, board orientation, or install geometry.

Unlike traditional roll gestures, this feature establishes a known neutral arm pose first. Optional pitch/roll offsets can calibrate that pose for curved hilts, angled chassis installs, or rotated board mounting, so preset navigation feels natural without changing the rest of ProffieOS motion behavior.

From the arm pose, twist right and return to center to advance presets. Twist left and return to center to move backward. The preset change is not committed until the chassis returns to the arm pose, which reduces accidental activations during handling.

When to choose flick over roll

  • Curved hilts (Count Dooku-style builds)
  • Crossguard sabers
  • Angled chassis installs
  • Rotated board orientations
  • Unconventional grip or emitter geometry
  • Accessibility-focused builds where large wrist rolls are uncomfortable

Gesture mechanics

Arm pose: pitch near 0°, roll near ±180°. Tolerance ±18° pitch, ±25° roll.

Twist pose: tolerance ±22° pitch, ±22° roll. Eligibility window opens 700ms after entering arm pose.

Commit: return to arm pose within 500ms after the twist pose.

Direction: roll near -90° then return selects the next preset. Roll near +90° then return selects the previous preset.

Optional tuning

JMT_PITCH_OFFSET and JMT_ROLL_OFFSET calibrate the flick gesture matcher after ORIENTATION_ROTATION has already been applied. They do not change the IMU orientation globally and do not affect other ProffieOS motion behavior.

Use these offsets when a rotated board or angled chassis makes your natural arm pose read somewhere other than pitch 0°, roll ±180°. The offsets shift only the flick preset target poses so your physical neutral position matches the gesture matcher.

MacroNotes
JMT_PITCH_OFFSET Degrees added to measured pitch for flick-preset matching. Requires ORIENTATION_ROTATION.
JMT_ROLL_OFFSET Degrees added to measured roll for flick-preset matching. Requires ORIENTATION_ROTATION.

Think of these as calibration offsets for this gesture only, not a replacement for ORIENTATION_ROTATION.

Active only when: saber not ignited and chassis removed.

Requires: CHASSIS_DETECT_PIN.

Mutually exclusive with: JMT_ROLL_PRESETS.

Software Blade Detect Blade insertion/removal via Blade ID, no detect pin needed.
Enable #define JMT_BLADE_DETECT

Uses the Blade ID scan result instead of a hardware detect pin. The prop considers the blade removed when the detected Blade ID resolves to NO_BLADE.

Behavior

On insertion:

  • Re-enables gesture control
  • Requests motion wake-up
  • Cancels any pending favorite-reset hold action

On removal:

  • Disables gesture control
  • Cancels any pending favorite-reset hold action

If FETT263_SAVE_GESTURE_OFF is defined, prior gesture state is saved on removal and restored on insertion. Otherwise gestures are force-enabled on insertion.

Blade-detect processing is skipped while charging when CHARGE_DETECT_PIN is defined and charging is active.

Required infrastructure

  • ENABLE_POWER_FOR_ID
  • BLADE_ID_SCAN_MILLIS > 0
  • BLADE_ID_TIMES > 0

ProffieOS 7.x with a custom no-blade ohm

If your BladeConfig array marks "no blade present" with a custom ohm value below the standard NO_BLADE constant (1e9), and you are on ProffieOS 7.x, add this define so the wrapper plays bladein.wav and bladeout.wav on blade swaps instead of font.wav:

#define JMT_NO_BLADE_VALUE <your no-blade ohm value>

On ProffieOS 8.0 or later, use the native NO_BLADE_ID_RANGE instead. If your BladeConfig already uses NO_BLADE as its no-blade ohm value (the default), this define is not needed on any version.

Mutually exclusive with: BLADE_DETECT_PIN.

Hardware Blade Detect Enhancements Additional behavior layered on standard hardware blade detect.
Enable Automatic when BLADE_DETECT_PIN is defined

If BLADE_DETECT_PIN is already present in your config, this feature adds two small behavior improvements:

  • Blade insertion and removal events cancel any pending favorite-reset hold action.
  • On blade insertion, a motion wake request is fired. No ignition and no sound. Useful for boards that have entered motion timeout or idle-off behavior.

Nothing additional to configure. No new macros required.

Mutually exclusive with: JMT_BLADE_DETECT.

Favorites System Mark presets as favorites, then jump between them with simple tilt gestures.
Enable Automatic (disabled on single-button builds)

A tilt-driven favorites system that lets a user mark presets and cycle through just those, without scrolling the full preset list. Triggered by AUX + EVENT_FIRST_HELD_LONG while the saber is off. The action depends on the saber's orientation when the trigger fires.

Tilt actions

OrientationAction
Pointing straight down (within ±5° of -90°)Arm favorites reset confirmation
Tilted up (beyond +5°)Jump to next favorite
Tilted down (beyond -5°, not the reset zone)Jump to previous favorite
Roughly level (within ±5°)Toggle current preset as favorite

Audio cues

  • Add favorite: one short 2kHz beep.
  • Remove favorite: two short 2kHz beeps.
  • List full: one long 2kHz beep.
  • List empty (on next/prev): five fast beeps.
  • Reset armed: three beeps plus mconfirm.wav and mdefault.wav.
  • Reset confirmed: two beeps plus mdefault.wav.
  • Reset cancelled or aborted: mcancel.wav.

Reset confirmation flow

  • BUTTON_POWER press confirms (clears favorites, writes empty file).
  • BUTTON_AUX press cancels.
  • All other input is ignored while reset confirmation is active.
  • Auto-cancels on chassis change, charge start, or blade-detect change.

Storage

Stored as favorites.ini on the SD card, with favorites.bak written as a best-effort backup after every successful save. The loader falls back to the backup if the primary fails and rewrites the primary if needed. Malformed lines are dropped and the file is rewritten cleanly.

Tuning

MacroDefaultMeaning
JMT_MAX_PRESET_FAVORITES10Maximum favorite slots
JMT_DISABLE_FAVORITESoffManually disable favorites entirely

Single-button builds (NUM_BUTTONS == 1) automatically disable favorites since the system relies on AUX.

Style Add-ons

Optional pieces that extend what a blade style can do. Each one ships in the add-ons repo and is enabled by an optional include in your config (see Setup). Once enabled, any blade style can use it directly.

ChargeFullPropFFunction Style-side function that lets a blade style react to a confirmed full-charge state.
Returns 0 when not full, 32768 when full
Drop-in for Mix<>, AlphaL<>, masks, transitions, selectors
Enable Add the matching include shown in Setup

When to use it (vs DisplayBattery)

DisplayBattery
What is the current estimated battery level?
Use for live battery meters and continuous indicators.
ChargeFullPropF
Has the charge handler confirmed a stable full-charge condition?
Use for visuals that switch only after charge is genuinely complete.

Why styles can trust it

By the time ChargeFullPropF returns 32768, the wrapper has already validated four conditions:

  • Charger physically present and debounced
  • Battery level above the enter threshold
  • Level held continuously through the dwell window
  • Exit hysteresis on the way down to prevent flicker

Thresholds and timing live in the Charge Full Tracking feature. Style code does not need its own smoothing.

Common pattern: switch between two styles

Mix<ChargeFullPropF, NOT_FULL_STYLE, FULL_STYLE>

When charge is not complete, the first branch shows. Once g_charge_full becomes true, the style instantly switches to the second branch.

Examples

Hard color swap

Amber while charging, green when full. The simplest possible use.

StylePtr<
  Mix<ChargeFullPropF,
    Rgb<255, 50, 0>,   // shown when charging (function = 0)
    Rgb<0, 255, 50>    // shown when full     (function = 32768)
  >
>()
AlphaL overlay

Amber base with a green pulse layered on top when full. AlphaL<> uses ChargeFullPropF as the alpha source for the pulse layer: invisible while charging, fully visible when full.

StylePtr<Layers<
  // Base: amber while charging
  RotateColorsX<Variation, Rgb<255, 80, 0>>,

  // When g_charge_full == true, fade in a green pulse overlay
  AlphaL<
    Pulsing<Rgb<0,255,0>, Black, 1200>,
    ChargeFullPropF
  >
>>()
Full preset with battery meter and boot wipe

A complete charging preset. Boot-wipe animation, then a live red-to-green battery meter while charging. Switches to a calm pulsing green when charge is confirmed complete.

StylePtr<
  Mix<
    ChargeFullPropF,

    // NOT FULL: battery bar with boot wipe
    Layers<
      Mix<
        PulsingF<Int<5000>>,
        Mix<
          SmoothStep<DisplayBattery, Int<-1>>,
          Black,
          Mix<DisplayBattery, Red, Green>
        >,
        Mix<
          SmoothStep<DisplayBattery, Int<-1>>,
          Black,
          Mix<DisplayBattery, Red, Green>
        >
      >,

      // BOOT: hold black during wipe setup
      TransitionEffectL<
        TrConcat<TrInstant, Black, TrDelay<5000>>,
        EFFECT_BOOT
      >,

      // BOOT: wipe battery bar upward
      TransitionEffectL<
        TrConcat<
          TrWipe<5000>,
          Mix<
            SmoothStep<DisplayBattery, Int<-1>>,
            Black,
            Mix<DisplayBattery, Red, Green>
          >,
          TrInstant
        >,
        EFFECT_BOOT
      >
    >,

    // FULL: pulsing green
    Pulsing<
      Green,
      Mix<Int<18000>, Green, Black>,
      4000
    >
  >
>()
Tip: pair with the charge style preset

If you also enable JMT_CHARGE_STYLE_PRESET, the typical setup is: the last preset in your array is your charging visual, and that preset's style uses ChargeFullPropF to switch to a "fully charged" appearance. The saber jumps to that preset automatically when plugged in, then visually announces when it is done charging without any user interaction.

PixelRelayStyle Alternating two-color flash on 1 or 2 pixels of an accent strip.
Top-level form StylePtr<PixelRelay<...>>(). Off pixels render solid black.
Layer form Layers<base, PixelRelayL<...>>. Off pixels stay transparent.
Enable Add the matching include shown in Setup

What it does

PixelRelay flashes COLOR_A COUNT_A times, then COLOR_B COUNT_B times, then repeats. Both colors share a single flash heartbeat (FLASH_PERIOD_MS) so the off color is simply dark while it is not its turn. Designed for the Luke ROTJ cave-scene arrow accent (the green-then-red alarm strobes in the Death Star II), but works as a general-purpose alternating flasher on any 1- or 2-pixel accent.

Two forms

  • PixelRelay: top-level form, pre-wrapped as Layers<Black, PixelRelayL<...>>. Drops directly into StylePtr<>. Off pixels render solid black.
  • PixelRelayL: layer form, returns transparent for off pixels. Compose it inside Layers<some_base_color, PixelRelayL<...>> when you want a base color to show through.

Parameters

ParameterDefaultMeaning
COLOR_ArequiredFirst color (any COLOR template)
COUNT_ArequiredNumber of flashes for COLOR_A before handing off (must be > 0)
COLOR_BrequiredSecond color
COUNT_BrequiredNumber of flashes for COLOR_B before handing back (must be > 0)
FLASH_PERIOD_MS333Full on+off duration of a single flash, in ms. Pass 0 to use the default.
SAME_PIXEL00 for two-pixel mode, 1 for one-pixel mode
START_INDEX0Starting pixel index for the relay. Must be 0 or positive.

Pixel modes

  • Two-pixel (default, SAME_PIXEL = 0): COLOR_A flashes at START_INDEX, COLOR_B flashes at START_INDEX + 1. Useful for two-LED accents.
  • Two-pixel with offset: same as default, with START_INDEX set to skip earlier pixels on the same strip. Useful when the accent strip has other LEDs before the relay pair.
  • One-pixel (SAME_PIXEL = 1): both colors flash on the same pixel at START_INDEX, alternating in time. Useful for single-LED accents or parallel-wired pairs.

Examples

Two-pixel Luke ROTJ cave scene at pixels 0 and 1

Green flashes 9 times, then red flashes 5 times, on the first two pixels of the accent strip. Both colors use RgbArg<BASE_COLOR_ARG, ...> so they are recolorable from the preset editor.

StylePtr<PixelRelay<
  RgbArg<BASE_COLOR_ARG, Rgb<0,255,0>>, 9,
  RgbArg<BASE_COLOR_ARG, Rgb<255,0,0>>, 5
>>()
Same effect offset to pixels 1 and 2

Leaves pixel 0 free for a different accent.

StylePtr<PixelRelay<
  RgbArg<BASE_COLOR_ARG, Rgb<0,255,0>>, 9,
  RgbArg<BASE_COLOR_ARG, Rgb<255,0,0>>, 5,
  0,  // FLASH_PERIOD_MS = 0 uses the default 333 ms
  0,  // SAME_PIXEL = 0 (two-pixel mode)
  1   // START_INDEX = 1 (relay lives on pixels 1 and 2)
>>()
Single-LED accent or parallel-wired pair

Both colors share a single pixel, alternating in time.

StylePtr<PixelRelay<
  RgbArg<BASE_COLOR_ARG, Rgb<0,255,0>>, 9,
  RgbArg<BASE_COLOR_ARG, Rgb<255,0,0>>, 5,
  0,  // default flash period
  1   // SAME_PIXEL = 1 enables one-pixel mode
>>()

Build Behavior

Hard Errors Combinations that fail to compile

These combinations will fail to compile. The error message points at the conflict directly.

  • Both JMT_ROLL_PRESETS and JMT_FLICK_PRESETS defined: Choose one gesture system
  • JMT_PITCH_OFFSET or JMT_ROLL_OFFSET without JMT_FLICK_PRESETS: Offsets only apply to the flick gesture
  • JMT_PITCH_OFFSET or JMT_ROLL_OFFSET without ORIENTATION_ROTATION: Required for offset math
  • Both BLADE_DETECT_PIN and JMT_BLADE_DETECT defined: Pick one blade detection method
  • Both CHASSIS_DETECT_PIN and JMT_CHASSIS_DETECT_RANGE defined: Pick one chassis detection method
  • JMT_CHARGE_LOCKOUT without CHARGE_DETECT_PIN: Charge features need a detect pin
  • JMT_CHARGE_STYLE_PRESET without CHARGE_DETECT_PIN: Charge features need a detect pin
  • JMT_CHARGE_COMPLETE_ANNOUNCE without CHARGE_DETECT_PIN: Charge features need a detect pin
  • JMT_BLADE_DETECT without ENABLE_POWER_FOR_ID: Required infrastructure
  • JMT_BLADE_DETECT without BLADE_ID_SCAN_MILLIS: Required infrastructure
  • JMT_BLADE_DETECT without BLADE_ID_TIMES: Required infrastructure
  • JMT_CHASSIS_DETECT_RANGE without ENABLE_POWER_FOR_ID: Required infrastructure (shares BladeID scan)
  • JMT_CHASSIS_DETECT_RANGE without BLADE_ID_SCAN_MILLIS: Required infrastructure (shares BladeID scan)
  • JMT_CHASSIS_DETECT_RANGE without BLADE_ID_TIMES: Required infrastructure (shares BladeID scan)
  • JMT_NO_BLADE_VALUE without JMT_BLADE_DETECT: Only applies when JMT blade detect is in use
  • BLADE_ID_SCAN_MILLIS ≤ 0 with JMT_BLADE_DETECT: Must be greater than 0
  • BLADE_ID_TIMES ≤ 0 with JMT_BLADE_DETECT: Must be greater than 0
  • CHARGE_FULL_EXITCHARGE_FULL_ENTER: Hysteresis required
  • CHARGE_FULL_DWELL_MS ≤ 0: Must be greater than 0
Warnings Build succeeds, with a warning emitted

Recommended to address before flashing, but not blocking.

  • JMT_CHARGE_LOCKOUT without FETT263_SAVE_GESTURE_OFF: Prior gesture state will not be fully preserved across a charge cycle
Automatic Behaviors Defaults and silent toggles you don't have to set

No action required. Listed here for transparency.

  • NUM_BUTTONS == 1 automatically enables JMT_DISABLE_FAVORITES. The favorites system relies on AUX, so it cannot run on a single-button build.
  • JMT_PITCH_OFFSET and JMT_ROLL_OFFSET default to 0 when JMT_FLICK_PRESETS is enabled.