mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	
		
			
				
	
	
		
			253 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #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 <numeric>
 | |
| #include <math.h>
 | |
| #include <strings.h>
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| bool FluxmapReader::skipToEvent(int event)
 | |
| {
 | |
|     unsigned ticks;
 | |
|     return 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<unsigned> candidates(intervalCount + 1);
 | |
|     std::vector<Fluxmap::Position> 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;
 | |
| }
 |