| 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 |