mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-24 11:11:02 -07:00
119 lines
2.7 KiB
C++
119 lines
2.7 KiB
C++
#include "lib/core/globals.h"
|
|
#include "lib/data/fluxmap.h"
|
|
#include "lib/data/fluxmapreader.h"
|
|
#include "lib/decoders/fluxdecoder.h"
|
|
#include "lib/decoders/decoders.pb.h"
|
|
|
|
/* This is a port of the samdisk code:
|
|
*
|
|
* https://github.com/simonowen/samdisk/blob/master/src/FluxDecoder.cpp
|
|
*
|
|
* I'm not actually terribly sure how it works, but it does, and much better
|
|
* than my code.
|
|
*/
|
|
|
|
FluxDecoder::FluxDecoder(
|
|
FluxmapReader* fmr, nanoseconds_t bitcell, const DecoderProto& config):
|
|
_fmr(fmr),
|
|
_pll_phase(config.pll_phase()),
|
|
_pll_adjust(config.pll_adjust()),
|
|
_flux_scale(config.flux_scale()),
|
|
_clock(bitcell),
|
|
_clock_centre(bitcell),
|
|
_clock_min(bitcell * (1.0 - _pll_adjust)),
|
|
_clock_max(bitcell * (1.0 + _pll_adjust)),
|
|
_flux(0),
|
|
_leading_zeroes(fmr->tell().zeroes)
|
|
{
|
|
}
|
|
|
|
bool FluxDecoder::readBit()
|
|
{
|
|
if (_leading_zeroes > 0)
|
|
{
|
|
_leading_zeroes--;
|
|
return false;
|
|
}
|
|
else if (_leading_zeroes == 0)
|
|
{
|
|
_leading_zeroes--;
|
|
return true;
|
|
}
|
|
|
|
while (!_fmr->eof() && (_flux < (_clock / 2)))
|
|
{
|
|
_flux += nextFlux() * _flux_scale;
|
|
;
|
|
_clocked_zeroes = 0;
|
|
}
|
|
|
|
_flux -= _clock;
|
|
if (_flux >= (_clock / 2))
|
|
{
|
|
_clocked_zeroes++;
|
|
_goodbits++;
|
|
return false;
|
|
}
|
|
|
|
/* PLL adjustment: change the clock frequency according to the phase
|
|
* mismatch */
|
|
if (_clocked_zeroes <= 3)
|
|
{
|
|
/* In sync: adjust base clock */
|
|
|
|
_clock += _flux * _pll_adjust;
|
|
}
|
|
else
|
|
{
|
|
/* Out of sync: adjust the base clock back towards the centre */
|
|
|
|
_clock += (_clock_centre - _clock) * _pll_adjust;
|
|
|
|
/* We require 256 good bits before reporting another sync loss event. */
|
|
|
|
if (_goodbits >= 256)
|
|
_sync_lost = true;
|
|
_goodbits = 0;
|
|
}
|
|
|
|
/* Clamp the clock's adjustment range. */
|
|
|
|
_clock = std::min(std::max(_clock_min, _clock), _clock_max);
|
|
|
|
/* I'm not sure what this does, but the original comment is:
|
|
* Authentic PLL: Do not snap the timing window to each flux transition
|
|
*/
|
|
|
|
_flux = _flux * (1.0 - _pll_phase);
|
|
|
|
_goodbits++;
|
|
return true;
|
|
}
|
|
|
|
std::vector<bool> FluxDecoder::readBits(unsigned count)
|
|
{
|
|
std::vector<bool> result;
|
|
while (!_fmr->eof() && count--)
|
|
{
|
|
bool b = readBit();
|
|
result.push_back(b);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::vector<bool> FluxDecoder::readBits(const Fluxmap::Position& until)
|
|
{
|
|
std::vector<bool> result;
|
|
while (!_fmr->eof() && (_fmr->tell().bytes < until.bytes))
|
|
{
|
|
bool b = readBit();
|
|
result.push_back(b);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
nanoseconds_t FluxDecoder::nextFlux()
|
|
{
|
|
return _fmr->readInterval(_clock_centre) * NS_PER_TICK;
|
|
}
|