| 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 GPL v2 as described in the | ||
| 11 | * included LICENSE.GPL file. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include "PixelStringTester.h" | ||
| 15 | #include <cstdint> | ||
| 16 | #include <vector> | ||
| 17 | |||
| 18 | class PixelCountPixelStringTester : public PixelStringTester { | ||
| 19 | protected: | ||
| 20 | 4692 | PixelCountPixelStringTester(bool byString) : | |
| 21 | 4692 | PixelStringTester(), m_byString(byString) {} | |
| 22 | |||
| 23 | const bool m_byString; | ||
| 24 | |||
| 25 | public: | ||
| 26 | virtual uint8_t* createTestData(PixelString* ps, int cycleCount, float percentOfCycle, uint8_t* inChannelData, uint32_t& newLen) override; | ||
| 27 | |||
| 28 | static PixelCountPixelStringTester INSTANCE_BYSTRING; | ||
| 29 | static PixelCountPixelStringTester INSTANCE_BYPORT; | ||
| 30 | }; | ||
| 31 | |||
| 32 | // Counts the pixels on each port from its current sensor. | ||
| 33 | // | ||
| 34 | // One sensor group at a time (OutputMonitor::lockToGroup), every port in the | ||
| 35 | // group searched in parallel. Each measurement reads the port dark, then | ||
| 36 | // with a pattern lit, then dark again, and uses the lit reading less the | ||
| 37 | // mean of the dark ones: a port's dark current climbs for a while after it | ||
| 38 | // powers on, and a string powered at both ends does not return to the same | ||
| 39 | // dark current once lit. Pixels are only ever lit in windows of WINDOW at | ||
| 40 | // full white, or one at a time at the very end: enough current for a seed | ||
| 41 | // pixel to register, too little to reach the top of the sensor's range. | ||
| 42 | // | ||
| 43 | // A window is lit if it draws more than half what a pixel does, taken from | ||
| 44 | // the windows the search has proven full, so nothing depends on a fixed mA | ||
| 45 | // threshold. A measurement is only decided once it clears that by twice its | ||
| 46 | // uncertainty, worked out from the spread of the port's readings and how far | ||
| 47 | // the dark current moved; until then it is taken again. A seed pixel draws | ||
| 48 | // less than a noisy sensor's spread, so the readings, not a fixed number of | ||
| 49 | // them, decide how long a port takes. | ||
| 50 | // | ||
| 51 | // The end is found by doubling then halving the window position, and then | ||
| 52 | // pixel by pixel inside the last window, starting where its current puts | ||
| 53 | // the end. Null nodes are counted as the pixels they are, and taken off the | ||
| 54 | // count reported. | ||
| 55 | class CurrentBasedPixelCountPixelStringTester : public PixelStringTester { | ||
| 56 | public: | ||
| 57 | static CurrentBasedPixelCountPixelStringTester INSTANCE; | ||
| 58 | |||
| 59 | enum Status { | ||
| 60 | NotRun, | ||
| 61 | Running, | ||
| 62 | Complete | ||
| 63 | }; | ||
| 64 | Status getCurrentStatus() const; | ||
| 65 | |||
| 66 | protected: | ||
| 67 | 2346 | CurrentBasedPixelCountPixelStringTester() : | |
| 68 | 2346 | PixelStringTester() {} | |
| 69 | |||
| 70 | struct PortSearch { | ||
| 71 | int configured = -1; // pixels, as configured | ||
| 72 | int nulls = 0; // null nodes configured on the port | ||
| 73 | int maxPixels = 0; // the furthest this port is searched, on the wire | ||
| 74 | bool testing = false; | ||
| 75 | int phase = 0; | ||
| 76 | float base = 0; // mA, port dark | ||
| 77 | float perPixel = 0; // mA one pixel adds at full white | ||
| 78 | std::vector<float> fullWindows; // windows a later lit one proved full | ||
| 79 | std::vector<float> spreads; // of each reading, for the sensor's noise | ||
| 80 | int lo = 0; // a window start known to hold pixels | ||
| 81 | int hi = 0; // a window start known to hold none | ||
| 82 | float loCurrent = 0; | ||
| 83 | int litPixel = 0; // finding the last pixel: one known lit... | ||
| 84 | int unlitPixel = 0; // ...one known not... | ||
| 85 | int guess = 0; // ...and where the current puts the end | ||
| 86 | int count = -1; // the answer, once known | ||
| 87 | int repeats = 0; // readings of an unclear measurement so far | ||
| 88 | float dSum = 0; | ||
| 89 | float errSq = 0; | ||
| 90 | int litStart = 0; // what this port shows now | ||
| 91 | int litLen = 0; | ||
| 92 | std::vector<float> samples; | ||
| 93 | std::vector<float> darkSamples; // before the lit reading | ||
| 94 | std::vector<float> darkAfterSamples; // and after it | ||
| 95 | }; | ||
| 96 | std::vector<PortSearch> ports; | ||
| 97 | |||
| 98 | int state = -1; | ||
| 99 | int lastCycleCount = 0; | ||
| 100 | int curGroup = 0; | ||
| 101 | uint32_t frameInMeasure = 0; | ||
| 102 | uint32_t sampleFrames = 0; | ||
| 103 | // each measurement reads the port dark, lit, then dark again | ||
| 104 | int part = 0; | ||
| 105 | uint64_t stateStartMS = 0; | ||
| 106 | |||
| 107 | void startGroup(); | ||
| 108 | bool step(PortSearch& p, int port, float d, float err); | ||
| 109 | void measureWindow(PortSearch& p, int start, int len); | ||
| 110 | |||
| 111 | public: | ||
| 112 | virtual void prepareTestData(int cycleCount, float percentOfCycle) override; | ||
| 113 | virtual uint8_t* createTestData(PixelString* ps, int cycleCount, float percentOfCycle, uint8_t* inChannelData, uint32_t& newLen) override; | ||
| 114 | }; | ||
| 115 |