FastLED 3.9.15
Loading...
Searching...
No Matches
potentiometer.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/stl/stdint.h"
4#include "fl/stl/function.h"
5#include "fl/stl/shared_ptr.h" // For FASTLED_SHARED_PTR macros
6#include "fl/stl/noexcept.h"
7
8namespace fl {
9
10// Low-level potentiometer class for direct ADC reading without callbacks.
11// This class provides raw hardware access without automatic updates.
13 public:
14 PotentiometerLowLevel(int pin);
19
20 // Read raw ADC value (0-1023 for 10-bit, 0-4095 for 12-bit ADC)
21 u16 read();
22
23 int getPin() const { return mPin; }
24
25 private:
26 int mPin;
27};
28
29// High-level potentiometer class with automatic updates and callback support.
30// This class hooks into FastLED EngineEvents to monitor value changes each frame.
31// Includes hysteresis to prevent noise-induced callback spam.
32// Supports calibration to map raw ADC values to normalized range (0.0-1.0).
34 public:
35 // Constructor
36 // @param pin: Analog pin number
37 // @param hysteresis: Minimum raw ADC change to trigger callbacks (0 = auto: 1% of calibrated range)
38 Potentiometer(int pin, u16 hysteresis = 0);
39
40 // ========================================================================
41 // Value Accessors
42 // ========================================================================
43
44 // Get raw ADC value (0-1023 for 10-bit, 0-4095 for 12-bit ADC)
45 u16 raw() const { return mCurrentValue; }
46
47 // Get normalized float value (0.0f - 1.0f) based on calibration range
48 // Maps mMinValue -> 0.0f and mMaxValue -> 1.0f
49 // Values outside range are clamped to [0.0, 1.0]
50 float normalized() const;
51
52 // Get fractional 16-bit value (0 - 65535) for high-precision integer math
53 // Based on calibration range (mMinValue -> 0, mMaxValue -> 65535)
54 u16 fractional16() const;
55
56 // Check if value changed this frame (beyond hysteresis threshold)
57 bool hasChanged() const { return mChangedThisFrame; }
58
59 // ========================================================================
60 // Callback Registration
61 // ========================================================================
62
63 // Register callback with Potentiometer reference (can access all value formats)
64 int onChange(fl::function<void(Potentiometer &)> callback);
65
66 // Register callback with normalized float value (convenience overload)
67 int onChange(fl::function<void(float)> callback);
68
69 // Remove callback by ID
70 void removeOnChange(int id) {
71 mOnChangeCallbacks.remove(id);
73 }
74
75 // ========================================================================
76 // Configuration
77 // ========================================================================
78
79 // Set hysteresis threshold in raw ADC units (e.g., 10 = must change by 10 ADC counts)
80 void setHysteresis(u16 threshold) { mHysteresis = threshold; }
81
82 // Set hysteresis as percentage of calibrated range (0.0-100.0)
83 // Example: 1.0 = 1% of (mMaxValue - mMinValue)
84 void setHysteresisPercent(float percent);
85
86 // Get current hysteresis threshold in raw ADC units
87 u16 getHysteresis() const { return mHysteresis; }
88
89 // ========================================================================
90 // Calibration (Range Mapping)
91 // ========================================================================
92
93 // Set the raw ADC range that maps to normalized [0.0, 1.0]
94 // @param min: Raw ADC value that maps to 0.0 (default: 0)
95 // @param max: Raw ADC value that maps to 1.0 (default: ADC max value)
96 // Example: setRange(100, 900) maps 100->0.0, 900->1.0, values outside are clamped
97 void setRange(u16 min, u16 max);
98
99 // Get the minimum raw value (maps to 0.0 in normalized)
100 u16 getRangeMin() const { return mMinValue; }
101
102 // Get the maximum raw value (maps to 1.0 in normalized)
103 u16 getRangeMax() const { return mMaxValue; }
104
105 // Calibrate to current position as minimum (0.0)
107
108 // Calibrate to current position as maximum (1.0)
110
111 // Reset calibration to full ADC range
113 mMinValue = 0;
115 }
116
117 // ========================================================================
118 // Test Helpers (for unit testing only)
119 // ========================================================================
120
121#ifdef FASTLED_UNIT_TEST
122 // Inject a test value directly (bypasses analogRead)
123 // Only available in unit test builds
124 void injectTestValue(u16 value) {
126 // Manually trigger change detection logic
127 u16 diff = (value > mLastValue) ? (value - mLastValue) : (mLastValue - value);
128 mChangedThisFrame = (diff >= mHysteresis);
129 if (mChangedThisFrame) {
131 mOnChangeCallbacks.invoke(*this);
132 float normalized_value = normalized();
133 mOnChangeNormalizedCallbacks.invoke(normalized_value);
134 }
135 }
136#endif
137
138 protected:
140 Listener(Potentiometer *owner);
143
144 // Update on end frame (before next frame is drawn, matching Button behavior)
145 void onEndFrame() override;
146
147 private:
149 bool added = false;
150 };
151
152 private:
155
156 u16 mCurrentValue = 0; // Current raw ADC value
157 u16 mLastValue = 0; // Last value that triggered callbacks
158 u16 mHysteresis = 0; // Hysteresis threshold in raw ADC units
159 bool mChangedThisFrame = false; // True if changed beyond hysteresis this frame
160
161 // Calibration range: raw ADC values that map to normalized [0.0, 1.0]
162 u16 mMinValue = 0; // Raw value that maps to 0.0 (default: 0)
163 u16 mMaxValue = 0; // Raw value that maps to 1.0 (default: ADC max)
164
165 fl::function_list<void(Potentiometer &)> mOnChangeCallbacks;
166 fl::function_list<void(float)> mOnChangeNormalizedCallbacks;
167
168 // Get ADC resolution (10-bit = 1023, 12-bit = 4095)
169 u16 getAdcMaxValue() const;
170
171 // Calculate default hysteresis (1% of calibrated range)
172 u16 calculateDefaultHysteresis() const;
173};
174
175} // namespace fl
Potentiometer(int pin, u16 hysteresis=0)
u16 calculateDefaultHysteresis() const
void setHysteresisPercent(float percent)
void setRange(u16 min, u16 max)
bool hasChanged() const
u16 getRangeMin() const
void removeOnChange(int id)
int onChange(fl::function< void(Potentiometer &)> callback)
fl::function_list< void(float)> mOnChangeNormalizedCallbacks
fl::function_list< void(Potentiometer &)> mOnChangeCallbacks
u16 getRangeMax() const
u16 getHysteresis() const
PotentiometerLowLevel mPot
void setHysteresis(u16 threshold)
PotentiometerLowLevel(PotentiometerLowLevel &&other) FL_NOEXCEPT=delete
PotentiometerLowLevel & operator=(const PotentiometerLowLevel &other) FL_NOEXCEPT=delete
PotentiometerLowLevel(const PotentiometerLowLevel &other) FL_NOEXCEPT=default
FL_DISABLE_WARNING_PUSH U constexpr common_type_t< T, U > min(T a, U b) FL_NOEXCEPT
Definition math.h:71
constexpr int type_rank< T >::value
constexpr common_type_t< T, U > max(T a, U b) FL_NOEXCEPT
Definition math.h:75
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NOEXCEPT