GCC Code Coverage Report


Directory: ./
File: gpio.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 17 17 100.0%
Functions: 1 1 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 #pragma once
2 /*
3 * This file is part of the Falcon Player (FPP) and is Copyright (C)
4 * 2013-2022 by the Falcon Player Developers.
5 *
6 * The Falcon Player (FPP) is free software, and is covered under
7 * multiple Open Source licenses. Please see the included 'LICENSES'
8 * file for descriptions of what files are covered by each license.
9 *
10 * This source file is covered under the LGPL v2.1 as described in the
11 * included LICENSE.LGPL file.
12 */
13 #include <functional>
14 #include "fpp-json-fwd.h"
15 #include <list>
16 #include <map>
17 #include <vector>
18 #include "fpphttp_types.h"
19 #include "config.h"
20
21 constexpr uint32_t DEFAULT_GPIO_DEBOUNCE_TIME = 100000;
22
23 class PinCapabilities;
24
25 class GPIOManager {
26 public:
27 static GPIOManager INSTANCE;
28 // Last value set on each pin by the "GPIO" command / API. Written from
29 // API threads, the main loop and the LED pulse timer at once, so FPP's
30 // own code only goes through the locked accessors below; the member stays
31 // public for out-of-tree code that read it directly.
32 std::map<std::string, bool> fppCommandLastValue;
33 static void SetCommandLastValue(const std::string& pin, bool value);
34 static bool GetCommandLastValue(const std::string& pin, bool& value);
35 static bool ToggleCommandLastValue(const std::string& pin); // returns the new value
36 HttpResponsePtr render_GET(const HttpRequestPtr& req);
37 HttpResponsePtr render_POST(const HttpRequestPtr& req);
38 void Initialize(std::map<int, std::function<bool(int)>>& callbacks);
39 void CheckGPIOInputs(void);
40 void Cleanup();
41 void AddGPIOCallback(const PinCapabilities* pin, const std::function<bool(int)>& cb);
42 void RemoveGPIOCallback(const PinCapabilities* pin);
43 // Live value of a configured GPIO Input pin (rising/falling/hold actions),
44 // by pin name - distinct from fppCommandLastValue, which only tracks
45 // pins explicitly set via the "GPIO" command/API and knows nothing about
46 // input-only pins. Used by the If command's "GPIO Pin" condition source
47 // (Condition.cpp) so checking an input's current state actually works,
48 // not just a previously-commanded output.
49 bool GetInputPinValue(const std::string& name, int& value) const;
50 private:
51 class GPIOState {
52 public:
53 16 GPIOState() :
54 16 pin(nullptr),
55 16 lastValue(0),
56 16 lastTriggerTime(0),
57 16 futureValue(0),
58 16 pendingValue(0),
59 16 pendingTime(0),
60 16 file(-1),
61 16 holdTime(0),
62 16 holdFired(false),
63 16 holdStartTime(0),
64 16 ledActiveHigh(true),
65 16 ledIdleMode(LEDIdleMode::Off),
66 16 ledPulseRateMs(500),
67 16 ledTriggerMode(LEDTriggerMode::FollowInput),
68 16 ledTriggerParam(0),
69 16 ledPulseState(false) {}
70
71 const PinCapabilities* pin;
72 int lastValue;
73 long long lastTriggerTime;
74 int futureValue;
75 int pendingValue; // candidate value waiting to settle
76 long long pendingTime; // GetMonotonicTimeMicros() when pendingValue was first seen
77 int file;
78
79 // Multiple commands per edge — old single-object format is normalised
80 // into these vectors during SetupGPIOInput.
81 std::vector<Json::Value> risingActions;
82 std::vector<Json::Value> fallingActions;
83
84 // Long-press / hold: commands fired after holdTime ms of continuous press.
85 std::vector<Json::Value> holdActions;
86 uint32_t holdTime; // ms; 0 = disabled
87 bool holdFired; // true once hold actions have fired this press
88 long long holdStartTime; // GetTimeMS() when the current press began
89
90 // ── LED output associated with this illuminated button ──────────────
91 std::string ledPin;
92 bool ledActiveHigh; // true → HIGH means LED on
93
94 // What the LED does when idle (not in a trigger effect)
95 enum class LEDIdleMode {
96 Off, // LED off at rest
97 On, // LED on at rest
98 Pulse // LED blinks at ledPulseRateMs interval
99 };
100 LEDIdleMode ledIdleMode;
101 uint32_t ledPulseRateMs; // ms per half-period when pulsing
102 bool ledPulseState; // current toggle state for pulsing
103
104 // What the LED does when a trigger fires (rising edge)
105 enum class LEDTriggerMode {
106 None, // no LED change on trigger; idle mode only
107 FollowInput, // LED mirrors input state (on when pressed, off when released)
108 Flash, // flash N times (ledTriggerParam = flash count) then restore idle
109 TimedOn // stay on for ledTriggerParam ms then restore idle
110 };
111 LEDTriggerMode ledTriggerMode;
112 uint32_t ledTriggerParam; // flash count OR duration ms
113
114 // ── LED helpers ─────────────────────────────────────────────────────
115 void initLED();
116 void setLEDState(bool on);
117 void startLEDIdle();
118 void stopLEDIdle();
119 void triggerLEDEffect(int v);
120 void doLEDFlash(int halfPeriodsRemaining);
121
122 // ── Callback (for non-command uses) ─────────────────────────────────
123 std::function<bool(int)> callback;
124 bool hasCallback = false;
125
126 // ── Debounce ────────────────────────────────────────────────────────
127 uint32_t debounceTime = DEFAULT_GPIO_DEBOUNCE_TIME;
128 enum class DebounceEdge {
129 Both, // debounce rising and falling (default)
130 Rising, // debounce only rising; falling fires immediately
131 Falling // debounce only falling; rising fires immediately
132 };
133 DebounceEdge debounceEdge = DebounceEdge::Both;
134
135 // ── Re-enable after trigger ──────────────────────────────────────────
136 // Controls how long the input is suppressed after commands fire.
137 enum class ReEnableMode {
138 Always, // always enabled — no suppression (default)
139 Timed, // re-enable after reEnableDelay ms
140 OnPlayerIdle // re-enable once the player returns to idle
141 };
142 ReEnableMode reEnableMode = ReEnableMode::Always;
143 uint32_t reEnableDelay = 0; // ms; used by Timed mode
144 bool inputDisabled = false; // true while the input is suppressed post-trigger
145
146 void scheduleReEnable();
147 void checkReEnable(long long startMs, bool playerHasStarted);
148
149 bool shouldDebounce(int v) const;
150 void doAction(int newVal);
151 void checkHoldTimer(long long scheduledStart);
152 };
153 GPIOManager();
154 ~GPIOManager();
155 void SetupGPIOInput(std::map<int, std::function<bool(int)>>& callbacks);
156 void addState(GPIOState* state);
157 void addGPIOCallback(GPIOState* state);
158 void checkDebounceTimers();
159 void scheduleDebounceCheck(GPIOState* state);
160 std::list<GPIOState*> pollStates;
161 std::list<GPIOState*> eventStates;
162 friend class GPIOCommand;
163 };
164