#include "lib/core/globals.h" #include "lib/config/config.h" #include "lib/data/fluxmap.h" #include "lib/data/fluxmapreader.h" #include "lib/data/fluxpattern.h" #include "lib/config/proto.h" #include "protocol.h" #include #include #include FluxmapReader::FluxmapReader(const Fluxmap& fluxmap): _fluxmap(fluxmap), _bytes(fluxmap.ptr()), _size(fluxmap.bytes()), _config(globalConfig()->decoder()) { rewind(); } void FluxmapReader::getNextEvent(int& event, unsigned& ticks) { ticks = 0; while (!eof()) { uint8_t b = _bytes[_pos.bytes++]; ticks += b & 0x3f; if (!b || (b & (F_BIT_PULSE | F_BIT_INDEX))) { _pos.ticks += ticks; event = b & 0xc0; return; } } _pos.ticks += ticks; event = F_EOF; } void FluxmapReader::skipToEvent(int event) { unsigned ticks; findEvent(event, ticks); } bool FluxmapReader::findEvent(int event, unsigned& ticks) { ticks = 0; while (!eof()) { unsigned thisTicks; int thisEvent; getNextEvent(thisEvent, thisTicks); ticks += thisTicks; if (thisEvent == F_EOF) return false; if ((event == thisEvent) || (event & thisEvent)) return true; } return false; } unsigned FluxmapReader::readInterval(nanoseconds_t clock) { unsigned thresholdTicks = (clock * _config.pulse_debounce_threshold()) / NS_PER_TICK; unsigned ticks = 0; while (ticks <= thresholdTicks) { unsigned thisTicks; if (!findEvent(F_BIT_PULSE, thisTicks)) break; ticks += thisTicks; } return ticks; } void FluxmapReader::seek(nanoseconds_t ns) { unsigned ticks = ns / NS_PER_TICK; if (ticks < _pos.ticks) { _pos.ticks = 0; _pos.bytes = 0; } while (!eof() && (_pos.ticks < ticks)) { int e; unsigned t; getNextEvent(e, t); } _pos.zeroes = 0; } void FluxmapReader::seekToByte(unsigned b) { if (b < _pos.bytes) { _pos.ticks = 0; _pos.bytes = 0; } while (!eof() && (_pos.bytes < b)) { int e; unsigned t; getNextEvent(e, t); } _pos.zeroes = 0; } nanoseconds_t FluxmapReader::seekToPattern(const FluxMatcher& pattern) { const FluxMatcher* unused; return seekToPattern(pattern, unused); } nanoseconds_t FluxmapReader::seekToPattern( const FluxMatcher& pattern, const FluxMatcher*& matching) { unsigned intervalCount = pattern.intervals(); std::vector candidates(intervalCount + 1); std::vector positions(intervalCount + 1); for (unsigned i = 0; i <= intervalCount; i++) { positions[i] = tell(); candidates[i] = 0; } while (!eof()) { FluxMatch match; if (pattern.matches(&*candidates.end(), match)) { seek(positions[intervalCount - match.intervals]); _pos.zeroes = match.zeroes; matching = match.matcher; nanoseconds_t detectedClock = match.clock * NS_PER_TICK; if (detectedClock > (_config.minimum_clock_us() * 1000)) return match.clock * NS_PER_TICK; } for (unsigned i = 0; i < intervalCount; i++) { positions[i] = positions[i + 1]; candidates[i] = candidates[i + 1]; } findEvent(F_BIT_PULSE, candidates[intervalCount]); positions[intervalCount] = tell(); } matching = NULL; return 0; } void FluxmapReader::seekToIndexMark() { skipToEvent(F_BIT_INDEX); _pos.zeroes = 0; } /* * Tries to guess the clock by finding the smallest common interval. * Returns nanoseconds. */ FluxmapReader::ClockData FluxmapReader::guessClock( double noiseFloorFactor, double signalLevelFactor) { ClockData data = {}; while (!eof()) { unsigned interval; findEvent(F_BIT_PULSE, interval); if (interval > 0xff) continue; data.buckets[interval]++; } uint32_t max = *std::max_element(std::begin(data.buckets), std::end(data.buckets)); uint32_t min = *std::min_element(std::begin(data.buckets), std::end(data.buckets)); data.noiseFloor = min + (max - min) * noiseFloorFactor; data.signalLevel = min + (max - min) * signalLevelFactor; /* Find a point solidly within the first pulse. */ int pulseindex = 0; while (pulseindex < 256) { if (data.buckets[pulseindex] > data.signalLevel) break; pulseindex++; } if (pulseindex == -1) return data; /* Find the upper and lower bounds of the pulse. */ int peaklo = pulseindex; while (peaklo > 0) { if (data.buckets[peaklo] < data.noiseFloor) break; peaklo--; } int peakhi = pulseindex; while (peakhi < 255) { if (data.buckets[peakhi] < data.noiseFloor) break; peakhi++; } /* Find the total accumulated size of the pulse. */ uint32_t total_size = 0; for (int i = peaklo; i < peakhi; i++) total_size += data.buckets[i]; /* Now find the median. */ uint32_t count = 0; int median = peaklo; while (median < peakhi) { count += data.buckets[median]; if (count > (total_size / 2)) break; median++; } /* * Okay, the median should now be a good candidate for the (or a) clock. * How this maps onto the actual clock rate depends on the encoding. */ data.peakStart = peaklo * NS_PER_TICK; data.peakEnd = peakhi * NS_PER_TICK; data.median = median * NS_PER_TICK; return data; }