Compare commits

...

1 Commits

Author SHA1 Message Date
David Given
537324c952 I've received some unreadable Mac disks --- let's try and improve the clock and
pulse detection code.
2019-03-17 13:08:34 +01:00
7 changed files with 59 additions and 14 deletions

View File

@@ -8,10 +8,10 @@
#include "fmt/format.h"
#include <numeric>
static DoubleFlag clockDecodeThreshold(
{ "--clock-decode-threshold" },
"Pulses below this fraction of a clock tick are considered spurious and ignored.",
0.80);
static DoubleFlag pulseAccuracyFactor(
{ "--pulse-accuracy-factor" },
"Pulses must be within this much of an expected clock tick to register (in clock periods).",
0.4);
static SettableFlag showClockHistogram(
{ "--show-clock-histogram" },
@@ -114,7 +114,20 @@ nanoseconds_t Fluxmap::guessClock() const
if (showClockHistogram)
{
std::cout << "Clock detection histogram:" << std::endl;
double blocks_per_count = 320.0/max;
auto show_noise_and_signal_levels = [=] {
/* Must be 12 chars in left margin */
std::cout << fmt::format(" 0% >{:>{}}{:>{}}{:<{}}< 100%\n",
"|",
int((noise_floor*blocks_per_count)/8),
"|",
int((signal_level - noise_floor)*blocks_per_count/8),
"",
int((max - signal_level)*blocks_per_count/8));
};
show_noise_and_signal_levels();
bool skipping = true;
for (int i=0; i<256; i++)
{
@@ -122,14 +135,14 @@ nanoseconds_t Fluxmap::guessClock() const
if (value < noise_floor/2)
{
if (!skipping)
std::cout << "..." << std::endl;
show_noise_and_signal_levels();
skipping = true;
}
else
{
skipping = false;
int bar = 320*value/max;
int bar = value * blocks_per_count;
int fullblocks = bar / 8;
std::string s;
@@ -137,7 +150,8 @@ nanoseconds_t Fluxmap::guessClock() const
s += BLOCK_ELEMENTS[8];
s += BLOCK_ELEMENTS[bar & 7];
std::cout << fmt::format("{:.2f} {:6} {}", (double)i * US_PER_TICK, value, s);
/* Must be 10 chars in left margin */
std::cout << fmt::format("{:5.2f}{:6} {}", (double)i * US_PER_TICK, value, s);
std::cout << std::endl;
}
}
@@ -161,7 +175,7 @@ nanoseconds_t Fluxmap::guessClock() const
const RawBits Fluxmap::decodeToBits(nanoseconds_t clockPeriod) const
{
int pulses = duration() / clockPeriod;
nanoseconds_t lowerThreshold = clockPeriod * clockDecodeThreshold;
nanoseconds_t pulseAccuracy = pulseAccuracyFactor * clockPeriod;
auto bitmap = std::make_unique<std::vector<bool>>(pulses);
auto indices = std::make_unique<std::vector<size_t>>();
@@ -178,13 +192,17 @@ const RawBits Fluxmap::decodeToBits(nanoseconds_t clockPeriod) const
timestamp += interval * NS_PER_TICK;
if (opcode == -1)
goto abort;
else if ((opcode == 0x80) && (timestamp >= lowerThreshold))
else if (opcode == 0x80)
break;
else if (opcode == 0x81)
indices->push_back(count);
}
int clocks = (timestamp + clockPeriod/2) / clockPeriod;
nanoseconds_t expectedClock = clocks*clockPeriod;
if (abs(expectedClock - timestamp) > pulseAccuracy)
continue;
count += clocks;
if (count >= bitmap->size())
goto abort;
@@ -197,7 +215,7 @@ abort:
return rawbits;
}
nanoseconds_t AbstractDecoder::guessClock(Fluxmap& fluxmap) const
nanoseconds_t AbstractDecoder::guessClock(Fluxmap& fluxmap, unsigned physicalTrack) const
{
return fluxmap.guessClock();
}

View File

@@ -22,7 +22,7 @@ class AbstractDecoder
public:
virtual ~AbstractDecoder() {}
virtual nanoseconds_t guessClock(Fluxmap& fluxmap) const;
virtual nanoseconds_t guessClock(Fluxmap& fluxmap, unsigned physicalTrack) const;
virtual RawRecordVector extractRecords(const RawBits& rawbits) const = 0;
virtual SectorVector decodeToSectors(const RawRecordVector& rawrecords,
unsigned physicalTrack) = 0;

View File

@@ -69,7 +69,7 @@ SectorVector AbstractIbmDecoder::decodeToSectors(const RawRecordVector& rawRecor
return sectors;
}
nanoseconds_t IbmMfmDecoder::guessClock(Fluxmap& fluxmap) const
nanoseconds_t IbmMfmDecoder::guessClock(Fluxmap& fluxmap, unsigned physicalTrack) const
{
return fluxmap.guessClock() / 2;
}

View File

@@ -65,7 +65,7 @@ public:
AbstractIbmDecoder(sectorIdBase)
{}
nanoseconds_t guessClock(Fluxmap& fluxmap) const;
nanoseconds_t guessClock(Fluxmap& fluxmap, unsigned physicalTrack) const;
int recordMatcher(uint64_t fifo) const;
protected:

View File

@@ -6,10 +6,16 @@
#include "sector.h"
#include "macintosh.h"
#include "bytes.h"
#include "flags.h"
#include "fmt/format.h"
#include <string.h>
#include <algorithm>
static BoolFlag guessClockFlag(
{ "--guess-clock" },
"Guess the clock rate rather than using the hard-coded table.",
false);
static int decode_data_gcr(uint8_t gcr)
{
switch (gcr)
@@ -144,6 +150,10 @@ SectorVector MacintoshDecoder::decodeToSectors(
break;
nextSector = decode_data_gcr(rawbytes[4]);
nextSide = decode_data_gcr(rawbytes[5]);
if (nextSector > 11)
break;
if (nextSide > 1)
break;
uint8_t formatByte = decode_data_gcr(rawbytes[6]);
uint8_t wantedsum = decode_data_gcr(rawbytes[7]);
@@ -189,3 +199,19 @@ int MacintoshDecoder::recordMatcher(uint64_t fifo) const
return 24;
return 0;
}
nanoseconds_t MacintoshDecoder::guessClock(Fluxmap& fluxmap, unsigned physicalTrack) const
{
if (guessClockFlag)
return AbstractDecoder::guessClock(fluxmap, physicalTrack);
if (physicalTrack < 16)
return 2750;
if (physicalTrack < 32)
return 3000;
if (physicalTrack < 48)
return 3250;
if (physicalTrack < 64)
return 3580;
return 4000;
}

View File

@@ -17,6 +17,7 @@ public:
SectorVector decodeToSectors(const RawRecordVector& rawRecords, unsigned physicalTrack);
int recordMatcher(uint64_t fifo) const;
nanoseconds_t guessClock(Fluxmap& fluxmap, unsigned physicalTrack) const;
};
#endif

View File

@@ -147,7 +147,7 @@ void readDiskCommand(AbstractDecoder& decoder, const std::string& outputFilename
{
std::unique_ptr<Fluxmap> fluxmap = track->read();
nanoseconds_t clockPeriod = decoder.guessClock(*fluxmap);
nanoseconds_t clockPeriod = decoder.guessClock(*fluxmap, track->track);
if (clockPeriod == 0)
{
std::cout << " no clock detected; giving up" << std::endl;