mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
165 lines
3.6 KiB
C++
165 lines
3.6 KiB
C++
#include "globals.h"
|
|
#include "fluxmap.h"
|
|
#include "decoders/fluxmapreader.h"
|
|
#include "protocol.h"
|
|
|
|
Fluxmap& Fluxmap::appendBytes(const Bytes& bytes)
|
|
{
|
|
if (bytes.size() == 0)
|
|
return *this;
|
|
|
|
return appendBytes(&bytes[0], bytes.size());
|
|
}
|
|
|
|
Fluxmap& Fluxmap::appendBytes(const uint8_t* ptr, size_t len)
|
|
{
|
|
ByteWriter bw(_bytes);
|
|
bw.seekToEnd();
|
|
|
|
while (len--)
|
|
{
|
|
uint8_t byte = *ptr++;
|
|
_ticks += byte & 0x3f;
|
|
bw.write_8(byte);
|
|
}
|
|
|
|
_duration = _ticks * NS_PER_TICK;
|
|
return *this;
|
|
}
|
|
|
|
uint8_t& Fluxmap::findLastByte()
|
|
{
|
|
if (_bytes.empty())
|
|
appendByte(0x00);
|
|
return *(_bytes.end() - 1);
|
|
}
|
|
|
|
Fluxmap& Fluxmap::appendInterval(uint32_t ticks)
|
|
{
|
|
while (ticks >= 0x3f)
|
|
{
|
|
appendByte(0x3f);
|
|
ticks -= 0x3f;
|
|
}
|
|
appendByte((uint8_t)ticks);
|
|
return *this;
|
|
}
|
|
|
|
Fluxmap& Fluxmap::appendPulse()
|
|
{
|
|
findLastByte() |= 0x80;
|
|
return *this;
|
|
}
|
|
|
|
Fluxmap& Fluxmap::appendIndex()
|
|
{
|
|
findLastByte() |= 0x40;
|
|
return *this;
|
|
}
|
|
|
|
Fluxmap& Fluxmap::appendDesync()
|
|
{
|
|
appendByte(F_DESYNC);
|
|
return *this;
|
|
}
|
|
|
|
std::vector<std::unique_ptr<const Fluxmap>> Fluxmap::split() const
|
|
{
|
|
std::vector<std::unique_ptr<const Fluxmap>> maps;
|
|
auto bytesVector = rawBytes().split(F_DESYNC);
|
|
|
|
for (auto bytes : bytesVector)
|
|
{
|
|
if (bytes.size() != 0)
|
|
maps.push_back(std::move(std::make_unique<Fluxmap>(bytes)));
|
|
}
|
|
|
|
return maps;
|
|
}
|
|
|
|
/*
|
|
* Tries to guess the clock by finding the smallest common interval.
|
|
* Returns nanoseconds.
|
|
*/
|
|
Fluxmap::ClockData Fluxmap::guessClock(
|
|
double noiseFloorFactor, double signalLevelFactor) const
|
|
{
|
|
ClockData data = {};
|
|
|
|
FluxmapReader fr(*this);
|
|
|
|
while (!fr.eof())
|
|
{
|
|
unsigned interval;
|
|
fr.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;
|
|
}
|