| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of the Falcon Player (FPP) and is Copyright (C) | ||
| 3 | * 2013-2022 by the Falcon Player Developers. | ||
| 4 | * | ||
| 5 | * The Falcon Player (FPP) is free software, and is covered under | ||
| 6 | * multiple Open Source licenses. Please see the included 'LICENSES' | ||
| 7 | * file for descriptions of what files are covered by each license. | ||
| 8 | * | ||
| 9 | * This source file is covered under the GPL v2 as described in the | ||
| 10 | * included LICENSE.GPL file. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include "fpp-pch.h" | ||
| 14 | |||
| 15 | #ifdef __ARM_NEON | ||
| 16 | #include <arm_neon.h> | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #include "fpp-json.h" | ||
| 20 | |||
| 21 | #include "BBBMatrix.h" | ||
| 22 | #include <sys/mman.h> | ||
| 23 | #include <sys/wait.h> | ||
| 24 | #include <cmath> | ||
| 25 | #include <fstream> | ||
| 26 | |||
| 27 | #include "../Warnings.h" | ||
| 28 | #include "ChannelOutputSetup.h" | ||
| 29 | #include "../common.h" | ||
| 30 | #include "../log.h" | ||
| 31 | #include "../settings.h" | ||
| 32 | |||
| 33 | #include "GammaLUT.h" | ||
| 34 | #include "PanelInterleaveHandler.h" | ||
| 35 | #include "overlays/PixelOverlay.h" | ||
| 36 | #include "util/BBBUtils.h" | ||
| 37 | |||
| 38 | #include "Plugin.h" | ||
| 39 | class BBBMatrixPlugin : public FPPPlugins::Plugin, public FPPPlugins::ChannelOutputPlugin { | ||
| 40 | public: | ||
| 41 | 15 | BBBMatrixPlugin() : | |
| 42 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
45 | FPPPlugins::Plugin("BBBMatrix") { |
| 43 | 15 | } | |
| 44 | 15 | virtual ChannelOutput* createChannelOutput(unsigned int startChannel, unsigned int channelCount) override { | |
| 45 |
2/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
30 | return new BBBMatrix(startChannel, channelCount); |
| 46 | } | ||
| 47 | }; | ||
| 48 | |||
| 49 | extern "C" { | ||
| 50 | 15 | FPPPlugins::Plugin* createPlugin() { | |
| 51 |
2/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
30 | return new BBBMatrixPlugin(); |
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | // These are the number of clock cycles it takes to clock out a single "row" of bits (1 bit) for 32x16 1/8 P10 scan panels. Other | ||
| 56 | // panel types and scan rates and stuff are proportional to these | ||
| 57 | static const uint32_t v1Timings[8][16] = { | ||
| 58 | { 0xA65, 0x14EA, 0x1F6F, 0x29ED, 0x346E, 0x3EEE, 0x496C, 0x53EB, 0x5E6B, 0x68ED, 0x7374, 0x7DF0, 0x887B, 0x92F4, 0x9D75, 0xA7FB }, | ||
| 59 | { 0xA69, 0x14EA, 0x1F6F, 0x29ED, 0x346E, 0x3EEE, 0x496C, 0x53EB, 0x5E6B, 0x68ED, 0x7374, 0x7DF0, 0x887B, 0x92F4, 0x9D75, 0xA7FB }, | ||
| 60 | { 0xA6A, 0x14EA, 0x1F6F, 0x29ED, 0x346E, 0x3EEE, 0x496C, 0x53EB, 0x5E6B, 0x68ED, 0x7374, 0x7DF0, 0x887B, 0x92F4, 0x9D75, 0xA7FB }, | ||
| 61 | { 0xC88, 0x1906, 0x2588, 0x340D, 0x3E8D, 0x4B10, 0x5790, 0x6410, 0x7090, 0x7D10, 0x8990, 0x9610, 0xA291, 0xAF0D, 0xBB90, 0xC80D }, | ||
| 62 | { 0xC88, 0x1906, 0x2588, 0x340D, 0x3E8D, 0x4B10, 0x5790, 0x6410, 0x7090, 0x7D10, 0x8990, 0x9610, 0xA291, 0xAF0D, 0xBB90, 0xC80D }, | ||
| 63 | { 0xC88, 0x1906, 0x2588, 0x340D, 0x3E8D, 0x4B10, 0x5790, 0x6410, 0x7090, 0x7D10, 0x8990, 0x9610, 0xA291, 0xAF0D, 0xBB90, 0xC80D }, | ||
| 64 | { 0xC88, 0x1906, 0x2588, 0x340D, 0x3E8D, 0x4B10, 0x5790, 0x6410, 0x7090, 0x7D10, 0x8990, 0x9610, 0xA291, 0xAF0D, 0xBB90, 0xC80D }, | ||
| 65 | { 0xC90, 0x190D, 0x2590, 0x340D, 0x3E8D, 0x4B10, 0x5790, 0x6410, 0x7090, 0x7D10, 0x8990, 0x9610, 0xA291, 0xAF0D, 0xBB90, 0xC80D } | ||
| 66 | }; | ||
| 67 | static const uint32_t v2Timings[8][16] = { | ||
| 68 | { 0x347, 0x64F, 0x95F, 0xC70, 0xF80, 0x129E, 0x15B3, 0x18CB, 0x1BE4, 0x1EFB, 0x2211, 0x252C, 0x2786, 0x2A88, 0x2D85, 0x3088 }, | ||
| 69 | { 0x864, 0x10ED, 0x196C, 0x21EA, 0x2A6C, 0x32E9, 0x3B6A, 0x43EC, 0x4C6A, 0x54EA, 0x5D6B, 0x65EB, 0x6E6D, 0x76ED, 0x7F6E, 0x87EE }, | ||
| 70 | { 0x864, 0x10ED, 0x196C, 0x21EA, 0x2A6C, 0x32E9, 0x3B6A, 0x43EC, 0x4C6A, 0x54EA, 0x5D6B, 0x65EB, 0x6E6D, 0x76ED, 0x7F6E, 0x87EE }, | ||
| 71 | { 0xA69, 0x14EA, 0x1F6F, 0x29ED, 0x346E, 0x3EEE, 0x496C, 0x53EB, 0x5E6B, 0x68ED, 0x7374, 0x7DF0, 0x887B, 0x92F4, 0x9D75, 0xA7FB }, | ||
| 72 | { 0xA6A, 0x14EA, 0x1F6F, 0x29ED, 0x346E, 0x3EEE, 0x496C, 0x53EB, 0x5E6B, 0x68ED, 0x7374, 0x7DF0, 0x887B, 0x92F4, 0x9D75, 0xA7FB }, | ||
| 73 | { 0xC88, 0x1906, 0x2588, 0x340D, 0x3E8D, 0x4B10, 0x5790, 0x6410, 0x7090, 0x7D10, 0x8990, 0x9610, 0xA291, 0xAF0D, 0xBB90, 0xC80D }, | ||
| 74 | { 0xC88, 0x1906, 0x2588, 0x340D, 0x3E8D, 0x4B10, 0x5790, 0x6410, 0x7090, 0x7D10, 0x8990, 0x9610, 0xA291, 0xAF0D, 0xBB90, 0xC80D }, | ||
| 75 | { 0xC88, 0x1906, 0x2588, 0x340D, 0x3E8D, 0x4B10, 0x5790, 0x6410, 0x7090, 0x7D10, 0x8990, 0x9610, 0xA291, 0xAF0D, 0xBB90, 0xC80D }, | ||
| 76 | }; | ||
| 77 | static const uint32_t psTimings[8][16] = { | ||
| 78 | { 0x440, 0x820, 0xC30, 0x1000, 0x1400, 0x17F1, 0x1C00, 0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, 0x4000 }, | ||
| 79 | { 0x940, 0x12C0, 0x1C80, 0x25C0, 0x2F40, 0x3900, 0x4240, 0x4C00, 0x5540, 0x5EC0, 0x6850, 0x71C0, 0x7B40, 0x84C0, 0x8E80, 0x97CE }, | ||
| 80 | { 0xB70, 0x1700, 0x2280, 0x2E00, 0x3A00, 0x4500, 0x5080, 0x5C00, 0x6780, 0x7320, 0x7E80, 0x8A00, 0x9580, 0xA100, 0xAC80, 0xB7F0 }, | ||
| 81 | { 0xB80, 0x1700, 0x2280, 0x2E00, 0x3A00, 0x4500, 0x5080, 0x5C00, 0x6780, 0x7320, 0x7E80, 0x8A00, 0x9580, 0xA100, 0xAC80, 0xB800 }, | ||
| 82 | { 0xB90, 0x1700, 0x2280, 0x2E00, 0x3A00, 0x4500, 0x5080, 0x5C00, 0x6780, 0x7320, 0x7E80, 0x8A00, 0x9580, 0xA100, 0xAC80, 0xB800 }, | ||
| 83 | { 0xB90, 0x1700, 0x2280, 0x2E00, 0x3A00, 0x4500, 0x5080, 0x5C00, 0x6780, 0x7320, 0x7E80, 0x8A00, 0x9580, 0xA100, 0xAC80, 0xB800 }, | ||
| 84 | { 0xC88, 0x1906, 0x2588, 0x340D, 0x3E8D, 0x4B10, 0x5790, 0x6410, 0x7090, 0x7D10, 0x8990, 0x9610, 0xA291, 0xAF0D, 0xBB90, 0xC80D }, | ||
| 85 | { 0xC88, 0x1906, 0x2588, 0x340D, 0x3E8D, 0x4B10, 0x5790, 0x6410, 0x7090, 0x7D10, 0x8990, 0x9610, 0xA291, 0xAF0D, 0xBB90, 0xC80D }, | ||
| 86 | }; | ||
| 87 | |||
| 88 | static std::map<int, std::vector<int>> BIT_ORDERS = { | ||
| 89 | { 6, { 5, 2, 1, 4, 3, 0 } }, | ||
| 90 | { 7, { 6, 2, 1, 4, 5, 3, 0 } }, | ||
| 91 | { 8, { 7, 3, 5, 1, 2, 6, 4, 0 } }, | ||
| 92 | //{ 8, { 7, 6, 5, 4, 3, 2, 1, 0 } }, | ||
| 93 | { 9, { 8, 3, 5, 1, 7, 2, 6, 4, 0 } }, | ||
| 94 | { 10, { 9, 4, 1, 6, 3, 8, 2, 7, 5, 0 } }, | ||
| 95 | { 11, { 10, 4, 7, 2, 3, 1, 6, 9, 8, 5, 0 } }, | ||
| 96 | { 12, { 11, 5, 8, 2, 4, 1, 7, 10, 3, 9, 6, 0 } } | ||
| 97 | }; | ||
| 98 | 14 | static void compilePRUMatrixCode(std::vector<std::string>& sargs) { | |
| 99 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | CompilePRUProgram("/opt/fpp/src/pru/compileMatrix.sh", sargs); |
| 100 | 14 | } | |
| 101 | |||
| 102 | 14 | void BBBMatrix::calcBrightnessFlags(std::vector<std::string>& sargs) { | |
| 103 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | LogDebug(VB_CHANNELOUT, "Calc Brightness: maxPanel: %d maxOutput: %d Brightness: %d rpo: %d ph: %d pw: %d\n", m_longestChain, m_outputs, m_brightness, m_panelScan, m_panelHeight, m_panelWidth); |
| 104 | |||
| 105 | // The tables stop at 8 outputs and 16 panels a chain, and the cape | ||
| 106 | // takes 16 outputs: past the tables this read beyond them. Use the | ||
| 107 | // nearest entry, the slowest timing the tables know. | ||
| 108 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | int to = std::clamp(m_outputs, 1, 8) - 1; |
| 109 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | int tc = std::clamp(m_longestChain, 1, 16) - 1; |
| 110 | 14 | uint32_t max = 0xB00; | |
| 111 |
1/3✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
|
14 | switch (m_timing) { |
| 112 | ✗ | case 2: | |
| 113 | ✗ | max = psTimings[to][tc]; | |
| 114 | ✗ | break; | |
| 115 | ✗ | case 1: | |
| 116 | ✗ | max = v2Timings[to][tc]; | |
| 117 | ✗ | break; | |
| 118 | 14 | default: | |
| 119 | 14 | max = v1Timings[to][tc]; | |
| 120 | 14 | break; | |
| 121 | } | ||
| 122 | |||
| 123 | // timings are based on 32 pixel wide panels | ||
| 124 | 14 | max *= m_panelWidth; | |
| 125 | 14 | max /= 32; | |
| 126 | |||
| 127 | // 1/4 scan we need to double the time since we have twice the number of pixels to clock out | ||
| 128 | 14 | max *= m_panelHeight; | |
| 129 | 14 | max /= (m_panelScan * 2); | |
| 130 | |||
| 131 | 14 | uint32_t origMax = max; | |
| 132 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
14 | if (m_colorDepth >= 11 && max < 0x9000) { |
| 133 | // for depth 10, we'll need a little more on time | ||
| 134 | // or the last bit will be on far too short | ||
| 135 | ✗ | max = 0x9000; | |
| 136 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
14 | } else if (m_colorDepth >= 10 && max < 0x8000) { |
| 137 | // for depth 10, we'll need a little more on time | ||
| 138 | // or the last bit will be on far too short | ||
| 139 | ✗ | max = 0x8000; | |
| 140 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
14 | } else if (m_colorDepth == 9 && max < 0x6800) { |
| 141 | // for depth 9, we'll need a little more on time | ||
| 142 | ✗ | max = 0x6800; | |
| 143 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
|
14 | } else if (max < 0x4500) { |
| 144 | // if max is too low, the low bit time is too short and | ||
| 145 | // extra ghosting occurs | ||
| 146 | // At this point, framerate will be supper high anyway >100fps | ||
| 147 | 12 | max = 0x4500; | |
| 148 | } | ||
| 149 | |||
| 150 | 14 | uint32_t origMax2 = max; | |
| 151 | |||
| 152 | 14 | max *= m_brightness; | |
| 153 | 14 | max /= 10; | |
| 154 | |||
| 155 | 14 | uint32_t delay = origMax2 - max; | |
| 156 |
3/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
14 | if ((origMax2 > origMax) && (origMax > max)) { |
| 157 | ✗ | delay = origMax - max; | |
| 158 | } | ||
| 159 | |||
| 160 | 14 | int maxBit = 8; | |
| 161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (m_colorDepth > 8) { |
| 162 | ✗ | maxBit = m_colorDepth; | |
| 163 | } | ||
| 164 | // printf("Delay : %d Max: %d OrigMax: %d OrigMax2: %d\n", delay, max, origMax, origMax2); | ||
| 165 |
2/2✓ Branch 0 taken 112 times.
✓ Branch 1 taken 14 times.
|
126 | for (int x = 0; x < maxBit; x++) { |
| 166 |
1/2✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
|
112 | LogDebug(VB_CHANNELOUT, "Brightness %d: %X\n", x, max); |
| 167 | 112 | delayValues[x] = delay; | |
| 168 | 112 | brightnessValues[x] = max; | |
| 169 | 112 | max >>= 1; | |
| 170 | 112 | origMax >>= 1; | |
| 171 | } | ||
| 172 | // low value cannot be less than 20 or ghosting | ||
| 173 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (brightnessValues[maxBit - 1] < 20) { |
| 174 | ✗ | brightnessValues[maxBit - 1] = 20; | |
| 175 | } | ||
| 176 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (brightnessValues[maxBit - 2] < brightnessValues[maxBit - 1]) { |
| 177 | ✗ | brightnessValues[maxBit - 2] = brightnessValues[maxBit - 2] + 5; | |
| 178 | } | ||
| 179 | |||
| 180 |
3/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 13 times.
|
14 | if (FileExists("/home/fpp/media/config/ledscape_dimming")) { |
| 181 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | FILE* file = fopen("/home/fpp/media/config/ledscape_dimming", "r"); |
| 182 | |||
| 183 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (file != NULL) { |
| 184 | // fgets, not getline: getline() was handed a stack buffer as if it | ||
| 185 | // were malloc'd, and a line of 100 characters or more made it | ||
| 186 | // realloc() the stack | ||
| 187 | char line[100]; | ||
| 188 | 1 | int count = 0; | |
| 189 | |||
| 190 |
6/8✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 1 times.
|
5 | while ((count < 10) && fgets(line, sizeof(line), file)) { |
| 191 | 4 | size_t read = strlen(line); | |
| 192 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | if ((!read) || (read == 1)) |
| 193 | ✗ | continue; | |
| 194 | |||
| 195 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | LogDebug(VB_CHANNELOUT, "Line %d: %s\n", count, line); |
| 196 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (count == 0) { |
| 197 | 1 | m_printStats = atoi(line); | |
| 198 | 1 | count++; | |
| 199 | } else { | ||
| 200 | uint32_t d1, d2; | ||
| 201 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (sscanf(line, "%X %X", &d1, &d2) == 2) { |
| 202 | 3 | brightnessValues[count - 1] = d1; | |
| 203 | 3 | delayValues[count - 1] = d2; | |
| 204 | } | ||
| 205 | 3 | count++; | |
| 206 | } | ||
| 207 | } | ||
| 208 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | fclose(file); |
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | char buf[255]; | ||
| 213 | |||
| 214 | 14 | int x = m_colorDepth; | |
| 215 | 14 | m_bitOrder.clear(); | |
| 216 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (m_outputByRow) { |
| 217 | // if outputing by row, we have to keep in decending order | ||
| 218 | ✗ | for (int x = m_colorDepth; x > 0; --x) { | |
| 219 | ✗ | m_bitOrder.push_back(x - 1); | |
| 220 | } | ||
| 221 | } else { | ||
| 222 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | m_bitOrder = BIT_ORDERS[m_colorDepth]; |
| 223 | } | ||
| 224 | |||
| 225 |
2/2✓ Branch 0 taken 110 times.
✓ Branch 1 taken 14 times.
|
124 | for (auto b : m_bitOrder) { |
| 226 | 110 | int idx = m_colorDepth - b - 1; | |
| 227 | 110 | snprintf(buf, sizeof(buf), "-DBRIGHTNESS%d=%d", x, brightnessValues[idx]); | |
| 228 | |||
| 229 |
2/4✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 110 times.
✗ Branch 3 not taken.
|
110 | sargs.push_back(buf); |
| 230 | 110 | snprintf(buf, sizeof(buf), "-DDELAY%d=%d", x, delayValues[idx]); | |
| 231 |
2/4✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 110 times.
✗ Branch 3 not taken.
|
110 | sargs.push_back(buf); |
| 232 | 110 | x--; | |
| 233 | } | ||
| 234 | 14 | } | |
| 235 | |||
| 236 | 15 | BBBMatrix::BBBMatrix(unsigned int startChannel, unsigned int channelCount) : | |
| 237 | ChannelOutput(startChannel, channelCount), | ||
| 238 | 15 | m_pru(nullptr), | |
| 239 | 15 | m_pruCopy(nullptr), | |
| 240 | 15 | m_matrix(nullptr), | |
| 241 | 15 | m_panelMatrix(nullptr), | |
| 242 | 15 | m_outputs(0), | |
| 243 | 15 | m_gpioFrame(nullptr), | |
| 244 | 15 | m_longestChain(0), | |
| 245 | 15 | m_panelWidth(32), | |
| 246 | 15 | m_panelHeight(16), | |
| 247 | 15 | m_invertedData(0), | |
| 248 | 15 | m_brightness(10), | |
| 249 | 15 | m_colorDepth(8), | |
| 250 | 15 | m_panelInterleave(), | |
| 251 | 15 | m_panelScan(8), | |
| 252 | 15 | m_timing(0), | |
| 253 | 15 | m_printStats(false), | |
| 254 | 15 | m_handler(nullptr), | |
| 255 | 15 | m_outputByRow(false), | |
| 256 | 15 | m_outputBlankData(false), | |
| 257 | 15 | m_curFrame(0), | |
| 258 | 15 | m_numFrames(0) { | |
| 259 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | LogDebug(VB_CHANNELOUT, "BBBMatrix::BBBMatrix(%u, %u)\n", |
| 260 | startChannel, channelCount); | ||
| 261 | 15 | } | |
| 262 | |||
| 263 | 60 | BBBMatrix::~BBBMatrix() { | |
| 264 | 30 | LogDebug(VB_CHANNELOUT, "BBBMatrix::~BBBMatrix()\n"); | |
| 265 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
30 | if (m_gpioFrame) |
| 266 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
30 | delete[] m_gpioFrame; |
| 267 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
30 | if (m_pru) |
| 268 | ✗ | delete m_pru; | |
| 269 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
30 | if (m_pruCopy) |
| 270 | ✗ | delete m_pruCopy; | |
| 271 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
30 | if (m_handler) |
| 272 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
30 | delete m_handler; |
| 273 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
30 | if (m_matrix) |
| 274 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
30 | delete m_matrix; |
| 275 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
30 | if (m_panelMatrix) |
| 276 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
30 | delete m_panelMatrix; |
| 277 | 60 | } | |
| 278 | |||
| 279 | 99 | bool BBBMatrix::configureControlPin(const std::string& ctype, Json::Value& root, std::ofstream& outputFile, int pru, int& controlGPIO) { | |
| 280 |
4/8✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 99 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 99 times.
✗ Branch 7 not taken.
|
99 | std::string type = root["controls"][ctype]["type"].asString(); |
| 281 |
2/4✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
|
99 | if (type != "none") { |
| 282 |
4/8✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 99 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 99 times.
✗ Branch 7 not taken.
|
99 | std::string pinName = root["controls"][ctype]["pin"].asString(); |
| 283 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | m_usedGPIOS.push_back(pinName); |
| 284 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | const PinCapabilities& pin = PinCapabilities::getPinByName(pinName); |
| 285 |
5/8✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 85 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 14 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 99 times.
|
99 | if (ctype == "oe" && pin.pwm >= 99) { |
| 286 | ✗ | outputFile << "#define oe_pwm_address " << std::to_string(pin.getPWMRegisterAddress()) << "\n"; | |
| 287 | ✗ | outputFile << "#define oe_pwm_output " << std::to_string(pin.subPwm) << "\n"; | |
| 288 | ✗ | int max = 300 * 255; | |
| 289 | // FIXME - adjust max for brightness | ||
| 290 | ✗ | pin.setupPWM(max); | |
| 291 | ✗ | pin.setPWMValue(0); | |
| 292 | ✗ | return true; | |
| 293 | } else { | ||
| 294 |
3/4✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 97 times.
|
99 | if (type == "pruout") { |
| 295 |
4/8✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
6 | pin.configPin("pru" + std::to_string(pru) + "out"); |
| 296 | 2 | const BBBPinCapabilities* bp = static_cast<const BBBPinCapabilities*>(&pin); | |
| 297 |
5/10✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
|
2 | outputFile << "#define pru_" << ctype << " " << std::to_string(bp->pruPin(pru)) << "\n"; |
| 298 | } else { | ||
| 299 |
2/4✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 97 times.
✗ Branch 3 not taken.
|
194 | pin.configPin(type); |
| 300 |
6/12✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 97 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 97 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 97 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 97 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 97 times.
✗ Branch 11 not taken.
|
97 | outputFile << "#define gpio_" << ctype << " " << std::to_string(pin.mappedGPIO()) << "\n"; |
| 301 |
1/2✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
|
97 | controlGPIO = pin.mappedGPIOIdx(); |
| 302 | } | ||
| 303 | } | ||
| 304 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | } |
| 305 | 99 | return false; | |
| 306 | 99 | } | |
| 307 | |||
| 308 | 102 | void BBBMatrix::configurePanelPin(int x, const std::string& color, int row, Json::Value& root, std::ofstream& outputFile, int* minPort) { | |
| 309 |
6/12✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 102 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 102 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 102 times.
✗ Branch 11 not taken.
|
102 | std::string pinName = root["outputs"][x]["pins"][color + std::to_string(row)].asString(); |
| 310 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | const PinCapabilities& pin = PinCapabilities::getPinByName(pinName); |
| 311 |
3/6✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
|
408 | pin.configPin(); |
| 312 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | m_usedGPIOS.push_back(pinName); |
| 313 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | int gpioIdx = pin.mappedGPIOIdx(); |
| 314 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | minPort[gpioIdx] = std::min(minPort[gpioIdx], (int)pin.mappedGPIO()); |
| 315 |
8/16✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 102 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 102 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 102 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 102 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 102 times.
✗ Branch 15 not taken.
|
102 | outputFile << "#define " << color << std::to_string(x + 1) << std::to_string(row) << "_gpio " << std::to_string(pin.mappedGPIOIdx()) << "\n"; |
| 316 |
8/16✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 102 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 102 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 102 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 102 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 102 times.
✗ Branch 15 not taken.
|
102 | outputFile << "#define " << color << std::to_string(x + 1) << std::to_string(row) << "_pin " << std::to_string(pin.mappedGPIO()) << "\n"; |
| 317 | |||
| 318 |
3/4✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 68 times.
|
102 | if (color == "r") { |
| 319 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | m_pinInfo[x].row[row - 1].r_gpio = pin.mappedGPIOIdx(); |
| 320 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | m_pinInfo[x].row[row - 1].r_pin = 1UL << pin.mappedGPIO(); |
| 321 |
3/4✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 34 times.
|
68 | } else if (color == "g") { |
| 322 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | m_pinInfo[x].row[row - 1].g_gpio = pin.mappedGPIOIdx(); |
| 323 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | m_pinInfo[x].row[row - 1].g_pin = 1UL << pin.mappedGPIO(); |
| 324 | } else { | ||
| 325 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | m_pinInfo[x].row[row - 1].b_gpio = pin.mappedGPIOIdx(); |
| 326 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | m_pinInfo[x].row[row - 1].b_pin = 1UL << pin.mappedGPIO(); |
| 327 | } | ||
| 328 | 102 | } | |
| 329 | |||
| 330 | 17 | void BBBMatrix::configurePanelPins(int x, Json::Value& root, std::ofstream& outputFile, int* minPort) { | |
| 331 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
34 | configurePanelPin(x, "r", 1, root, outputFile, minPort); |
| 332 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
34 | configurePanelPin(x, "g", 1, root, outputFile, minPort); |
| 333 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | configurePanelPin(x, "b", 1, root, outputFile, minPort); |
| 334 | 17 | outputFile << "\n"; | |
| 335 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
34 | configurePanelPin(x, "r", 2, root, outputFile, minPort); |
| 336 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
34 | configurePanelPin(x, "g", 2, root, outputFile, minPort); |
| 337 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | configurePanelPin(x, "b", 2, root, outputFile, minPort); |
| 338 | 17 | outputFile << "\n"; | |
| 339 | 17 | } | |
| 340 | |||
| 341 | 15 | int BBBMatrix::Init(Json::Value config) { | |
| 342 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | LogDebug(VB_CHANNELOUT, "BBBMatrix::Init(JSON)\n"); |
| 343 | |||
| 344 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | m_panelWidth = config["panelWidth"].asInt(); |
| 345 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | m_panelHeight = config["panelHeight"].asInt(); |
| 346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (!m_panelWidth) |
| 347 | ✗ | m_panelWidth = 32; | |
| 348 | |||
| 349 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (!m_panelHeight) |
| 350 | ✗ | m_panelHeight = 16; | |
| 351 | |||
| 352 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | int addressingType = config["panelRowAddressType"].asInt(); |
| 353 | |||
| 354 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | m_invertedData = config["invertedData"].asInt(); |
| 355 |
3/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
|
15 | m_colorOrder = ColorOrderFromString(config["colorOrder"].asString()); |
| 356 | |||
| 357 |
3/8✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
15 | m_panelMatrix = new PanelMatrix(m_panelWidth, m_panelHeight, m_invertedData); |
| 358 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (!m_panelMatrix) { |
| 359 | ✗ | LogErr(VB_CHANNELOUT, "BBBMatrix: Unable to create PanelMatrix\n"); | |
| 360 | ✗ | return 0; | |
| 361 | } | ||
| 362 | 15 | bool usesOutput[16] = { | |
| 363 | false, false, false, false, | ||
| 364 | false, false, false, false, | ||
| 365 | false, false, false, false, | ||
| 366 | false, false, false, false | ||
| 367 | }; | ||
| 368 |
4/6✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 15 times.
|
34 | for (int i = 0; i < config["panels"].size(); i++) { |
| 369 |
3/6✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
|
19 | Json::Value p = config["panels"][i]; |
| 370 | 19 | char orientation = 'N'; | |
| 371 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
|
19 | std::string o = p["orientation"].asString(); |
| 372 | |||
| 373 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | if (!o.empty()) |
| 374 | 19 | orientation = o[0]; | |
| 375 | |||
| 376 |
4/8✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19 times.
✗ Branch 7 not taken.
|
19 | if (p["colorOrder"].asString() == "") |
| 377 |
3/6✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
|
19 | p["colorOrder"] = ColorOrderToString(m_colorOrder); |
| 378 | |||
| 379 | // the cape has at most 16 outputs, and usesOutput is sized for that | ||
| 380 |
3/6✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19 times.
|
19 | if (p["outputNumber"].asInt() >= 16) { |
| 381 | ✗ | LogErr(VB_CHANNELOUT, "Invalid panel output number %d\n", p["outputNumber"].asInt()); | |
| 382 | ✗ | continue; | |
| 383 | } | ||
| 384 | // a refused panel (out of range) must not count toward the outputs or chains below | ||
| 385 |
4/8✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19 times.
✗ Branch 7 not taken.
|
38 | if (!m_panelMatrix->AddPanel(p["outputNumber"].asInt(), |
| 386 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
|
19 | p["panelNumber"].asInt(), orientation, |
| 387 |
4/8✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19 times.
✗ Branch 7 not taken.
|
19 | p["xOffset"].asInt(), p["yOffset"].asInt(), |
| 388 |
3/6✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19 times.
|
38 | ColorOrderFromString(p["colorOrder"].asString()))) { |
| 389 | ✗ | continue; | |
| 390 | } | ||
| 391 | |||
| 392 |
4/6✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 15 times.
|
19 | if (p["outputNumber"].asInt() > m_outputs) |
| 393 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | m_outputs = p["outputNumber"].asInt(); |
| 394 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
|
19 | usesOutput[p["outputNumber"].asInt()] = true; |
| 395 | |||
| 396 |
4/6✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 17 times.
|
19 | if (p["panelNumber"].asInt() > m_longestChain) |
| 397 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | m_longestChain = p["panelNumber"].asInt(); |
| 398 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
|
19 | } |
| 399 | // Both of these are 0-based, so bump them up by 1 for comparisons | ||
| 400 | 15 | m_outputs++; | |
| 401 | 15 | m_longestChain++; | |
| 402 | |||
| 403 | // get the dimensions of the matrix | ||
| 404 | 15 | m_panels = m_panelMatrix->PanelCount(); | |
| 405 | 15 | m_rows = m_outputs * m_panelHeight; | |
| 406 | 15 | m_width = m_panelMatrix->Width(); | |
| 407 | 15 | m_height = m_panelMatrix->Height(); | |
| 408 | |||
| 409 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | if (config.isMember("brightness")) { |
| 410 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | m_brightness = config["brightness"].asInt(); |
| 411 | } | ||
| 412 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
|
15 | if (m_brightness < 1 || m_brightness > 10) { |
| 413 | ✗ | m_brightness = 10; | |
| 414 | } | ||
| 415 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | if (config.isMember("panelColorDepth")) { |
| 416 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | m_colorDepth = config["panelColorDepth"].asInt(); |
| 417 | } | ||
| 418 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | if (config.isMember("panelOutputOrder")) { |
| 419 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | m_outputByRow = config["panelOutputOrder"].asBool(); |
| 420 | } | ||
| 421 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
|
15 | if (config.isMember("panelOutputBlankRow")) { |
| 422 | ✗ | m_outputBlankData = config["panelOutputBlankRow"].asBool(); | |
| 423 | } | ||
| 424 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (m_colorDepth < 0) { |
| 425 | ✗ | m_colorDepth = -m_colorDepth; | |
| 426 | ✗ | m_outputBlankData = true; | |
| 427 | } | ||
| 428 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
|
15 | if (m_colorDepth > 12 || m_colorDepth < 6) { |
| 429 | ✗ | m_colorDepth = 8; | |
| 430 | } | ||
| 431 | |||
| 432 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | if (config.isMember("panelInterleave")) { |
| 433 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | m_panelInterleave = config["panelInterleave"].asString(); |
| 434 | } | ||
| 435 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | m_panelScan = config["panelScan"].asInt(); |
| 436 | // printf("Interleave: %d Scan: %d ZZI: %d ZZCI: %d SI: %d\n", m_interleave, m_panelScan, zigZagInterleave, zigZagClusterInterleave, stripeInterleave); | ||
| 437 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (m_panelScan == 0) { |
| 438 | // default scan is 1/2 the height of the panel | ||
| 439 | ✗ | m_panelScan = m_panelHeight / 2; | |
| 440 | } | ||
| 441 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | m_handler = PanelInterleaveHandler::createHandler(m_panelInterleave, m_panelWidth, m_panelHeight, m_panelScan); |
| 442 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (!m_handler) { |
| 443 | // A panel that scans fewer rows than half its height folds the rest | ||
| 444 | // into extra columns, so it needs an interleave that matches; without | ||
| 445 | // one the pixels have nowhere to go. | ||
| 446 | ✗ | LogErr(VB_CHANNELOUT, "BBBMatrix: Panel interleave '%s' cannot map a %dx%d 1/%d scan panel\n", | |
| 447 | m_panelInterleave.c_str(), m_panelWidth, m_panelHeight, m_panelScan); | ||
| 448 | ✗ | AddOutputConfigWarning(50, "LED panel output disabled: panel interleave '" + m_panelInterleave + | |
| 449 | ✗ | "' is not valid for a " + std::to_string(m_panelWidth) + "x" + std::to_string(m_panelHeight) + | |
| 450 | ✗ | " 1/" + std::to_string(m_panelScan) + " scan panel. Set the Panel Interleave to match the panel."); | |
| 451 | ✗ | return 0; | |
| 452 | } | ||
| 453 | 15 | m_channelCount = m_width * m_height * 3; | |
| 454 | |||
| 455 |
3/8✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
15 | m_matrix = new Matrix(m_startChannel, m_width, m_height); |
| 456 | |||
| 457 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
|
15 | if (config.isMember("subMatrices")) { |
| 458 | ✗ | for (int i = 0; i < config["subMatrices"].size(); i++) { | |
| 459 | ✗ | Json::Value sm = config["subMatrices"][i]; | |
| 460 | |||
| 461 | ✗ | m_matrix->AddSubMatrix( | |
| 462 | ✗ | sm["enabled"].asInt(), | |
| 463 | ✗ | sm["startChannel"].asInt() - 1, | |
| 464 | ✗ | sm["width"].asInt(), | |
| 465 | ✗ | sm["height"].asInt(), | |
| 466 | ✗ | sm["xOffset"].asInt(), | |
| 467 | ✗ | sm["yOffset"].asInt()); | |
| 468 | ✗ | } | |
| 469 | } | ||
| 470 | |||
| 471 | 15 | m_rowSize = m_longestChain * m_panelWidth * 3; | |
| 472 | 15 | int maxBits = 8; | |
| 473 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (m_colorDepth > 8) { |
| 474 | ✗ | maxBits = m_colorDepth; | |
| 475 | } | ||
| 476 | 15 | int gpioFrameLen = m_longestChain * m_panelWidth * maxBits * (m_panelHeight / 2) * 4; | |
| 477 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | m_gpioFrame = new uint32_t[gpioFrameLen]; |
| 478 | 15 | memset(m_gpioFrame, 0, gpioFrameLen * 4); | |
| 479 | |||
| 480 | 15 | std::vector<std::string> compileArgs; | |
| 481 | |||
| 482 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
30 | std::string dirname = "bbb"; |
| 483 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | std::string name = "Octoscroller"; |
| 484 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
|
15 | if (getBeagleBoneType() == PocketBeagle) { |
| 485 | ✗ | dirname = "pb"; | |
| 486 | ✗ | name = "PocketScroller"; | |
| 487 | } | ||
| 488 |
4/8✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
|
15 | if (config["wiringPinout"] == "v2") { |
| 489 | ✗ | name += "-v2"; | |
| 490 | } | ||
| 491 |
5/8✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 14 times.
|
15 | if (config["wiringPinout"] == "v3") { |
| 492 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | name += "-v3"; |
| 493 | } | ||
| 494 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | Json::Value root; |
| 495 | char filename[256]; | ||
| 496 | 15 | int minPort[4] = { 99, 99, 99, 99 }; | |
| 497 | 15 | int pru = 0; | |
| 498 | 15 | snprintf(filename, sizeof(filename), "/home/fpp/media/tmp/panels/%s.json", name.c_str()); | |
| 499 |
3/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 14 times.
|
15 | if (!FileExists(filename)) { |
| 500 | 1 | snprintf(filename, sizeof(filename), "/home/fpp/media/tmp/panels/CapePanels.json", dirname.c_str()); | |
| 501 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (FileExists(filename)) { |
| 502 | ✗ | name = "CapePanels"; | |
| 503 | } | ||
| 504 | } | ||
| 505 |
3/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 14 times.
|
15 | if (!FileExists(filename)) { |
| 506 | 1 | snprintf(filename, sizeof(filename), "/opt/fpp/capes/%s/panels/%s.json", dirname.c_str(), name.c_str()); | |
| 507 | } | ||
| 508 | 15 | bool isPWM = false; | |
| 509 |
3/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 14 times.
|
15 | if (!FileExists(filename)) { |
| 510 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | LogErr(VB_CHANNELOUT, "No output pin configuration for %s - %s\n", name.c_str(), filename); |
| 511 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | AddOutputConfigWarning(50, "LED panel output: no output pin configuration for " + name); |
| 512 | 1 | return 0; | |
| 513 | } else { | ||
| 514 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | LogDebug(VB_CHANNELOUT, "Using panel pinout from %s\n", filename); |
| 515 |
3/6✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14 times.
|
28 | if (!LoadJsonFromFile(filename, root, JsonRoot::Object)) { |
| 516 | ✗ | LogErr(VB_CHANNELOUT, "Could not read pin configuration for %s - %s\n", name.c_str(), filename); | |
| 517 | ✗ | AddOutputConfigWarning(50, "LED panel output: could not read pin configuration for " + name); | |
| 518 | ✗ | return 0; | |
| 519 | } | ||
| 520 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | std::string longName = root["longName"].asString(); |
| 521 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | LogDebug(VB_CHANNELOUT, "Using pin configuration for %s from %s\n", longName.c_str(), filename); |
| 522 | |||
| 523 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | std::ofstream outputFile; |
| 524 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | outputFile.open("/tmp/PanelPinConfiguration.hp", std::ofstream::out | std::ofstream::trunc); |
| 525 | |||
| 526 | // kind of a hack, ideally the timing info would go into the json as well | ||
| 527 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | m_timing = root["timing"].asInt(); |
| 528 | |||
| 529 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | pru = root["pru"].asInt(); |
| 530 | |||
| 531 |
3/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 9 times.
|
14 | if (root.isMember("singlePRU")) { |
| 532 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | m_singlePRU = root["singlePRU"].asBool(); |
| 533 | } | ||
| 534 | // m_singlePRU = true; | ||
| 535 | |||
| 536 |
3/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 12 times.
|
14 | if (root.isMember("dataOffset")) { |
| 537 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | m_dataOffset = root["dataOffset"].asInt(); |
| 538 | 2 | m_dataOffset *= 1024; // dataOffset is in KB | |
| 539 | } | ||
| 540 | |||
| 541 |
3/6✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
14 | int controlGpio = root["controls"]["gpio"].asInt(); |
| 542 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | configureControlPin("latch", root, outputFile, pru, controlGpio); |
| 543 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | outputFile << "\n"; |
| 544 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | isPWM = configureControlPin("oe", root, outputFile, pru, controlGpio); |
| 545 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | outputFile << "\n"; |
| 546 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | configureControlPin("clock", root, outputFile, pru, controlGpio); |
| 547 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | outputFile << "\n"; |
| 548 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
28 | configureControlPin("sel0", root, outputFile, pru, controlGpio); |
| 549 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
28 | configureControlPin("sel1", root, outputFile, pru, controlGpio); |
| 550 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
28 | configureControlPin("sel2", root, outputFile, pru, controlGpio); |
| 551 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | configureControlPin("sel3", root, outputFile, pru, controlGpio); |
| 552 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13 times.
|
14 | if (m_panelScan > 16) { |
| 553 | // a row address of 16 or more needs the fifth "E" line - 1/32 | ||
| 554 | // scan, and 80x40 1/20 scan (rows 16-19) | ||
| 555 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | configureControlPin("sel4", root, outputFile, pru, controlGpio); |
| 556 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | compileArgs.push_back("-DE_SCAN_LINE"); |
| 557 | } | ||
| 558 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | outputFile << "\n"; |
| 559 |
3/6✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
14 | outputFile << "#define CONTROLS_GPIO_BASE GPIO" << std::to_string(controlGpio) << "\n"; |
| 560 |
3/6✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
14 | outputFile << "#define gpio_controls_led_mask gpio" << std::to_string(controlGpio) << "_led_mask\n"; |
| 561 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | outputFile << "\n"; |
| 562 |
3/6✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14 times.
|
14 | if (m_outputs > root["outputs"].size()) { |
| 563 | ✗ | m_outputs = root["outputs"].size(); | |
| 564 | } | ||
| 565 |
2/2✓ Branch 0 taken 112 times.
✓ Branch 1 taken 14 times.
|
126 | for (int x = 0; x < 8; x++) { |
| 566 |
3/4✓ Branch 0 taken 17 times.
✓ Branch 1 taken 95 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
112 | if (usesOutput[x] && x < m_outputs) { |
| 567 |
1/2✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
|
17 | configurePanelPins(x, root, outputFile, minPort); |
| 568 | } else { | ||
| 569 |
3/6✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 95 times.
✗ Branch 5 not taken.
|
95 | outputFile << "#define NO_OUTPUT_" << std::to_string(x + 1) << "\n"; |
| 570 |
1/2✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
|
95 | outputFile << "\n"; |
| 571 | } | ||
| 572 | } | ||
| 573 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | outputFile << "\n"; |
| 574 | #ifdef PLATFORM_BBB | ||
| 575 | // Dual PRU split output: the copy PRU writes up to two of the data | ||
| 576 | // GPIO banks itself (see FalconMatrixPRUCpy.asm), roughly a 1.35x | ||
| 577 | // higher pixel clock. The controls bank and GPIO0 (which has | ||
| 578 | // multi-microsecond write-landing jitter on the L4_WKUP bus) stay | ||
| 579 | // on the output PRU so their behavior is unchanged. AM335x only. | ||
| 580 | // | ||
| 581 | // Not with a GPIO clock: the clock write is posted, so the copy PRU | ||
| 582 | // can't write the next pixel until a read back proves the edge has | ||
| 583 | // landed (ACK_SPLIT), and that read makes the split slower than one | ||
| 584 | // PRU doing everything (measured 70Hz vs 100Hz). Without it the copy | ||
| 585 | // PRU's data beat ~1 in 5 clock edges and bled into the neighbouring | ||
| 586 | // pixel. A PRU (r30) clock is immediate and needs no read back. | ||
| 587 |
5/10✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14 times.
✗ Branch 9 not taken.
|
14 | bool gpioClock = root["controls"]["clock"]["type"].asString() != "pruout"; |
| 588 |
16/26✓ Branch 0 taken 9 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✓ Branch 17 taken 12 times.
✓ Branch 18 taken 2 times.
✓ Branch 19 taken 12 times.
✓ Branch 20 taken 2 times.
✓ Branch 21 taken 12 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
|
14 | if (!m_singlePRU && !gpioClock && !root.get("noSplitOutput", false).asBool() && getSettingInt("BBBMatrixNoSplitOutput", 0) == 0) { |
| 589 | 2 | int cnt = 0; | |
| 590 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
|
8 | for (int x = 3; x > 0; x--) { // never GPIO0 |
| 591 |
4/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
6 | if (minPort[x] != 99 && x != controlGpio && cnt < 2) { |
| 592 | 2 | m_splitCpyBanks[x] = true; | |
| 593 | 2 | cnt++; | |
| 594 | } | ||
| 595 | } | ||
| 596 | 2 | m_splitOutput = cnt > 0; | |
| 597 | } | ||
| 598 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
|
14 | if (m_splitOutput) { |
| 599 |
4/8✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
2 | LogDebug(VB_CHANNELOUT, "BBBMatrix: split output, copy PRU owns GPIO banks:%s%s%s\n", |
| 600 | m_splitCpyBanks[1] ? " 1" : "", m_splitCpyBanks[2] ? " 2" : "", m_splitCpyBanks[3] ? " 3" : ""); | ||
| 601 | } | ||
| 602 | #endif | ||
| 603 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 14 times.
|
70 | for (int x = 0; x < 4; x++) { |
| 604 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 27 times.
|
56 | if (minPort[x] != 99) { |
| 605 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 28 times.
|
29 | if (x == controlGpio) { |
| 606 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | outputFile << "#define OUTPUT_GPIO_" << std::to_string(x) << "(a, b, c, d) OUTPUT_GPIO_FORCE_CLEAR a, b, c, d\n"; |
| 607 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 26 times.
|
28 | } else if (m_splitCpyBanks[x]) { |
| 608 | // in split mode the copy PRU owns this bank; the output | ||
| 609 | // PRU compiles the bank's writes out | ||
| 610 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | outputFile << "#if defined(SPLIT_GPIO) && !defined(IN_CPY_PRU)\n"; |
| 611 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | outputFile << "#define OUTPUT_GPIO_" << std::to_string(x) << "(a, b, c, d)\n"; |
| 612 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | outputFile << "#else\n"; |
| 613 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | outputFile << "#define OUTPUT_GPIO_" << std::to_string(x) << "(a, b, c, d) OUTPUT_GPIO a, b, c, d\n"; |
| 614 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | outputFile << "#endif\n"; |
| 615 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | outputFile << "#define CPY_OWNS_GPIO" << std::to_string(x) << "\n"; |
| 616 | } else { | ||
| 617 |
3/6✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
|
26 | outputFile << "#define OUTPUT_GPIO_" << std::to_string(x) << "(a, b, c, d) OUTPUT_GPIO a, b, c, d\n"; |
| 618 | } | ||
| 619 | } else { | ||
| 620 |
3/6✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
|
27 | outputFile << "#define OUTPUT_GPIO_" << std::to_string(x) << "(a, b, c, d)\n"; |
| 621 | } | ||
| 622 | } | ||
| 623 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | outputFile << "\n"; |
| 624 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
|
14 | if (minPort[controlGpio] == 99) { |
| 625 | // not outputting anything on the GPIO the controls are using | ||
| 626 | // we need to make sure the controls are set/cleared indepentent of the panel data | ||
| 627 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | outputFile << "#define NO_CONTROLS_WITH_DATA\n"; |
| 628 | } | ||
| 629 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | outputFile << "\n"; |
| 630 | |||
| 631 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | outputFile.close(); |
| 632 | 14 | } | |
| 633 | |||
| 634 | char buf[200]; | ||
| 635 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 9 times.
|
14 | if (m_singlePRU) { |
| 636 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
10 | compileArgs.push_back("-DSINGLEPRU"); |
| 637 | } | ||
| 638 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
|
14 | if (m_splitOutput) { |
| 639 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | compileArgs.push_back("-DSPLIT_GPIO"); |
| 640 | } | ||
| 641 | 14 | snprintf(buf, sizeof(buf), "-DRUNNING_ON_PRU%d", pru); | |
| 642 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | compileArgs.push_back(buf); |
| 643 | 14 | snprintf(buf, sizeof(buf), "-DRUNNING_ON_PRU=%d", pru); | |
| 644 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | compileArgs.push_back(buf); |
| 645 | 14 | snprintf(buf, sizeof(buf), "-DOUTPUTS=%d", m_outputs); | |
| 646 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | compileArgs.push_back(buf); |
| 647 | 14 | snprintf(buf, sizeof(buf), "-DROWS=%d", m_panelScan); | |
| 648 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | compileArgs.push_back(buf); |
| 649 | 14 | snprintf(buf, sizeof(buf), "-DBITS=%d", m_colorDepth); | |
| 650 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | compileArgs.push_back(buf); |
| 651 | 14 | int tmp = m_longestChain * m_panelWidth; | |
| 652 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (m_panelScan * 4 == m_panelHeight) { |
| 653 | ✗ | tmp *= 2; | |
| 654 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | } else if (m_panelScan * 8 == m_panelHeight) { |
| 655 | ✗ | tmp *= 4; | |
| 656 | } | ||
| 657 | 14 | snprintf(buf, sizeof(buf), "-DROW_LEN=%d", tmp); | |
| 658 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | compileArgs.push_back(buf); |
| 659 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (isPWM) { |
| 660 | ✗ | compileArgs.push_back("-DUSING_PWM"); | |
| 661 | } | ||
| 662 | |||
| 663 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (addressingType == 2) { |
| 664 | // 1/2 scan panel that uses 2 bits, bit one for scan row 1 and bit two for row 2 | ||
| 665 | // Normal addressing would be 1 bit, 0 for row 1, 1 for row 2 | ||
| 666 | ✗ | compileArgs.push_back("-DADDRESSING_AB=1"); | |
| 667 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | } else if (addressingType == 3) { |
| 668 | // the row drivers are shift registers clocked on A with data on C; | ||
| 669 | // every row change clocks one bit per panel row since panels can | ||
| 670 | // daisy chain a driver per band of scan rows | ||
| 671 | ✗ | compileArgs.push_back("-DADDRESSING_ABC_SHIFT=1"); | |
| 672 | ✗ | snprintf(buf, sizeof(buf), "-DROW_CHAIN=%d", m_panelHeight); | |
| 673 | ✗ | compileArgs.push_back(buf); | |
| 674 | } | ||
| 675 | |||
| 676 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | calcBrightnessFlags(compileArgs); |
| 677 | // m_printStats = true; | ||
| 678 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (m_printStats) { |
| 679 | ✗ | snprintf(buf, sizeof(buf), "-DENABLESTATS=1", m_outputs); | |
| 680 | ✗ | compileArgs.push_back("-DENABLESTATS=1"); | |
| 681 | } | ||
| 682 | |||
| 683 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (m_outputByRow) { |
| 684 | ✗ | compileArgs.push_back("-DOUTPUTBYROW"); | |
| 685 | ✗ | if (m_outputBlankData) { | |
| 686 | ✗ | compileArgs.push_back("-DOUTPUTBLANKROW"); | |
| 687 | } | ||
| 688 | } else { | ||
| 689 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
28 | compileArgs.push_back("-DOUTPUTBYDEPTH"); |
| 690 | } | ||
| 691 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | compilePRUMatrixCode(compileArgs); |
| 692 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | std::string pru_program = "/tmp/FalconMatrix.out"; |
| 693 | |||
| 694 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 5 times.
|
14 | if (!m_singlePRU) { |
| 695 |
3/8✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
9 | m_pruCopy = new BBBPru(pru ? 0 : 1); |
| 696 | } | ||
| 697 | |||
| 698 |
3/8✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
14 | m_pru = new BBBPru(pru); |
| 699 | 14 | m_pruData = (BBBPruMatrixData*)m_pru->data_ram; | |
| 700 | |||
| 701 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 5 times.
|
14 | if (!m_singlePRU) { |
| 702 |
3/6✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
|
27 | if (!m_pruCopy->run("/tmp/FalconMatrixPRUCpy.out")) { |
| 703 | ✗ | LogErr(VB_CHANNELOUT, "BBBMatrix: Unable to start PRU. May require a reboot.\n"); | |
| 704 | ✗ | AddOutputConfigWarning(20, "BBBMatrix: Unable to start PRU. May require a reboot."); | |
| 705 | ✗ | return 0; | |
| 706 | } | ||
| 707 | } | ||
| 708 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
|
14 | if (!m_pru->run(pru_program)) { |
| 709 | ✗ | LogErr(VB_CHANNELOUT, "BBBMatrix: Unable to start PRU. May require a reboot.\n"); | |
| 710 | ✗ | AddOutputConfigWarning(20, "BBBMatrix: Unable to start PRU. May require a reboot."); | |
| 711 | ✗ | return 0; | |
| 712 | } | ||
| 713 | |||
| 714 | // Nothing may touch the PRU memories before run() has started the core. | ||
| 715 | // The PRUSS is only clocked once its firmware is loaded and running, so an | ||
| 716 | // earlier access is dropped at best and aborts the process at worst - and | ||
| 717 | // run() clears the whole data RAM as its last step anyway, so a write made | ||
| 718 | // before it could never have survived. The sibling PRU outputs | ||
| 719 | // (BBB48String, BBBSerial, BBShiftString, BBShiftPanel) all order it this | ||
| 720 | // way; this one did not, which is why a board whose PRUSS was left | ||
| 721 | // unpowered segfaulted here instead of reporting the error above. | ||
| 722 | 14 | m_pruData->address_dma = m_pru->ddr_addr + m_dataOffset; | |
| 723 | 14 | m_pruData->command = 0; | |
| 724 | 14 | m_pruData->response = 0; | |
| 725 | |||
| 726 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | GammaLUT::BuildForColorDepth(gammaCurve, GammaLUT::ParseConfig(config, 2.2f), m_colorDepth); |
| 727 | |||
| 728 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (isPWM) { |
| 729 | // need to calculate the clock counts for the PWM subsystem | ||
| 730 | ✗ | int i = m_pruData->pwmBrightness[0]; | |
| 731 | ✗ | while (i == 0) { | |
| 732 | ✗ | i = m_pruData->pwmBrightness[0]; | |
| 733 | } | ||
| 734 | ✗ | printf("PERIOD: %X\n", i); | |
| 735 | |||
| 736 | ✗ | int f = i; | |
| 737 | // f *= 300; | ||
| 738 | // f /= 500; | ||
| 739 | ✗ | i = f; | |
| 740 | ✗ | printf("New PERIOD: %X\n", i); | |
| 741 | |||
| 742 | ✗ | i *= m_brightness; | |
| 743 | ✗ | i /= 10; | |
| 744 | ✗ | for (int x = 0; x < 8; x++) { | |
| 745 | ✗ | printf("%d: %X\n", x, i); | |
| 746 | ✗ | m_pruData->pwmBrightness[7 - x] = i; | |
| 747 | ✗ | i /= 2; | |
| 748 | } | ||
| 749 | } | ||
| 750 | /* | ||
| 751 | for (int x = 0; x < 8; x++) { | ||
| 752 | printf("%d R1: %d %8X\n",x, m_pinInfo[x].row[0].r_gpio, m_pinInfo[x].row[0].r_pin); | ||
| 753 | printf(" G1: %d %8X\n", m_pinInfo[x].row[0].g_gpio, m_pinInfo[x].row[0].g_pin); | ||
| 754 | printf(" B1: %d %8X\n", m_pinInfo[x].row[0].b_gpio, m_pinInfo[x].row[0].b_pin); | ||
| 755 | printf(" R2: %d %8X\n", m_pinInfo[x].row[1].r_gpio, m_pinInfo[x].row[1].r_pin); | ||
| 756 | printf(" G2: %d %8X\n", m_pinInfo[x].row[1].g_gpio, m_pinInfo[x].row[1].g_pin); | ||
| 757 | printf(" B2: %d %8X\n", m_pinInfo[x].row[1].b_gpio, m_pinInfo[x].row[1].b_pin); | ||
| 758 | } | ||
| 759 | */ | ||
| 760 | |||
| 761 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | buildPrepTables(); |
| 762 | |||
| 763 | // make sure the PRU starts outputting a blank frame to remove any random noise | ||
| 764 | // from the panels | ||
| 765 | 14 | m_fullFrameLen = gpioFrameLen * 4; | |
| 766 | // round up to next page boundary | ||
| 767 | 14 | int alignedLen = m_fullFrameLen + 8192; | |
| 768 | 14 | alignedLen -= (alignedLen & 0xFFF); | |
| 769 | |||
| 770 | // the frame flipping slots come from the shared DDR region allocator so | ||
| 771 | // string/serial outputs on the same region (e.g. the K8-B-Scroller runs | ||
| 772 | // BBB48String + BBBSerial + panels) cannot overlap us; the cape's | ||
| 773 | // dataOffset is kept as a floor for the historic layout. 4 slots is | ||
| 774 | // plenty (3 is the tear-free flip threshold) and leaving the rest of | ||
| 775 | // the region free lets the other outputs grow on a partial reload. | ||
| 776 | 14 | m_numFrames = 4; | |
| 777 | 14 | uint8_t* framesBase = nullptr; | |
| 778 | 14 | uint32_t framesPhys = 0; | |
| 779 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | while (m_numFrames > 0) { |
| 780 |
2/4✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 | framesBase = BBBPru::ddrAlloc("BBBMatrix", (size_t)alignedLen * m_numFrames, framesPhys, m_dataOffset); |
| 781 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
|
16 | if (framesBase) { |
| 782 | 14 | break; | |
| 783 | } | ||
| 784 | 2 | m_numFrames--; | |
| 785 | } | ||
| 786 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (!framesBase) { |
| 787 | ✗ | LogErr(VB_CHANNELOUT, "BBBMatrix: no room in the PRU DDR region for even one frame\n"); | |
| 788 | ✗ | AddOutputConfigWarning(20, "BBBMatrix: no room in the PRU DDR region - reduce panel count/color depth or other outputs' buffers"); | |
| 789 | ✗ | return 0; | |
| 790 | } | ||
| 791 |
2/2✓ Branch 0 taken 112 times.
✓ Branch 1 taken 14 times.
|
126 | for (int x = 0; x < 8; x++) { |
| 792 | 112 | m_frames[x] = framesBase + (size_t)std::min(x, m_numFrames - 1) * alignedLen; | |
| 793 | } | ||
| 794 | 14 | m_pruData->address_dma = framesPhys; | |
| 795 | 14 | m_curFrame = 0; | |
| 796 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | if (PixelOverlayManager::INSTANCE.isAutoCreatePixelOverlayModels()) { |
| 797 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | std::string dd = "LED Panels"; |
| 798 |
4/16✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 14 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 14 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
14 | if (config.isMember("LEDPanelMatrixName") && !config["LEDPanelMatrixName"].asString().empty()) { |
| 799 | ✗ | dd = config["LEDPanelMatrixName"].asString(); | |
| 800 | } | ||
| 801 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
|
14 | if (config.isMember("description")) { |
| 802 | ✗ | dd = config["description"].asString(); | |
| 803 | } | ||
| 804 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | std::string desc = dd; |
| 805 | 14 | int count = 0; | |
| 806 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
|
14 | while (PixelOverlayManager::INSTANCE.getModel(desc) != nullptr) { |
| 807 | ✗ | count++; | |
| 808 | ✗ | desc = dd + "-" + std::to_string(count); | |
| 809 | } | ||
| 810 |
4/8✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
|
98 | PixelOverlayManager::INSTANCE.addAutoOverlayModel(desc, |
| 811 | m_startChannel, m_channelCount, 3, | ||
| 812 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | "H", m_invertedData ? "BL" : "TL", |
| 813 | 14 | m_height, 1); | |
| 814 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | m_autoCreatedModelName = desc; |
| 815 | 14 | } | |
| 816 | // We need to send the data once to make sure the panels are cleared and "off" | ||
| 817 | // However, this doesn't always work so we'll set everything slightly "on" first | ||
| 818 | // real quick to make sure all the memory changes and is properly mapped into | ||
| 819 | // the process, then we'll reset everything to off | ||
| 820 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 14 times.
|
68 | for (int x = 0; x < m_numFrames; x++) { |
| 821 | 54 | memset(m_frames[x], 0x1, m_fullFrameLen); | |
| 822 | } | ||
| 823 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | msync(m_frames[0], m_pru->ddr_size, MS_SYNC | MS_INVALIDATE); |
| 824 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | SendData(nullptr); |
| 825 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 14 times.
|
68 | for (int x = 0; x < m_numFrames; x++) { |
| 826 | 54 | memset(m_frames[x], 0x0, m_fullFrameLen); | |
| 827 | } | ||
| 828 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | msync(m_frames[0], m_pru->ddr_size, MS_SYNC | MS_INVALIDATE); |
| 829 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | SendData(nullptr); |
| 830 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | return ChannelOutput::Init(config); |
| 831 | 15 | } | |
| 832 | |||
| 833 | 14 | int BBBMatrix::Close(void) { | |
| 834 | 14 | LogDebug(VB_CHANNELOUT, "BBBMatrix::Close()\n"); | |
| 835 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | BBBPru::ddrRelease("BBBMatrix"); |
| 836 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | if (!m_autoCreatedModelName.empty()) { |
| 837 | 14 | PixelOverlayManager::INSTANCE.removeAutoOverlayModel(m_autoCreatedModelName); | |
| 838 | } | ||
| 839 | |||
| 840 | // Send the stop command | ||
| 841 | 14 | m_pruData->command = 0xFF; | |
| 842 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | if (m_pru) { |
| 843 | 14 | m_pru->stop(); | |
| 844 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | delete m_pru; |
| 845 | 14 | m_pru = nullptr; | |
| 846 | } | ||
| 847 | |||
| 848 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 5 times.
|
14 | if (m_pruCopy) { |
| 849 | 9 | m_pruCopy->stop(); | |
| 850 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | delete m_pruCopy; |
| 851 | 9 | m_pruCopy = nullptr; | |
| 852 | } | ||
| 853 | 14 | return ChannelOutput::Close(); | |
| 854 | } | ||
| 855 | |||
| 856 | static int fcount = 0; | ||
| 857 | |||
| 858 | ✗ | void BBBMatrix::printStats() { | |
| 859 | FILE* rfile; | ||
| 860 | ✗ | rfile = fopen("/tmp/framerates.txt", "w"); | |
| 861 | ✗ | for (int x = 0; x < m_colorDepth; ++x) { | |
| 862 | ✗ | fprintf(rfile, "DV: %d %8X %8X\n", (m_colorDepth - x), brightnessValues[x], delayValues[x]); | |
| 863 | } | ||
| 864 | ✗ | int off = 0; | |
| 865 | ✗ | uint32_t total = 0; | |
| 866 | ✗ | int count = 0; | |
| 867 | ✗ | for (int x = 0; x < m_panelScan; ++x) { | |
| 868 | ✗ | for (int y = m_colorDepth; y > 0; --y) { | |
| 869 | ✗ | fprintf(rfile, "r%2d b%2d: %8X %8X %8X\n", x, y, m_pruData->stats[off], m_pruData->stats[off + 1], m_pruData->stats[off + 2]); | |
| 870 | ✗ | total += m_pruData->stats[off]; | |
| 871 | ✗ | count++; | |
| 872 | ✗ | off += 3; | |
| 873 | } | ||
| 874 | } | ||
| 875 | ✗ | fprintf(rfile, "Average Per Row/Bit: %8X\n", (total / count)); | |
| 876 | // printf("0x%X\n", (total / count)); | ||
| 877 | ✗ | fclose(rfile); | |
| 878 | ✗ | } | |
| 879 | |||
| 880 | 27 | void BBBMatrix::GetRequiredChannelRanges(const std::function<void(int, int)>& addRange) { | |
| 881 | 27 | addRange(m_startChannel, m_startChannel + m_channelCount - 1); | |
| 882 | 27 | } | |
| 883 | |||
| 884 | ✗ | void BBBMatrix::OverlayTestData(unsigned char* channelData, int cycleNum, float percentOfCycle, int testType, const Json::Value& config) { | |
| 885 | ✗ | for (int output = 0; output < m_outputs; output++) { | |
| 886 | ✗ | int panelsOnOutput = m_panelMatrix->m_outputPanels[output].size(); | |
| 887 | ✗ | for (int i = 0; i < panelsOnOutput; i++) { | |
| 888 | ✗ | int panel = m_panelMatrix->m_outputPanels[output][i]; | |
| 889 | |||
| 890 | ✗ | m_panelMatrix->m_panels[panel].drawTestPattern(channelData + m_startChannel, cycleNum, percentOfCycle, testType); | |
| 891 | } | ||
| 892 | } | ||
| 893 | ✗ | } | |
| 894 | |||
| 895 | 14 | void BBBMatrix::buildPrepTables() { | |
| 896 | // per output: the 4 GPIO bank words for every combination of the 6 pins, | ||
| 897 | // so setting the pins for a pixel/bit is 4 unconditional ORs instead of | ||
| 898 | // 6 data dependent branches | ||
| 899 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 14 times.
|
45 | for (int o = 0; o < m_outputs; o++) { |
| 900 | 31 | const GPIOPinInfo::Pins& p0 = m_pinInfo[o].row[0]; | |
| 901 | 31 | const GPIOPinInfo::Pins& p1 = m_pinInfo[o].row[1]; | |
| 902 |
2/2✓ Branch 0 taken 1984 times.
✓ Branch 1 taken 31 times.
|
2015 | for (int idx = 0; idx < 64; idx++) { |
| 903 | 1984 | uint32_t v[4] = { 0, 0, 0, 0 }; | |
| 904 |
2/2✓ Branch 0 taken 992 times.
✓ Branch 1 taken 992 times.
|
1984 | if (idx & 1) |
| 905 | 992 | v[p0.r_gpio] |= p0.r_pin; | |
| 906 |
2/2✓ Branch 0 taken 992 times.
✓ Branch 1 taken 992 times.
|
1984 | if (idx & 2) |
| 907 | 992 | v[p0.g_gpio] |= p0.g_pin; | |
| 908 |
2/2✓ Branch 0 taken 992 times.
✓ Branch 1 taken 992 times.
|
1984 | if (idx & 4) |
| 909 | 992 | v[p0.b_gpio] |= p0.b_pin; | |
| 910 |
2/2✓ Branch 0 taken 992 times.
✓ Branch 1 taken 992 times.
|
1984 | if (idx & 8) |
| 911 | 992 | v[p1.r_gpio] |= p1.r_pin; | |
| 912 |
2/2✓ Branch 0 taken 992 times.
✓ Branch 1 taken 992 times.
|
1984 | if (idx & 16) |
| 913 | 992 | v[p1.g_gpio] |= p1.g_pin; | |
| 914 |
2/2✓ Branch 0 taken 992 times.
✓ Branch 1 taken 992 times.
|
1984 | if (idx & 32) |
| 915 | 992 | v[p1.b_gpio] |= p1.b_pin; | |
| 916 |
2/2✓ Branch 0 taken 7936 times.
✓ Branch 1 taken 1984 times.
|
9920 | for (int g = 0; g < 4; g++) { |
| 917 | 7936 | m_pinLUT[o][idx][g] = v[g]; | |
| 918 | } | ||
| 919 | } | ||
| 920 | } | ||
| 921 | // spread the gamma corrected value so bit b lands in byte b; shifting | ||
| 922 | // six spread values together produces the 6 bit pin combination for | ||
| 923 | // every bit plane of a pixel in a couple of operations | ||
| 924 |
2/2✓ Branch 0 taken 3584 times.
✓ Branch 1 taken 14 times.
|
3598 | for (int v = 0; v < 256; v++) { |
| 925 | 3584 | uint16_t g = gammaCurve[v]; | |
| 926 | 3584 | uint64_t lo = 0; | |
| 927 | 3584 | uint32_t hi = 0; | |
| 928 |
2/2✓ Branch 0 taken 28672 times.
✓ Branch 1 taken 3584 times.
|
32256 | for (int b = 0; b < 8; b++) { |
| 929 |
2/2✓ Branch 0 taken 14335 times.
✓ Branch 1 taken 14337 times.
|
28672 | if ((g >> b) & 1) |
| 930 | 14335 | lo |= 1ULL << (8 * b); | |
| 931 | } | ||
| 932 |
2/2✓ Branch 0 taken 14336 times.
✓ Branch 1 taken 3584 times.
|
17920 | for (int b = 8; b < 12; b++) { |
| 933 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14336 times.
|
14336 | if ((g >> b) & 1) |
| 934 | ✗ | hi |= 1u << (8 * (b - 8)); | |
| 935 | } | ||
| 936 | 3584 | m_gammaSpreadLo[v] = lo; | |
| 937 | 3584 | m_gammaSpreadHi[v] = hi; | |
| 938 | } | ||
| 939 | // group the panels by chain position; all outputs at the same chain | ||
| 940 | // position write into the same gpio words and can accumulate in registers | ||
| 941 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | m_chainPanels.assign(m_longestChain, {}); |
| 942 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 14 times.
|
45 | for (int output = 0; output < m_outputs; output++) { |
| 943 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 31 times.
|
49 | for (int i = 0; i < m_panelMatrix->m_outputPanels[output].size(); i++) { |
| 944 | 18 | int panel = m_panelMatrix->m_outputPanels[output][i]; | |
| 945 | 18 | int chain = m_panelMatrix->m_panels[panel].chain; | |
| 946 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | if (chain >= 0 && chain < m_longestChain) { |
| 947 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | m_chainPanels[chain].emplace_back(output, panel); |
| 948 | } | ||
| 949 | } | ||
| 950 | } | ||
| 951 | // the interleave mapping only depends on the coordinates, not the panel | ||
| 952 | // or output, so it can be precomputed once instead of a virtual call per | ||
| 953 | // pixel per frame | ||
| 954 | 14 | int h2 = m_panelHeight / 2; | |
| 955 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | m_yOutMap.resize(h2); |
| 956 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | m_xOutMap.resize(h2 * m_panelWidth); |
| 957 |
2/2✓ Branch 0 taken 228 times.
✓ Branch 1 taken 14 times.
|
242 | for (int y = 0; y < h2; y++) { |
| 958 | 228 | int xo = 0; | |
| 959 | 228 | int yo = y; | |
| 960 | 228 | m_handler->map(xo, yo); | |
| 961 | 228 | m_yOutMap[y] = yo; | |
| 962 |
2/2✓ Branch 0 taken 14912 times.
✓ Branch 1 taken 228 times.
|
15140 | for (int x = 0; x < m_panelWidth; x++) { |
| 963 | 14912 | int xOut = x; | |
| 964 | 14912 | int yo2 = y; | |
| 965 | 14912 | m_handler->map(xOut, yo2); | |
| 966 | 14912 | m_xOutMap[y * m_panelWidth + x] = xOut; | |
| 967 | } | ||
| 968 | } | ||
| 969 | 14 | size_t maxPairs = 1; | |
| 970 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 14 times.
|
42 | for (auto& c : m_chainPanels) { |
| 971 | 28 | maxPairs = std::max(maxPairs, c.size()); | |
| 972 | } | ||
| 973 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | m_stageLo.resize(maxPairs * m_panelWidth * 8); |
| 974 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | m_stageHi.resize(maxPairs * m_panelWidth * 4); |
| 975 | |||
| 976 | // PrepData skips the per-frame memset and uses plain stores, which is | ||
| 977 | // only valid if the interleave maps every (y, x) onto a distinct slot of | ||
| 978 | // the chain block (it covers and overwrites everything). If a handler | ||
| 979 | // is not a clean bijection, fall back to memset + OR accumulation which | ||
| 980 | // matches the historical behavior exactly. | ||
| 981 | 14 | m_prepNeedsMemset = false; | |
| 982 | 14 | int blockW = m_panelWidth * m_panelHeight / (m_panelScan * 2); | |
| 983 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
28 | std::vector<uint8_t> covered(m_panelScan * blockW, 0); |
| 984 |
2/2✓ Branch 0 taken 228 times.
✓ Branch 1 taken 14 times.
|
242 | for (int y = 0; y < h2; y++) { |
| 985 |
2/2✓ Branch 0 taken 14912 times.
✓ Branch 1 taken 228 times.
|
15140 | for (int x = 0; x < m_panelWidth; x++) { |
| 986 | 14912 | int yOut = m_yOutMap[y]; | |
| 987 | 14912 | int xOut = m_xOutMap[y * m_panelWidth + x]; | |
| 988 |
6/12✓ Branch 0 taken 14912 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14912 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14912 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14912 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 14912 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 14912 times.
|
14912 | if (yOut < 0 || yOut >= m_panelScan || xOut < 0 || xOut >= blockW || covered[yOut * blockW + xOut]) { |
| 989 | ✗ | m_prepNeedsMemset = true; | |
| 990 | } else { | ||
| 991 | 14912 | covered[yOut * blockW + xOut] = 1; | |
| 992 | } | ||
| 993 | } | ||
| 994 | } | ||
| 995 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (m_prepNeedsMemset) { |
| 996 | ✗ | LogWarn(VB_CHANNELOUT, "BBBMatrix: interleave map for %s is not a clean bijection, using slower PrepData path\n", | |
| 997 | m_panelInterleave.c_str()); | ||
| 998 | } | ||
| 999 | 14 | } | |
| 1000 | |||
| 1001 | 220 | void BBBMatrix::PrepData(unsigned char* channelData) { | |
| 1002 | 220 | m_matrix->OverlaySubMatrices(channelData); | |
| 1003 | |||
| 1004 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
|
220 | if (m_printStats) { |
| 1005 | ✗ | fcount++; | |
| 1006 | ✗ | if (fcount == 20) { | |
| 1007 | // every 20 frames or so, save stats | ||
| 1008 | ✗ | fcount = 0; | |
| 1009 | ✗ | printStats(); | |
| 1010 | } | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | 220 | channelData += m_startChannel; | |
| 1014 | |||
| 1015 | // number of uint32_t per row for each bit | ||
| 1016 | 220 | size_t rowLen = m_panelWidth * m_longestChain * m_panelHeight / (m_panelScan * 2) * 4; // 4 GPIO's | |
| 1017 | // number of uint32_t per full row (all bits) | ||
| 1018 | 220 | size_t fullRowLen = rowLen * m_colorDepth; | |
| 1019 | |||
| 1020 | 220 | uint32_t* gpioFrame = m_gpioFrame; | |
| 1021 | 220 | int h2 = m_panelHeight / 2; | |
| 1022 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
|
220 | size_t bitStride = m_outputByRow ? rowLen : (rowLen * m_panelScan); |
| 1023 | |||
| 1024 | // For each chain position, the packed bit-plane pin indexes for every | ||
| 1025 | // output are staged for the row, then each bit plane is written with all | ||
| 1026 | // outputs accumulated in a register and stored without a read-modify- | ||
| 1027 | // write. Iterating every chain position and row covers (and thus | ||
| 1028 | // clears) the whole frame, so no memset is needed; bit planes past the | ||
| 1029 | // color depth were zeroed at init and are never touched. | ||
| 1030 | 220 | const bool rmw = m_prepNeedsMemset; | |
| 1031 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
|
220 | if (rmw) { |
| 1032 | ✗ | memset(gpioFrame, 0, m_fullFrameLen); | |
| 1033 | } | ||
| 1034 |
2/2✓ Branch 0 taken 269 times.
✓ Branch 1 taken 220 times.
|
489 | for (int chain = 0; chain < m_longestChain; chain++) { |
| 1035 | 269 | auto& pairs = m_chainPanels[chain]; | |
| 1036 | 269 | int nPairs = (int)pairs.size(); | |
| 1037 | 269 | size_t chainOff = (size_t)(m_longestChain - chain - 1) * 4 * m_panelWidth * m_panelHeight / m_panelScan / 2; | |
| 1038 |
2/2✓ Branch 0 taken 4328 times.
✓ Branch 1 taken 269 times.
|
4597 | for (int y = 0; y < h2; y++) { |
| 1039 | 4328 | int yw1 = y * m_panelWidth * 3; | |
| 1040 | 4328 | int yw2 = (y + h2) * m_panelWidth * 3; | |
| 1041 | 4328 | const uint16_t* xMap = &m_xOutMap[y * m_panelWidth]; | |
| 1042 |
2/2✓ Branch 0 taken 3752 times.
✓ Branch 1 taken 4328 times.
|
8080 | for (int p = 0; p < nPairs; p++) { |
| 1043 | 3752 | const int* pixelMap = &m_panelMatrix->m_panels[pairs[p].second].pixelMap[0]; | |
| 1044 | 3752 | uint8_t* stLo = &m_stageLo[p * m_panelWidth * 8]; | |
| 1045 |
2/2✓ Branch 0 taken 242048 times.
✓ Branch 1 taken 3752 times.
|
245800 | for (int x = 0; x < m_panelWidth; ++x) { |
| 1046 | 242048 | uint64_t pk = m_gammaSpreadLo[channelData[pixelMap[yw1 + x * 3]]] | | |
| 1047 | 242048 | (m_gammaSpreadLo[channelData[pixelMap[yw1 + x * 3 + 1]]] << 1) | | |
| 1048 | 242048 | (m_gammaSpreadLo[channelData[pixelMap[yw1 + x * 3 + 2]]] << 2) | | |
| 1049 | 242048 | (m_gammaSpreadLo[channelData[pixelMap[yw2 + x * 3]]] << 3) | | |
| 1050 | 242048 | (m_gammaSpreadLo[channelData[pixelMap[yw2 + x * 3 + 1]]] << 4) | | |
| 1051 | 242048 | (m_gammaSpreadLo[channelData[pixelMap[yw2 + x * 3 + 2]]] << 5); | |
| 1052 | 242048 | memcpy(&stLo[x * 8], &pk, 8); | |
| 1053 | } | ||
| 1054 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3752 times.
|
3752 | if (m_colorDepth > 8) { |
| 1055 | ✗ | uint8_t* stHi = &m_stageHi[p * m_panelWidth * 4]; | |
| 1056 | ✗ | for (int x = 0; x < m_panelWidth; ++x) { | |
| 1057 | ✗ | uint32_t pk = m_gammaSpreadHi[channelData[pixelMap[yw1 + x * 3]]] | | |
| 1058 | ✗ | (m_gammaSpreadHi[channelData[pixelMap[yw1 + x * 3 + 1]]] << 1) | | |
| 1059 | ✗ | (m_gammaSpreadHi[channelData[pixelMap[yw1 + x * 3 + 2]]] << 2) | | |
| 1060 | ✗ | (m_gammaSpreadHi[channelData[pixelMap[yw2 + x * 3]]] << 3) | | |
| 1061 | ✗ | (m_gammaSpreadHi[channelData[pixelMap[yw2 + x * 3 + 1]]] << 4) | | |
| 1062 | ✗ | (m_gammaSpreadHi[channelData[pixelMap[yw2 + x * 3 + 2]]] << 5); | |
| 1063 | ✗ | memcpy(&stHi[x * 4], &pk, 4); | |
| 1064 | } | ||
| 1065 | } | ||
| 1066 | } | ||
| 1067 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4328 times.
|
4328 | size_t offset = (m_outputByRow ? (size_t)m_yOutMap[y] * fullRowLen : (size_t)m_yOutMap[y] * rowLen) + chainOff; |
| 1068 | // Depths below 8 take the TOP bits of the 8 bit gamma value: the | ||
| 1069 | // bit order is relative to the depth (0..depth-1, which the | ||
| 1070 | // brightness flags index by), so shift it up past the bits the | ||
| 1071 | // depth drops. Without this 6 and 7 bit showed the low bits and | ||
| 1072 | // wrapped - at 6 bit, 136 came out black. | ||
| 1073 |
2/2✓ Branch 0 taken 2736 times.
✓ Branch 1 taken 1592 times.
|
4328 | const int bitShift = m_colorDepth < 8 ? 8 - m_colorDepth : 0; |
| 1074 |
2/2✓ Branch 0 taken 29152 times.
✓ Branch 1 taken 4328 times.
|
33480 | for (int bi = 0; bi < m_colorDepth; bi++) { |
| 1075 | 29152 | int b = m_bitOrder[bi] + bitShift; | |
| 1076 | 29152 | uint32_t* out = &gpioFrame[offset + (size_t)bi * bitStride]; | |
| 1077 |
1/2✓ Branch 0 taken 29152 times.
✗ Branch 1 not taken.
|
29152 | const uint8_t* st = (b < 8) ? m_stageLo.data() : m_stageHi.data(); |
| 1078 |
1/2✓ Branch 0 taken 29152 times.
✗ Branch 1 not taken.
|
29152 | size_t stStride = (b < 8) ? (m_panelWidth * 8) : (m_panelWidth * 4); |
| 1079 |
1/2✓ Branch 0 taken 29152 times.
✗ Branch 1 not taken.
|
29152 | int stMult = (b < 8) ? 8 : 4; |
| 1080 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29152 times.
|
29152 | int bb = (b < 8) ? b : (b - 8); |
| 1081 | #ifdef __ARM_NEON | ||
| 1082 |
2/2✓ Branch 0 taken 1881088 times.
✓ Branch 1 taken 29152 times.
|
1910240 | for (int x = 0; x < m_panelWidth; ++x) { |
| 1083 | 1881088 | uint32_t* o2 = &out[(size_t)xMap[x] * 4]; | |
| 1084 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1881088 times.
|
3762176 | uint32x4_t acc = rmw ? vld1q_u32(o2) : vdupq_n_u32(0); |
| 1085 |
2/2✓ Branch 0 taken 1586176 times.
✓ Branch 1 taken 1881088 times.
|
3467264 | for (int p = 0; p < nPairs; p++) { |
| 1086 | 4758528 | acc = vorrq_u32(acc, vld1q_u32(m_pinLUT[pairs[p].first][st[p * stStride + x * stMult + bb]])); | |
| 1087 | } | ||
| 1088 | vst1q_u32(o2, acc); | ||
| 1089 | } | ||
| 1090 | #else | ||
| 1091 | for (int x = 0; x < m_panelWidth; ++x) { | ||
| 1092 | uint32_t* o2 = &out[(size_t)xMap[x] * 4]; | ||
| 1093 | uint32_t a0 = 0, a1 = 0, a2 = 0, a3 = 0; | ||
| 1094 | if (rmw) { | ||
| 1095 | a0 = o2[0]; | ||
| 1096 | a1 = o2[1]; | ||
| 1097 | a2 = o2[2]; | ||
| 1098 | a3 = o2[3]; | ||
| 1099 | } | ||
| 1100 | for (int p = 0; p < nPairs; p++) { | ||
| 1101 | const uint32_t* t = m_pinLUT[pairs[p].first][st[p * stStride + x * stMult + bb]]; | ||
| 1102 | a0 |= t[0]; | ||
| 1103 | a1 |= t[1]; | ||
| 1104 | a2 |= t[2]; | ||
| 1105 | a3 |= t[3]; | ||
| 1106 | } | ||
| 1107 | o2[0] = a0; | ||
| 1108 | o2[1] = a1; | ||
| 1109 | o2[2] = a2; | ||
| 1110 | o2[3] = a3; | ||
| 1111 | } | ||
| 1112 | #endif | ||
| 1113 | } | ||
| 1114 | } | ||
| 1115 | } | ||
| 1116 | |||
| 1117 |
2/4✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 220 times.
✗ Branch 3 not taken.
|
220 | if ((m_numFrames >= 3) && (m_frames[m_curFrame] != (uint8_t*)gpioFrame)) { |
| 1118 | 220 | memcpy(m_frames[m_curFrame], m_gpioFrame, m_fullFrameLen); | |
| 1119 | } | ||
| 1120 | 220 | } | |
| 1121 | 230 | int BBBMatrix::SendData(unsigned char* channelData) { | |
| 1122 | 230 | LogExcess(VB_CHANNELOUT, "BBBMatrix::SendData(%p)\n", channelData); | |
| 1123 | |||
| 1124 | // long long startTime = GetTime(); | ||
| 1125 | 230 | uint32_t addr = m_pru->ddr_addr + (uint32_t)(m_frames[m_curFrame] - m_pru->ddr); | |
| 1126 | 230 | uint8_t* ptr = m_frames[m_curFrame]; | |
| 1127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 230 times.
|
230 | if (m_numFrames < 3) { |
| 1128 | // if we have less than 3 blocks, we cannot copy | ||
| 1129 | // in prep or we'd get potential tearing/flickering | ||
| 1130 | ✗ | memcpy(ptr, m_gpioFrame, m_fullFrameLen); | |
| 1131 | } | ||
| 1132 | // long long cpyTime = GetTime(); | ||
| 1133 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 165 times.
|
230 | if (m_curFrame == 0) { |
| 1134 | 65 | m_curFrame = m_numFrames - 1; | |
| 1135 | } else { | ||
| 1136 | 165 | m_curFrame--; | |
| 1137 | } | ||
| 1138 | |||
| 1139 | // make sure memory is flushed before command is set to 1 | ||
| 1140 | 230 | msync(ptr, m_fullFrameLen, MS_SYNC | MS_INVALIDATE); | |
| 1141 | 230 | __builtin___clear_cache(ptr, ptr + m_fullFrameLen); | |
| 1142 | 230 | m_pruData->address_dma = addr; | |
| 1143 | |||
| 1144 | 230 | __asm__ __volatile__("" :: | |
| 1145 | : "memory"); | ||
| 1146 | // long long flshTime = GetTime(); | ||
| 1147 | 230 | m_pruData->command = 1; | |
| 1148 | |||
| 1149 | /* | ||
| 1150 | if (fcount == 0) { | ||
| 1151 | printf("%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n", | ||
| 1152 | m_outputFrame[0], m_outputFrame[1], m_outputFrame[2], | ||
| 1153 | m_outputFrame[3], m_outputFrame[4], m_outputFrame[5], | ||
| 1154 | m_outputFrame[6], m_outputFrame[7], m_outputFrame[8], | ||
| 1155 | m_outputFrame[9], m_outputFrame[10], m_outputFrame[11], | ||
| 1156 | m_outputFrame[12], m_outputFrame[13], m_outputFrame[15] | ||
| 1157 | ); | ||
| 1158 | |||
| 1159 | uint32_t *t = (uint32_t *)m_pruCopy->data_ram; | ||
| 1160 | printf(" %d %X %X %X %X %X\n", t[0], t[1], t[2], t[3], t[4], t[5]); | ||
| 1161 | } | ||
| 1162 | */ | ||
| 1163 | /* | ||
| 1164 | long long endTime = GetTime(); | ||
| 1165 | if ((endTime - startTime) > 100) { | ||
| 1166 | printf("cpy: %d flush: %d cmd: %d Total: %d\n", (int)(cpyTime - startTime), (int)(flshTime - cpyTime), (int)(endTime - flshTime), (int)(endTime - startTime)); | ||
| 1167 | } | ||
| 1168 | */ | ||
| 1169 | 230 | return m_channelCount; | |
| 1170 | } | ||
| 1171 | |||
| 1172 | 14 | void BBBMatrix::DumpConfig(void) { | |
| 1173 | 14 | LogDebug(VB_CHANNELOUT, "BBBMatrix::DumpConfig()\n"); | |
| 1174 | 14 | LogDebug(VB_CHANNELOUT, " Width : %d\n", m_width); | |
| 1175 | 14 | LogDebug(VB_CHANNELOUT, " Height : %d\n", m_height); | |
| 1176 | 14 | LogDebug(VB_CHANNELOUT, " Rows : %d\n", m_rows); | |
| 1177 | 14 | LogDebug(VB_CHANNELOUT, " Row Size : %d\n", m_rowSize); | |
| 1178 | 14 | LogDebug(VB_CHANNELOUT, " Color Depth : %d\n", m_colorDepth); | |
| 1179 | 14 | LogDebug(VB_CHANNELOUT, " Outputs : %d\n", m_outputs); | |
| 1180 | 14 | LogDebug(VB_CHANNELOUT, " Longest Chain : %d\n", m_longestChain); | |
| 1181 | 14 | LogDebug(VB_CHANNELOUT, " Inverted Data : %d\n", m_invertedData); | |
| 1182 | |||
| 1183 | 14 | ChannelOutput::DumpConfig(); | |
| 1184 | 14 | } | |
| 1185 |