diff --git a/lib/decoders/decoders.cc b/lib/decoders/decoders.cc index 7c09d8fb..3451e78e 100644 --- a/lib/decoders/decoders.cc +++ b/lib/decoders/decoders.cc @@ -11,152 +11,6 @@ #include "fmt/format.h" #include -static SettableFlag showClockHistogram( - { "--show-clock-histogram" }, - "Dump the clock detection histogram."); - -static DoubleFlag manualClockRate( - { "--manual-clock-rate-us" }, - "If not zero, force this clock rate; if zero, try to autodetect it.", - 0.0); - -static DoubleFlag noiseFloorFactor( - { "--noise-floor-factor" }, - "Clock detection noise floor (min + (max-min)*factor).", - 0.01); - -static DoubleFlag signalLevelFactor( - { "--signal-level-factor" }, - "Clock detection signal level (min + (max-min)*factor).", - 0.05); - -void setDecoderManualClockRate(double clockrate_us) -{ - manualClockRate.value = clockrate_us; -} - -static const std::string BLOCK_ELEMENTS[] = -{ " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" }; - -/* -* Tries to guess the clock by finding the smallest common interval. - * Returns nanoseconds. - */ -nanoseconds_t Fluxmap::guessClock() const -{ - if (manualClockRate != 0.0) - return manualClockRate * 1000.0; - - uint32_t buckets[256] = {}; - FluxmapReader fr(*this); - - while (!fr.eof()) - { - unsigned interval = fr.readNextMatchingOpcode(F_OP_PULSE); - if (interval > 0xff) - continue; - buckets[interval]++; - } - - uint32_t max = *std::max_element(std::begin(buckets), std::end(buckets)); - uint32_t min = *std::min_element(std::begin(buckets), std::end(buckets)); - uint32_t noise_floor = min + (max-min)*noiseFloorFactor; - uint32_t signal_level = min + (max-min)*signalLevelFactor; - - /* Find a point solidly within the first pulse. */ - - int pulseindex = 0; - while (pulseindex < 256) - { - if (buckets[pulseindex] > signal_level) - break; - pulseindex++; - } - if (pulseindex == -1) - return 0; - - /* Find the upper and lower bounds of the pulse. */ - - int peaklo = pulseindex; - while (peaklo > 0) - { - if (buckets[peaklo] < noise_floor) - break; - peaklo--; - } - - int peakhi = pulseindex; - while (peakhi < 255) - { - if (buckets[peakhi] < noise_floor) - break; - peakhi++; - } - - /* Find the total accumulated size of the pulse. */ - - uint32_t total_size = 0; - for (int i = peaklo; i < peakhi; i++) - total_size += buckets[i]; - - /* Now find the median. */ - - uint32_t count = 0; - int median = peaklo; - while (median < peakhi) - { - count += buckets[median]; - if (count > (total_size/2)) - break; - median++; - } - - if (showClockHistogram) - { - std::cout << "Clock detection histogram:" << std::endl; - - bool skipping = true; - for (int i=0; i<256; i++) - { - uint32_t value = buckets[i]; - if (value < noise_floor/2) - { - if (!skipping) - std::cout << "..." << std::endl; - skipping = true; - } - else - { - skipping = false; - - int bar = 320*value/max; - int fullblocks = bar / 8; - - std::string s; - for (int j=0; j& bits, nanoseconds_t clock); void precompensate(int threshold_ticks, int amount_ticks); diff --git a/src/fe-inspect.cc b/src/fe-inspect.cc index 3b865780..0a4d7c45 100644 --- a/src/fe-inspect.cc +++ b/src/fe-inspect.cc @@ -34,6 +34,145 @@ static DoubleFlag seekFlag( "Seek this many milliseconds into the track before displaying it.", 0.0); +static DoubleFlag manualClockRate( + { "--manual-clock-rate-us" }, + "If not zero, force this clock rate; if zero, try to autodetect it.", + 0.0); + +static DoubleFlag noiseFloorFactor( + { "--noise-floor-factor" }, + "Clock detection noise floor (min + (max-min)*factor).", + 0.01); + +static DoubleFlag signalLevelFactor( + { "--signal-level-factor" }, + "Clock detection signal level (min + (max-min)*factor).", + 0.05); + +void setDecoderManualClockRate(double clockrate_us) +{ + manualClockRate.value = clockrate_us; +} + +static const std::string BLOCK_ELEMENTS[] = +{ " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" }; + +/* +* Tries to guess the clock by finding the smallest common interval. + * Returns nanoseconds. + */ +static nanoseconds_t guessClock(const Fluxmap& fluxmap) +{ + if (manualClockRate != 0.0) + return manualClockRate * 1000.0; + + uint32_t buckets[256] = {}; + FluxmapReader fr(fluxmap); + + while (!fr.eof()) + { + unsigned interval = fr.readNextMatchingOpcode(F_OP_PULSE); + if (interval > 0xff) + continue; + buckets[interval]++; + } + + uint32_t max = *std::max_element(std::begin(buckets), std::end(buckets)); + uint32_t min = *std::min_element(std::begin(buckets), std::end(buckets)); + uint32_t noise_floor = min + (max-min)*noiseFloorFactor; + uint32_t signal_level = min + (max-min)*signalLevelFactor; + + /* Find a point solidly within the first pulse. */ + + int pulseindex = 0; + while (pulseindex < 256) + { + if (buckets[pulseindex] > signal_level) + break; + pulseindex++; + } + if (pulseindex == -1) + return 0; + + /* Find the upper and lower bounds of the pulse. */ + + int peaklo = pulseindex; + while (peaklo > 0) + { + if (buckets[peaklo] < noise_floor) + break; + peaklo--; + } + + int peakhi = pulseindex; + while (peakhi < 255) + { + if (buckets[peakhi] < noise_floor) + break; + peakhi++; + } + + /* Find the total accumulated size of the pulse. */ + + uint32_t total_size = 0; + for (int i = peaklo; i < peakhi; i++) + total_size += buckets[i]; + + /* Now find the median. */ + + uint32_t count = 0; + int median = peaklo; + while (median < peakhi) + { + count += buckets[median]; + if (count > (total_size/2)) + break; + median++; + } + + std::cout << "\nClock detection histogram:" << std::endl; + + bool skipping = true; + for (int i=0; i<256; i++) + { + uint32_t value = buckets[i]; + if (value < noise_floor/2) + { + if (!skipping) + std::cout << "..." << std::endl; + skipping = true; + } + else + { + skipping = false; + + int bar = 320*value/max; + int fullblocks = bar / 8; + + std::string s; + for (int j=0; jreadFluxmap(); - nanoseconds_t clockPeriod = track->fluxmap->guessClock(); - std::cout << fmt::format(" {:.2f} us clock detected; ", (double)clockPeriod/1000.0) << std::flush; + nanoseconds_t clockPeriod = guessClock(*track->fluxmap); + std::cout << fmt::format("{:.2f} us clock detected.", (double)clockPeriod/1000.0) << std::flush; FluxmapReader fmr(*track->fluxmap); fmr.seek(seekFlag*1000000.0); - std::cout << fmt::format("{:.2f} us bit clock; ", (double)clockPeriod/1000.0) << std::flush; if (dumpFluxFlag) { - std::cout << std::endl - << "Magnetic flux follows (times in us):" << std::endl; + std::cout << "\n\nMagnetic flux follows (times in us):" << std::endl; int resolution = fluxmapResolutionFlag; if (resolution == 0) @@ -76,6 +213,14 @@ int main(int argc, const char* argv[]) nanoseconds_t next; bool clocked = false; + + bool bannered = false; + auto banner = [&]() + { + std::cout << fmt::format("\n{: 10.3f}:{}", (double)next / 1000.0, clocked ? '-' : ' '); + bannered = true; + }; + for (;;) { next = now + resolution; @@ -84,24 +229,26 @@ int main(int argc, const char* argv[]) nextclock += clockPeriod; if (next >= transition) break; - std::cout << std::endl - << fmt::format("{: 10.3f}:{}", (double)next / 1000.0, clocked ? '-' : ' '); + banner(); now = next; } nanoseconds_t length = transition - lasttransition; + if (!bannered) + banner(); std::cout << fmt::format("==== {:06x} {: 10.3f} +{:.3f} = {:.1f} clocks", fmr.tell().bytes, (double)transition / 1000.0, (double)length / 1000.0, (double)length / clockPeriod); + bannered = false; lasttransition = transition; } } if (dumpBitstreamFlag) { - std::cout << fmt::format("Aligned bitstream from {:.3f}ms follows:\n", + std::cout << fmt::format("\n\nAligned bitstream from {:.3f}ms follows:\n", fmr.tell().ns() / 1000000.0); while (!fmr.eof()) diff --git a/src/fe-readfb100.cc b/src/fe-readfb100.cc index e50da488..4e66267e 100644 --- a/src/fe-readfb100.cc +++ b/src/fe-readfb100.cc @@ -19,7 +19,6 @@ int main(int argc, const char* argv[]) { setReaderDefaultSource(":t=0-79x2:s=0"); setReaderRevolutions(2); - setDecoderManualClockRate(4.0); Flag::parseFlags(argc, argv); Fb100Decoder decoder;