mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Common out the disk read code between the two fe-read commands.
This commit is contained in:
@@ -14,14 +14,14 @@ class Fluxmap;
|
||||
class BrotherBitmapDecoder : public BitmapDecoder
|
||||
{
|
||||
public:
|
||||
RecordVector decodeBitsToRecords(const std::vector<bool>& bitmap);
|
||||
RecordVector decodeBitsToRecords(const std::vector<bool>& bitmap) const;
|
||||
};
|
||||
|
||||
class BrotherRecordParser : public RecordParser
|
||||
{
|
||||
public:
|
||||
std::vector<std::unique_ptr<Sector>> parseRecordsToSectors(
|
||||
const RecordVector& records);
|
||||
const RecordVector& records) const;
|
||||
};
|
||||
|
||||
extern void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor,
|
||||
|
||||
@@ -51,7 +51,7 @@ static void add_record(RecordVector& records,
|
||||
records.push_back(std::unique_ptr<Record>(new Record(position, data)));
|
||||
}
|
||||
|
||||
RecordVector BrotherBitmapDecoder::decodeBitsToRecords(const std::vector<bool>& bits)
|
||||
RecordVector BrotherBitmapDecoder::decodeBitsToRecords(const std::vector<bool>& bits) const
|
||||
{
|
||||
RecordVector records;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <string.h>
|
||||
|
||||
std::vector<std::unique_ptr<Sector>> BrotherRecordParser::parseRecordsToSectors(
|
||||
const RecordVector& records)
|
||||
const RecordVector& records) const
|
||||
{
|
||||
int nextTrack = 0;
|
||||
int nextSector = 0;
|
||||
|
||||
@@ -33,13 +33,18 @@ class BitmapDecoder
|
||||
public:
|
||||
virtual ~BitmapDecoder() {}
|
||||
|
||||
virtual RecordVector decodeBitsToRecords(const std::vector<bool>& bitmap) = 0;
|
||||
virtual nanoseconds_t guessClock(Fluxmap& fluxmap) const;
|
||||
|
||||
virtual RecordVector decodeBitsToRecords(
|
||||
const std::vector<bool>& bitmap) const = 0;
|
||||
};
|
||||
|
||||
class MfmBitmapDecoder
|
||||
class MfmBitmapDecoder : public BitmapDecoder
|
||||
{
|
||||
public:
|
||||
RecordVector decodeBitsToRecords(const std::vector<bool>& bitmap);
|
||||
nanoseconds_t guessClock(Fluxmap& fluxmap) const;
|
||||
|
||||
RecordVector decodeBitsToRecords(const std::vector<bool>& bitmap) const;
|
||||
};
|
||||
|
||||
class RecordParser
|
||||
@@ -48,7 +53,7 @@ public:
|
||||
virtual ~RecordParser() {}
|
||||
|
||||
virtual std::vector<std::unique_ptr<Sector>> parseRecordsToSectors(
|
||||
const RecordVector& records) = 0;
|
||||
const RecordVector& records) const = 0;
|
||||
};
|
||||
|
||||
class IbmRecordParser : public RecordParser
|
||||
@@ -59,7 +64,7 @@ public:
|
||||
{}
|
||||
|
||||
std::vector<std::unique_ptr<Sector>> parseRecordsToSectors(
|
||||
const RecordVector& records);
|
||||
const RecordVector& records) const;
|
||||
|
||||
private:
|
||||
int _sectorIdBase;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "fluxmap.h"
|
||||
#include "decoders.h"
|
||||
#include "protocol.h"
|
||||
|
||||
static IntFlag clockDetectionNoiseFloor(
|
||||
@@ -87,3 +88,8 @@ abort:
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
nanoseconds_t BitmapDecoder::guessClock(Fluxmap& fluxmap) const
|
||||
{
|
||||
return fluxmap.guessClock();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
static_assert(std::is_trivially_copyable<IbmIdam>::value);
|
||||
|
||||
std::vector<std::unique_ptr<Sector>> IbmRecordParser::parseRecordsToSectors(
|
||||
const RecordVector& records)
|
||||
const RecordVector& records) const
|
||||
{
|
||||
bool idamValid = false;
|
||||
IbmIdam idam;
|
||||
|
||||
@@ -35,7 +35,12 @@ static void add_record(RecordVector& records,
|
||||
records.push_back(std::unique_ptr<Record>(new Record(position, data)));
|
||||
}
|
||||
|
||||
RecordVector MfmBitmapDecoder::decodeBitsToRecords(const std::vector<bool>& bits)
|
||||
nanoseconds_t MfmBitmapDecoder::guessClock(Fluxmap& fluxmap) const
|
||||
{
|
||||
return fluxmap.guessClock()/2;
|
||||
}
|
||||
|
||||
RecordVector MfmBitmapDecoder::decodeBitsToRecords(const std::vector<bool>& bits) const
|
||||
{
|
||||
RecordVector records;
|
||||
|
||||
|
||||
117
lib/reader.cc
117
lib/reader.cc
@@ -5,6 +5,11 @@
|
||||
#include "fluxmap.h"
|
||||
#include "sql.h"
|
||||
#include "dataspec.h"
|
||||
#include "decoders.h"
|
||||
#include "sector.h"
|
||||
#include "sectorset.h"
|
||||
#include "record.h"
|
||||
#include "image.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
static DataSpecFlag source(
|
||||
@@ -26,6 +31,15 @@ static IntFlag revolutions(
|
||||
"read this many revolutions of the disk",
|
||||
1);
|
||||
|
||||
static SettableFlag dumpRecords(
|
||||
{ "--dump-records" },
|
||||
"Dump the parsed records.");
|
||||
|
||||
static IntFlag retries(
|
||||
{ "--retries" },
|
||||
"How many times to retry each track in the event of a read failure.",
|
||||
5);
|
||||
|
||||
static sqlite3* indb;
|
||||
static sqlite3* outdb;
|
||||
|
||||
@@ -105,3 +119,106 @@ std::vector<std::unique_ptr<ReaderTrack>> readTracks()
|
||||
|
||||
return tracks;
|
||||
}
|
||||
|
||||
void readDiskCommand(
|
||||
const BitmapDecoder& bitmapDecoder, const RecordParser& recordParser,
|
||||
const std::string& outputFilename)
|
||||
{
|
||||
bool failures = false;
|
||||
SectorSet allSectors;
|
||||
for (auto& track : readTracks())
|
||||
{
|
||||
std::map<int, std::unique_ptr<Sector>> readSectors;
|
||||
for (int retry = ::retries; retry >= 0; retry--)
|
||||
{
|
||||
std::unique_ptr<Fluxmap> fluxmap = track->read();
|
||||
|
||||
nanoseconds_t clockPeriod = bitmapDecoder.guessClock(*fluxmap);
|
||||
std::cout << fmt::format(" {:.1f} us clock; ", (double)clockPeriod/1000.0) << std::flush;
|
||||
|
||||
auto bitmap = fluxmap->decodeToBits(clockPeriod);
|
||||
std::cout << fmt::format("{} bytes encoded; ", bitmap.size()/8) << std::flush;
|
||||
|
||||
auto records = bitmapDecoder.decodeBitsToRecords(bitmap);
|
||||
std::cout << records.size() << " records." << std::endl;
|
||||
|
||||
auto sectors = recordParser.parseRecordsToSectors(records);
|
||||
std::cout << " " << sectors.size() << " sectors; ";
|
||||
|
||||
for (auto& sector : sectors)
|
||||
{
|
||||
auto& replacing = readSectors[sector->sector];
|
||||
if (sector->status == Sector::OK)
|
||||
replacing = std::move(sector);
|
||||
else
|
||||
{
|
||||
if (!replacing || (replacing->status == Sector::OK))
|
||||
replacing = std::move(sector);
|
||||
}
|
||||
}
|
||||
|
||||
bool hasBadSectors = false;
|
||||
for (const auto& i : readSectors)
|
||||
{
|
||||
const auto& sector = i.second;
|
||||
if (sector->status != Sector::OK)
|
||||
{
|
||||
std::cout << std::endl
|
||||
<< " Failed to read sector " << sector->sector
|
||||
<< " (" << Sector::statusToString((Sector::Status)sector->status) << "); ";
|
||||
hasBadSectors = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasBadSectors)
|
||||
failures = false;
|
||||
|
||||
if (dumpRecords && (!hasBadSectors || (retry == 0)))
|
||||
{
|
||||
std::cout << "\nRaw records follow:\n\n";
|
||||
for (auto& record : records)
|
||||
{
|
||||
std::cout << fmt::format("I+{:.3f}ms", (double)(record->position*clockPeriod)/1e6)
|
||||
<< std::endl;
|
||||
hexdump(std::cout, record->data);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasBadSectors)
|
||||
break;
|
||||
|
||||
std::cout << std::endl
|
||||
<< " ";
|
||||
if (retries == 0)
|
||||
std::cout << "giving up" << std::endl
|
||||
<< " ";
|
||||
else
|
||||
std::cout << retry << " retries remaining" << std::endl;
|
||||
}
|
||||
|
||||
int size = 0;
|
||||
bool printedTrack = false;
|
||||
for (auto& i : readSectors)
|
||||
{
|
||||
auto& sector = i.second;
|
||||
if (sector)
|
||||
{
|
||||
if (!printedTrack)
|
||||
{
|
||||
std::cout << "logical track " << sector->track << "; ";
|
||||
printedTrack = true;
|
||||
}
|
||||
|
||||
size += sector->data.size();
|
||||
allSectors[{sector->track, sector->side, sector->sector}] = std::move(sector);
|
||||
}
|
||||
}
|
||||
std::cout << size << " bytes decoded." << std::endl;
|
||||
}
|
||||
|
||||
Geometry geometry = guessGeometry(allSectors);
|
||||
writeSectorsToFile(allSectors, geometry, outputFilename);
|
||||
if (failures)
|
||||
std::cerr << "Warning: some sectors could not be decoded." << std::endl;
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
#define READER_H
|
||||
|
||||
class Fluxmap;
|
||||
class BitmapDecoder;
|
||||
class RecordParser;
|
||||
|
||||
class ReaderTrack
|
||||
{
|
||||
@@ -30,4 +32,8 @@ public:
|
||||
extern void setReaderDefaultSource(const std::string& source);
|
||||
extern std::vector<std::unique_ptr<ReaderTrack>> readTracks();
|
||||
|
||||
extern void readDiskCommand(
|
||||
const BitmapDecoder& bitmapDecoder, const RecordParser& recordParser,
|
||||
const std::string& outputFilename);
|
||||
|
||||
#endif
|
||||
|
||||
18
meson.build
18
meson.build
@@ -35,14 +35,6 @@ sqllib = shared_library('sqllib',
|
||||
['lib/sql.cc'],
|
||||
link_with: [felib],
|
||||
dependencies: [sqlite])
|
||||
readerlib = shared_library('readerlib',
|
||||
['lib/reader.cc'],
|
||||
include_directories: [fmtinc],
|
||||
link_with: [felib, sqllib, fmtlib])
|
||||
writerlib = shared_library('writerlib',
|
||||
['lib/writer.cc'],
|
||||
include_directories: [fmtinc],
|
||||
link_with: [felib, sqllib, fmtlib])
|
||||
|
||||
decoderlib = shared_library('decoderlib',
|
||||
[
|
||||
@@ -55,6 +47,16 @@ decoderlib = shared_library('decoderlib',
|
||||
)
|
||||
decoderinc = include_directories('lib/decoders')
|
||||
|
||||
readerlib = shared_library('readerlib',
|
||||
['lib/reader.cc'],
|
||||
include_directories: [fmtinc, decoderinc],
|
||||
link_with: [felib, sqllib, fmtlib, decoderlib])
|
||||
|
||||
writerlib = shared_library('writerlib',
|
||||
['lib/writer.cc'],
|
||||
include_directories: [fmtinc],
|
||||
link_with: [felib, sqllib, fmtlib])
|
||||
|
||||
encoderlib = shared_library('encoderlib',
|
||||
[
|
||||
'lib/encoder.cc',
|
||||
|
||||
@@ -16,15 +16,6 @@ static StringFlag outputFilename(
|
||||
"The output image file to write to.",
|
||||
"brother.img");
|
||||
|
||||
static SettableFlag dumpRecords(
|
||||
{ "--dump-records" },
|
||||
"Dump the parsed records.");
|
||||
|
||||
static IntFlag retries(
|
||||
{ "--retries" },
|
||||
"How many times to retry each track in the event of a read failure.",
|
||||
5);
|
||||
|
||||
#define SECTOR_COUNT 12
|
||||
#define TRACK_COUNT 78
|
||||
|
||||
@@ -33,106 +24,10 @@ int main(int argc, const char* argv[])
|
||||
setReaderDefaultSource(":t=0-81:s=0");
|
||||
Flag::parseFlags(argc, argv);
|
||||
|
||||
BrotherRecordParser recordParser;
|
||||
BrotherBitmapDecoder bitmapDecoder;
|
||||
BrotherRecordParser recordParser;
|
||||
readDiskCommand(bitmapDecoder, recordParser, outputFilename);
|
||||
|
||||
bool failures = false;
|
||||
SectorSet allSectors;
|
||||
for (auto& track : readTracks())
|
||||
{
|
||||
std::map<int, std::unique_ptr<Sector>> readSectors;
|
||||
for (int retry = ::retries; retry >= 0; retry--)
|
||||
{
|
||||
std::unique_ptr<Fluxmap> fluxmap = track->read();
|
||||
|
||||
nanoseconds_t clockPeriod = fluxmap->guessClock();
|
||||
std::cout << fmt::format(" {:.1f} us clock; ", (double)clockPeriod/1000.0) << std::flush;
|
||||
|
||||
auto bitmap = fluxmap->decodeToBits(clockPeriod);
|
||||
std::cout << fmt::format("{} bytes encoded; ", bitmap.size()/8) << std::flush;
|
||||
|
||||
auto records = bitmapDecoder.decodeBitsToRecords(bitmap);
|
||||
std::cout << records.size() << " records." << std::endl;
|
||||
|
||||
auto sectors = recordParser.parseRecordsToSectors(records);
|
||||
std::cout << " " << sectors.size() << " sectors; ";
|
||||
|
||||
for (auto& sector : sectors)
|
||||
{
|
||||
if ((sector->sector < SECTOR_COUNT) && (sector->track < TRACK_COUNT))
|
||||
{
|
||||
auto& replacing = readSectors[sector->sector];
|
||||
if (sector->status == Sector::OK)
|
||||
replacing = std::move(sector);
|
||||
else
|
||||
{
|
||||
if (!replacing || (replacing->status == Sector::OK))
|
||||
replacing = std::move(sector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool hasBadSectors = false;
|
||||
for (int i=0; i<SECTOR_COUNT; i++)
|
||||
{
|
||||
auto& sector = readSectors[i];
|
||||
Sector::Status status = sector ? (Sector::Status)sector->status : Sector::MISSING;
|
||||
if (status != Sector::OK)
|
||||
{
|
||||
std::cout << std::endl
|
||||
<< " Failed to read sector " << i
|
||||
<< " (" << Sector::statusToString(status) << "); ";
|
||||
hasBadSectors = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasBadSectors)
|
||||
failures = false;
|
||||
|
||||
if (dumpRecords && (!hasBadSectors || (retry == 0)))
|
||||
{
|
||||
std::cout << "\nRaw records follow:\n\n";
|
||||
for (auto& record : records)
|
||||
{
|
||||
std::cout << fmt::format("I+{:.3f}ms", (double)(record->position*clockPeriod)/1e6)
|
||||
<< std::endl;
|
||||
hexdump(std::cout, record->data);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasBadSectors)
|
||||
break;
|
||||
|
||||
std::cout << std::endl
|
||||
<< " " << retry << " retries remaining" << std::endl;
|
||||
}
|
||||
|
||||
int size = 0;
|
||||
bool printedTrack = false;
|
||||
for (int sectorId = 0; sectorId < SECTOR_COUNT; sectorId++)
|
||||
{
|
||||
auto& sector = readSectors[sectorId];
|
||||
if (sector)
|
||||
{
|
||||
if (!printedTrack)
|
||||
{
|
||||
std::cout << "logical track " << sector->track << "; ";
|
||||
printedTrack = true;
|
||||
}
|
||||
|
||||
size += sector->data.size();
|
||||
allSectors[{sector->track, 0, sector->sector}] = std::move(sector);
|
||||
}
|
||||
}
|
||||
std::cout << size << " bytes decoded." << std::endl;
|
||||
|
||||
}
|
||||
|
||||
Geometry geometry = guessGeometry(allSectors);
|
||||
writeSectorsToFile(allSectors, geometry, outputFilename);
|
||||
if (failures)
|
||||
std::cerr << "Warning: some sectors could not be decoded." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,6 @@ static StringFlag outputFilename(
|
||||
"The output image file to write to.",
|
||||
"ibm.img");
|
||||
|
||||
static SettableFlag dumpRecords(
|
||||
{ "--dump-records" },
|
||||
"Dump the parsed records.");
|
||||
|
||||
static IntFlag sectorIdBase(
|
||||
{ "--sector-id-base" },
|
||||
"Sector ID of the first sector.",
|
||||
@@ -28,88 +24,9 @@ int main(int argc, const char* argv[])
|
||||
setReaderDefaultSource(":t=0-79:s=0-1");
|
||||
Flag::parseFlags(argc, argv);
|
||||
|
||||
IbmRecordParser recordParser(sectorIdBase);
|
||||
MfmBitmapDecoder bitmapDecoder;
|
||||
|
||||
bool failures = false;
|
||||
SectorSet allSectors;
|
||||
for (auto& track : readTracks())
|
||||
{
|
||||
int retries = 5;
|
||||
std::map<int, std::unique_ptr<Sector>> goodSectors;
|
||||
|
||||
retry:
|
||||
std::unique_ptr<Fluxmap> fluxmap = track->read();
|
||||
nanoseconds_t clockPeriod = fluxmap->guessClock();
|
||||
std::cout << fmt::format(" {:.1f} us clock; ", (double)clockPeriod/1000.0) << std::flush;
|
||||
|
||||
/* For MFM, the bit clock is half the detected clock. */
|
||||
auto bitmap = fluxmap->decodeToBits(clockPeriod/2);
|
||||
std::cout << fmt::format("{} bytes encoded; ", bitmap.size()/8) << std::flush;
|
||||
|
||||
auto records = bitmapDecoder.decodeBitsToRecords(bitmap);
|
||||
std::cout << records.size() << " records." << std::endl;
|
||||
|
||||
auto sectors = recordParser.parseRecordsToSectors(records);
|
||||
std::cout << " " << sectors.size() << " sectors; ";
|
||||
|
||||
bool hasBadSectors = false;
|
||||
for (auto& sector : sectors)
|
||||
{
|
||||
bool sectorPending = goodSectors.find(sector->sector) == goodSectors.end();
|
||||
if (sectorPending)
|
||||
{
|
||||
if (sector->status != Sector::OK)
|
||||
{
|
||||
std::cout << std::endl
|
||||
<< " Bad CRC on sector " << sector->sector << "; ";
|
||||
hasBadSectors = true;
|
||||
}
|
||||
|
||||
if (((sector->status == Sector::OK) || (retries == 0)) && (sector->sector >= 0))
|
||||
goodSectors[sector->sector] = std::move(sector);
|
||||
}
|
||||
}
|
||||
if (hasBadSectors)
|
||||
{
|
||||
if (retries == 0)
|
||||
failures = true;
|
||||
else
|
||||
{
|
||||
std::cout << std::endl
|
||||
<< " " << retries << " retries remaining" << std::endl;
|
||||
retries--;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
int size = 0;
|
||||
for (auto& i : goodSectors)
|
||||
{
|
||||
auto& sector = i.second;
|
||||
size += sector->data.size();
|
||||
allSectors[{sector->track, sector->side, sector->sector}] =
|
||||
std::move(sector);
|
||||
}
|
||||
std::cout << size << " bytes decoded." << std::endl;
|
||||
|
||||
if (dumpRecords)
|
||||
{
|
||||
std::cout << "\nRaw records follow:\n\n";
|
||||
for (auto& record : records)
|
||||
{
|
||||
std::cout << fmt::format("I+{:.3f}ms", (double)(record->position*clockPeriod)/1e6)
|
||||
<< std::endl;
|
||||
hexdump(std::cout, record->data);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Geometry geometry = guessGeometry(allSectors);
|
||||
writeSectorsToFile(allSectors, geometry, outputFilename);
|
||||
if (failures)
|
||||
std::cerr << "Warning: some sectors could not be decoded." << std::endl;
|
||||
IbmRecordParser recordParser(sectorIdBase);
|
||||
readDiskCommand(bitmapDecoder, recordParser, outputFilename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user