GCC Code Coverage Report


Directory: ./
File: non-gpl/DPIPixels/DPIPixels.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 21 22 95.5%
Functions: 3 4 75.0%
Branches: 3 4 75.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 CC-BY-ND as described in the
11 * included LICENSE.CC-BY-ND file. This file may be modified for
12 * personal use, but modified copies MAY NOT be redistributed in any form.
13 */
14
15 #include <string>
16 #include "fpp-json-fwd.h"
17 #include <vector>
18
19 #include "channeloutput/ChannelOutput.h"
20 #include "channeloutput/PixelString.h"
21 #include "framebuffer/FrameBuffer.h"
22
23 constexpr int MAX_DPI_PIXEL_LATCHES = 4;
24
25 class DPIPixelsOutput : public ChannelOutput {
26 public:
27 DPIPixelsOutput(unsigned int startChannel, unsigned int channelCount);
28 virtual ~DPIPixelsOutput();
29
30 24 virtual std::string GetOutputType() const {
31
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
48 return "DPI Pixels";
32 }
33
34 virtual int Init(Json::Value config) override;
35 virtual int Close(void) override;
36
37 virtual void PrepData(unsigned char* channelData) override;
38 virtual int SendData(unsigned char* channelData) override;
39
40 virtual void DumpConfig(void) override;
41
42 virtual void GetRequiredChannelRanges(const std::function<void(int, int)>& addRange) override;
43
44 virtual void OverlayTestData(unsigned char* channelData, int cycleNum, float percentOfCycle, int testType, const Json::Value& config) override;
45 ✗ virtual bool SupportsTesting() const override { return true; }
46
47 private:
48 bool LoadStringConfig(const std::string& subType, Json::Value& root, std::string& usedSubType);
49 int GetDPIPinBitPosition(std::string pinName);
50 bool FrameBufferIsConfigured(void);
51 void WriteDataAtPosition(uint8_t *&ptr, const uint32_t value);
52 void WriteLatchedDataAtPosition(uint8_t *&ptr, const uint32_t value, const uint32_t latches);
53
54 bool InitializeWS281x(void);
55 void CopyShadowToAllPages(void);
56 int IdleFpsFromSetting(void);
57
58 std::string device = "DPI-1";
59 std::string protocol = "ws2811";
60 int licensedOutputs = 0;
61 bool usingSmartReceivers = false;
62 bool usingLatches = false;
63 uint8_t* onOffMap = nullptr;
64
65 std::vector<PixelString*> pixelStrings;
66 int bitPos[MAX_DPI_PIXEL_LATCHES * 24];
67
68 FrameBuffer* fb = nullptr;
69 int fbPage = -1;
70
71 // The KMS pages are uncached DMA memory: streaming writes are fine but any
72 // read-back is ~30x slower than RAM, and scattered writes into a page the
73 // DPI is still scanning can tear a bit's middle third. So the WS bit
74 // stream is built in this ordinary malloc'd copy of a page (template from
75 // InitializeWS281x(), middle thirds from PrepData()) and SendData() copies
76 // the data rows into the free page in one burst once the previous flip has
77 // retired. Two KMS pages are enough for that; no third buffer in CMA.
78 uint8_t* m_shadow = nullptr;
79 int m_shadowCopyBytes = 0; // data rows only; the reset rows never change
80
81 int latchCount = 0;
82 int longestString = 0;
83 int outputToStringMap[MAX_DPI_PIXEL_LATCHES * 24];
84 int stringToOutputMap[MAX_DPI_PIXEL_LATCHES * 24];
85 int stringLengths[MAX_DPI_PIXEL_LATCHES * 24];
86 uint32_t latchPinMask = 0x000000;
87 uint32_t latchPinMasks[MAX_DPI_PIXEL_LATCHES];
88 uint32_t onOffMask[MAX_DPI_PIXEL_LATCHES][4800]; // Max 1600 pixels * 3 channels each.
89
90 int protoBitsPerLine = 0;
91 int protoBitOnLine = 0;
92 uint8_t* protoDest = nullptr;
93 int protoDestExtra = 0;
94
95 int fbPixelMult = 1;
96
97 // Runtime refresh-rate control. The framebuffer height is sized once to the
98 // longest string; the DPI output rate is then set per-sequence by varying
99 // only the vertical blanking (see KMSFrameBuffer::SetRefreshRate).
100 int m_configuredMaxFps = 0; // highest rate the longest string allows
101 int m_currentFps = 0; // last rate applied to the framebuffer
102 int m_idleFps = 20; // 1000 / E131BridgingInterval, kept current by a settings listener
103 bool m_initialized = false; // gates runtime rate control (off during Init/Close)
104 // GetTime() when output went idle, for the settle window in PrepData().
105 // 0 means "a sequence is running, or none has stopped yet".
106 long long m_idleSinceUS = 0;
107
108 // Track which pins we configured as DPI so we can reset them on close
109 std::vector<std::string> m_configuredDPIPins;
110
111 // output testing data
112 int m_testCycle = -1;
113 int m_testType = 0;
114 float m_testPercent = 0.0f;
115
116 std::list<std::string> m_autoCreatedModelNames;
117 };
118
119
120 // This function writes out 16 FB pixels at a time as 12 uint32_t.
121 // Used by non-latch mode since we need to write out the same data 16 times.
122 207616 inline void DPIPixelsOutput::WriteDataAtPosition(uint8_t *&ptr, const uint32_t value) {
123 // value is 24-bit value in a uint32_t
124 // FB uint32_t value new uint32_t fb0 order
125 // v1 0x00abcdef 0xefabcdef ef cd ab ef
126 // v2 0x00abcdef 0xcdefabcd cd ab ef cd
127 // v3 0x00abcdef 0xabcdefab ab ef cd ab
128
129 207616 uint32_t v1 = value | (value << 24);
130 207616 uint32_t v2 = (value << 16) | (value >> 8);
131 207616 uint32_t v3 = (value << 8) | (value >> 16);
132 207616 uint32_t *tptr = (uint32_t*)ptr;
133
134 // 4 FB pixels per 3 words, repeated 4 times. Written as pure stores (no
135 // read-back of what was just written) so this stays cheap even if the
136 // destination is ever uncached memory.
137
2/2
✓ Branch 0 taken 830464 times.
✓ Branch 1 taken 207616 times.
1038080 for (int i = 0; i < 4; i++) {
138 830464 *(tptr++) = v1;
139 830464 *(tptr++) = v2;
140 830464 *(tptr++) = v3;
141 }
142
143 207616 ptr += 48; // 12 uint32_t
144 207616 }
145
146 // This function writes out 4 FB pixels at a time as 3 uint32_t.
147 // Used by Latch mode since we write out data for each latch 4 FB pixels at a time.
148 768000 inline void DPIPixelsOutput::WriteLatchedDataAtPosition(uint8_t *&ptr, const uint32_t value, const uint32_t latches) {
149 // value and valueWithLatch are each 24-bit values in a uint32_t
150 // FB uint32_t value valueWithLatch new uint32_t fb0 order
151 // #1 0x00abcdef 0x00ghijkl 0xklabcdef ef cd ab kl
152 // #2 0x00abcdef 0x00ghijkl 0xijklghij ij gh kl ij
153 // #3 0x00abcdef 0x00ghijkl 0xabcdefgh gh ef cd ab
154
155 768000 uint32_t valueWithLatch = value | latches;
156 768000 uint32_t *tptr = (uint32_t*)ptr;
157
158 768000 *(tptr++) = value | (valueWithLatch << 24);
159 768000 *(tptr++) = (valueWithLatch << 16) | (valueWithLatch >> 8);
160 768000 *(tptr++) = (value << 8) | (valueWithLatch >> 16);
161
162 768000 ptr += 12;
163 768000 }
164
165