Refactor the low-level reading stuff to be cleaner, simpler, and allow more

flux sources.
This commit is contained in:
David Given
2019-02-14 20:15:35 +01:00
parent c68dc4eeb3
commit 31a00696e1
10 changed files with 206 additions and 105 deletions

View File

@@ -46,6 +46,7 @@ public:
std::map<std::string, Modifier> modifiers;
std::vector<Location> locations;
unsigned drive;
unsigned revolutions;
};
std::ostream& operator << (std::ostream& os, const DataSpec& dataSpec)

View File

@@ -0,0 +1,24 @@
#include "globals.h"
#include "flags.h"
#include "dataspec.h"
#include "fluxreader.h"
static bool ends_with(const std::string& value, const std::string& ending)
{
if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
std::unique_ptr<FluxReader> FluxReader::create(const DataSpec& spec)
{
const auto& filename = spec.filename;
if (filename.empty())
return createHardwareFluxReader(spec.drive);
else if (ends_with(filename, ".flux"))
return createSqliteFluxReader(filename);
Error() << "unrecognised flux filename extension";
return std::unique_ptr<FluxReader>();
}

View File

@@ -0,0 +1,27 @@
#ifndef FLUXREADER_H
#define FLUXREADER_H
class Fluxmap;
class DataSpec;
class FluxReader
{
public:
virtual ~FluxReader() {}
private:
static std::unique_ptr<FluxReader> createSqliteFluxReader(const std::string& filename);
static std::unique_ptr<FluxReader> createHardwareFluxReader(unsigned drive);
public:
static std::unique_ptr<FluxReader> create(const DataSpec& spec);
public:
virtual std::unique_ptr<Fluxmap> readFlux(int track, int side) = 0;
virtual void recalibrate() {}
};
extern void setHardwareFluxReaderRevolutions(int revolutions);
#endif

View File

@@ -0,0 +1,52 @@
#include "globals.h"
#include "flags.h"
#include "fluxmap.h"
#include "usb.h"
#include "fluxreader.h"
static IntFlag revolutions(
{ "--revolutions" },
"read this many revolutions of the disk",
1);
class HardwareFluxReader : public FluxReader
{
public:
HardwareFluxReader(unsigned drive):
_drive(drive)
{
}
~HardwareFluxReader()
{
}
public:
std::unique_ptr<Fluxmap> readFlux(int track, int side)
{
usbSetDrive(_drive);
usbSeek(track);
return usbRead(side, revolutions);
}
void recalibrate() {
usbRecalibrate();
}
private:
unsigned _drive;
unsigned _revolutions;
};
void setHardwareFluxReaderRevolutions(int revolutions)
{
::revolutions.value = ::revolutions.defaultValue = revolutions;
}
std::unique_ptr<FluxReader> FluxReader::createHardwareFluxReader(unsigned drive)
{
return std::unique_ptr<FluxReader>(new HardwareFluxReader(drive));
}

View File

@@ -0,0 +1,37 @@
#include "globals.h"
#include "fluxmap.h"
#include "sql.h"
#include "fluxreader.h"
class SqliteFluxReader : public FluxReader
{
public:
SqliteFluxReader(const std::string& filename)
{
_indb = sqlOpen(filename, SQLITE_OPEN_READONLY);
}
~SqliteFluxReader()
{
if (_indb)
sqlClose(_indb);
}
public:
std::unique_ptr<Fluxmap> readFlux(int track, int side)
{
return sqlReadFlux(_indb, track, side);
}
void recalibrate() {}
private:
sqlite3* _indb;
};
std::unique_ptr<FluxReader> FluxReader::createSqliteFluxReader(const std::string& filename)
{
return std::unique_ptr<FluxReader>(new SqliteFluxReader(filename));
}

View File

@@ -1,6 +1,7 @@
#include "globals.h"
#include "flags.h"
#include "usb.h"
#include "fluxreader.h"
#include "reader.h"
#include "fluxmap.h"
#include "sql.h"
@@ -22,15 +23,6 @@ static StringFlag destination(
"write the raw magnetic flux to this file",
"");
static SettableFlag justRead(
{ "--just-read", "-R" },
"just read the disk but do no further processing");
static IntFlag revolutions(
{ "--revolutions" },
"read this many revolutions of the disk",
1);
static SettableFlag dumpRecords(
{ "--dump-records" },
"Dump the parsed records.");
@@ -40,7 +32,6 @@ static IntFlag retries(
"How many times to retry each track in the event of a read failure.",
5);
static sqlite3* indb;
static sqlite3* outdb;
void setReaderDefaultSource(const std::string& source)
@@ -50,48 +41,21 @@ void setReaderDefaultSource(const std::string& source)
void setReaderRevolutions(int revolutions)
{
::revolutions.value = ::revolutions.defaultValue = revolutions;
setHardwareFluxReaderRevolutions(revolutions);
}
std::unique_ptr<Fluxmap> ReaderTrack::read()
std::unique_ptr<Fluxmap> Track::read()
{
std::cout << fmt::format("{0:>3}.{1}: ", track, side) << std::flush;
std::unique_ptr<Fluxmap> fluxmap = reallyRead();
std::cout << fmt::format(
"{0} ms in {1} bytes", int(fluxmap->duration()/1e6), fluxmap->bytes()) << std::endl;
if (outdb)
sqlWriteFlux(outdb, track, side, *fluxmap);
return fluxmap;
std::cout << fmt::format("reading track {} side {}", track, side) << std::endl;
return _fluxReader->readFlux(track, side);
}
std::unique_ptr<Fluxmap> CapturedReaderTrack::reallyRead()
void Track::recalibrate()
{
usbSetDrive(drive);
usbSeek(track);
return usbRead(side, revolutions);
_fluxReader->recalibrate();
}
void CapturedReaderTrack::recalibrate()
{
usbRecalibrate();
}
std::unique_ptr<Fluxmap> FileReaderTrack::reallyRead()
{
if (!indb)
{
indb = sqlOpen(source.value.filename, SQLITE_OPEN_READONLY);
atexit([]() { sqlClose(indb); });
}
return sqlReadFlux(indb, track, side);
}
void FileReaderTrack::recalibrate()
{}
std::vector<std::unique_ptr<ReaderTrack>> readTracks()
std::vector<std::unique_ptr<Track>> readTracks()
{
const DataSpec& dataSpec = source.value;
@@ -111,28 +75,14 @@ std::vector<std::unique_ptr<ReaderTrack>> readTracks()
);
}
std::vector<std::unique_ptr<ReaderTrack>> tracks;
for (const auto& location : dataSpec.locations)
{
std::unique_ptr<ReaderTrack> t(
dataSpec.filename.empty()
? (ReaderTrack*)new CapturedReaderTrack()
: (ReaderTrack*)new FileReaderTrack());
t->drive = location.drive;
t->track = location.track;
t->side = location.side;
tracks.push_back(std::move(t));
}
std::shared_ptr<FluxReader> fluxreader = FluxReader::create(dataSpec);
if (justRead)
{
for (auto& track : tracks)
track->read();
std::cout << "--just-read specified, terminating without further processing" << std::endl;
exit(0);
}
return tracks;
std::vector<std::unique_ptr<Track>> tracks;
for (const auto& location : dataSpec.locations)
tracks.push_back(
std::unique_ptr<Track>(new Track(fluxreader, location.track, location.side)));
return tracks;
}
void readDiskCommand(
@@ -141,12 +91,17 @@ void readDiskCommand(
{
bool failures = false;
SectorSet allSectors;
for (auto& track : readTracks())
{
for (const auto& track : readTracks())
{
std::map<int, std::unique_ptr<Sector>> readSectors;
for (int retry = ::retries; retry >= 0; retry--)
{
std::cout << fmt::format("{0:>3}.{1}: ", track->track, track->side) << std::flush;
std::unique_ptr<Fluxmap> fluxmap = track->read();
std::cout << fmt::format(
"{0} ms in {1} bytes", int(fluxmap->duration()/1e6), fluxmap->bytes()) << std::endl;
if (outdb)
sqlWriteFlux(outdb, track->track, track->side, *fluxmap);
nanoseconds_t clockPeriod = bitmapDecoder.guessClock(*fluxmap);
std::cout << fmt::format(" {:.2f} us clock; ", (double)clockPeriod/1000.0) << std::flush;
@@ -219,7 +174,7 @@ void readDiskCommand(
{
if (!printedTrack)
{
std::cout << "logical track " << sector->track << "; ";
std::cout << fmt::format("logical track {}.{}; ", sector->track, sector->side);
printedTrack = true;
}

View File

@@ -2,40 +2,34 @@
#define READER_H
class Fluxmap;
class FluxReader;
class BitmapDecoder;
class RecordParser;
class ReaderTrack
{
public:
virtual ~ReaderTrack() {}
int drive;
int track;
int side;
std::unique_ptr<Fluxmap> read();
virtual std::unique_ptr<Fluxmap> reallyRead() = 0;
virtual void recalibrate() = 0;
};
class CapturedReaderTrack : public ReaderTrack
{
public:
std::unique_ptr<Fluxmap> reallyRead();
void recalibrate();
};
class FileReaderTrack : public ReaderTrack
{
public:
std::unique_ptr<Fluxmap> reallyRead();
void recalibrate();
};
extern void setReaderDefaultSource(const std::string& source);
extern void setReaderRevolutions(int revolutions);
extern std::vector<std::unique_ptr<ReaderTrack>> readTracks();
class Track
{
public:
Track(std::shared_ptr<FluxReader>& fluxReader, unsigned track, unsigned side):
track(track),
side(side),
_fluxReader(fluxReader)
{}
public:
std::unique_ptr<Fluxmap> read();
void recalibrate();
unsigned track;
unsigned side;
private:
std::shared_ptr<FluxReader> _fluxReader;
};
extern std::vector<std::unique_ptr<Track>> readTracks();
extern void readDiskCommand(
const BitmapDecoder& bitmapDecoder, const RecordParser& recordParser,

View File

@@ -31,9 +31,21 @@ felib = shared_library('felib',
feinc = include_directories('lib')
sqllib = shared_library('sqllib',
['lib/sql.cc'],
link_with: [felib],
dependencies: [sqlite])
['lib/sql.cc'],
link_with: [felib],
dependencies: [sqlite]
)
fluxreaderlib = shared_library('fluxreaderlib',
[
'lib/fluxreader/fluxreader.cc',
'lib/fluxreader/sqlitefluxreader.cc',
'lib/fluxreader/hardwarefluxreader.cc',
],
include_directories: [feinc, fmtinc],
link_with: [felib, sqllib, fmtlib]
)
fluxreaderinc = include_directories('lib/fluxreader')
decoderlib = shared_library('decoderlib',
[
@@ -49,8 +61,8 @@ decoderinc = include_directories('lib/decoders')
readerlib = shared_library('readerlib',
['lib/reader.cc'],
include_directories: [fmtinc, decoderinc],
link_with: [felib, sqllib, fmtlib, decoderlib])
include_directories: [fmtinc, decoderinc, fluxreaderinc],
link_with: [felib, sqllib, fmtlib, decoderlib, fluxreaderlib])
writerlib = shared_library('writerlib',
['lib/writer.cc'],

View File

@@ -1,6 +1,5 @@
#include "globals.h"
#include "flags.h"
#include "reader.h"
#include "fluxmap.h"
#include "sector.h"
#include "sectorset.h"

View File

@@ -18,7 +18,7 @@ int main(int argc, const char* argv[])
track->read();
writeTracks(
[&](int physicalTrack, int physicalSide) -> std::unique_ptr<Fluxmap>
[&](unsigned physicalTrack, unsigned physicalSide) -> std::unique_ptr<Fluxmap>
{
for (auto& track : tracks)
{