GCC Code Coverage Report


Directory: ./
File: OutputMonitor.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 1 1 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
14 #include <atomic>
15 #include <functional>
16 #include "fpp-json-fwd.h"
17 #include <list>
18 #include <map>
19 #include <mutex>
20 #include <shared_mutex>
21 #include <string>
22 #include <vector>
23
24 #include "fpphttp_types.h"
25
26 #include "util/GPIOUtils.h"
27
28 class PortPinInfo;
29
30 class OutputMonitor {
31 public:
32 static OutputMonitor INSTANCE;
33
34 void Initialize(std::map<int, std::function<bool(int)>>& callbacks);
35 void Cleanup();
36
37 void RemovePortConfiguration(int port, const Json::Value& config);
38 void AddPortConfiguration(int port, const Json::Value& config, bool enabled = true);
39 const PinCapabilities* AddOutputPin(const std::string& name, const std::string& pin, bool addToList = true);
40
41 void EnableOutputs();
42 void DisableOutputs();
43
44 void SetOutput(const std::string& port, bool on);
45
46 void AutoEnableOutputs();
47 void AutoDisableOutputs();
48
49 void GetCurrentPortStatusJson(Json::Value& result);
50
51 HttpResponsePtr render_GET(const HttpRequestPtr& req);
52
53 3 int getGroupCount() const { return numGroups; }
54 void lockToGroup(int i);
55 bool isPortInGroup(int group, int port);
56 std::vector<float> GetPortCurrentValues();
57 void SetPixelCount(int port, int pc, int cc = -1);
58 int GetPixelCount(int port);
59
60 void checkPixelCounts(const std::string& portList, const std::string& action, int sensitivy);
61
62 void setSmartReceiverInfo(int port, int index, bool enabled, bool tripped, int current, int pixelCount);
63 void setSmartReceiverEventCallback(std::function<void(int port, int index, const std::string& cmd)>&& f);
64
65 private:
66 OutputMonitor();
67 ~OutputMonitor();
68
69 std::list<const PinCapabilities*> pullHighOutputPins;
70 std::list<const PinCapabilities*> pullLowOutputPins;
71
72 std::map<std::string, const PinCapabilities*> fusePins;
73 std::vector<PortPinInfo*> portPins;
74 std::list<PortPinInfo*> eFuseRetries;
75 bool retryTimerRunning = false;
76 // Whether the enable pins are currently supposed to be driven on. Ports
77 // are re-registered whenever a string config is reloaded, which happens
78 // while output is running (an xLights auto-upload lands after "output to
79 // lights" has already started the output thread), so AddPortConfiguration
80 // has to bring a port up in the state the monitor is already in rather
81 // than assume the pre-output state.
82 std::atomic<bool> outputsEnabled{ false };
83 // Guards portPins, the pull-high/low pin lists, fusePins, eFuseRetries,
84 // and pendingEFusePresets. Writers (config reload, the eFuse GPIO
85 // callbacks, retry processing, enable/disable) take it exclusive; status
86 // readers (HTTP/MQTT port status, the pixel-count tester) take it
87 // shared. Presets and the smart-receiver callback must NOT be invoked
88 // while it is held: command presets run synchronously and can re-enter
89 // EnableOutputs/DisableOutputs/SetOutput on the same thread.
90 std::shared_mutex gpioLock;
91 int numGroups = 1;
92 int curGroup = -1;
93
94 int eFuseRetryCount = 0;
95 int eFuseRetryInterval = 100;
96
97 // The smart-receiver callback is owned by a FalconV5Support that is
98 // destroyed on a config reload while commands ("Set Port Status") are
99 // still arriving on the API/MQTT/GPIO threads. The callback captures that
100 // object, so it must never be copied out and invoked after the lock is
101 // dropped -- the copy carries no ownership and the object can be freed in
102 // between. Invoking it under this mutex, which ~FalconV5Support() also
103 // takes to clear the callback, means the unregister blocks behind any
104 // in-flight call and no call can start after it returns.
105 //
106 // Deliberately not gpioLock: dispatch has to happen with the port state
107 // unlocked so a callback that re-enters the monitor can't self-deadlock.
108 std::mutex srCallbackLock;
109 std::function<void(int port, int index, const std::string& cmd)> srCallback;
110 // Port names whose EFUSE_TRIGGERED preset still needs to fire. Queued by
111 // addEFuseWarning() (called with gpioLock held) and drained by
112 // triggerEFusePresets() after the lock is released.
113 std::vector<std::string> pendingEFusePresets;
114
115 const PinCapabilities* addOutputPinInternal(const std::string& name, const std::string& pin, bool addToList);
116 void addEFuseWarning(PortPinInfo* port, int rec = 0);
117 void clearEFuseWarning(PortPinInfo* port, int rec = 0);
118 void clearReceiverWarnings(PortPinInfo* port);
119 bool checkEFuseRetry(PortPinInfo* port);
120 void processRetries();
121 void triggerEFusePresets();
122 };
123