mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Rename FluxReader and FluxWriter to FluxSource and FluxSink.
This commit is contained in:
26
lib/fluxsource/fluxsource.cc
Normal file
26
lib/fluxsource/fluxsource.cc
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "dataspec.h"
|
||||
#include "fluxsource.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<FluxSource> FluxSource::create(const DataSpec& spec)
|
||||
{
|
||||
const auto& filename = spec.filename;
|
||||
|
||||
if (filename.empty())
|
||||
return createHardwareFluxSource(spec.drive);
|
||||
else if (ends_with(filename, ".flux"))
|
||||
return createSqliteFluxSource(filename);
|
||||
else if (ends_with(filename, "/"))
|
||||
return createStreamFluxSource(filename);
|
||||
|
||||
Error() << "unrecognised flux filename extension";
|
||||
return std::unique_ptr<FluxSource>();
|
||||
}
|
||||
30
lib/fluxsource/fluxsource.h
Normal file
30
lib/fluxsource/fluxsource.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef FLUXSOURCE_H
|
||||
#define FLUXSOURCE_H
|
||||
|
||||
class Fluxmap;
|
||||
class DataSpec;
|
||||
|
||||
class FluxSource
|
||||
{
|
||||
public:
|
||||
virtual ~FluxSource() {}
|
||||
|
||||
private:
|
||||
static std::unique_ptr<FluxSource> createSqliteFluxSource(const std::string& filename);
|
||||
static std::unique_ptr<FluxSource> createHardwareFluxSource(unsigned drive);
|
||||
static std::unique_ptr<FluxSource> createStreamFluxSource(const std::string& path);
|
||||
|
||||
public:
|
||||
static std::unique_ptr<FluxSource> create(const DataSpec& spec);
|
||||
|
||||
public:
|
||||
virtual std::unique_ptr<Fluxmap> readFlux(int track, int side) = 0;
|
||||
virtual void recalibrate() {}
|
||||
virtual bool retryable() { return false; }
|
||||
};
|
||||
|
||||
extern void setHardwareFluxSourceRevolutions(int revolutions);
|
||||
extern void setHardwareFluxSourceDensity(bool high_density);
|
||||
|
||||
#endif
|
||||
|
||||
68
lib/fluxsource/hardwarefluxsource.cc
Normal file
68
lib/fluxsource/hardwarefluxsource.cc
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "fluxmap.h"
|
||||
#include "usb.h"
|
||||
#include "fluxsource.h"
|
||||
|
||||
static IntFlag revolutions(
|
||||
{ "--revolutions" },
|
||||
"read this many revolutions of the disk",
|
||||
1);
|
||||
|
||||
static bool high_density = false;
|
||||
|
||||
void setHardwareFluxSourceDensity(bool high_density)
|
||||
{
|
||||
::high_density = high_density;
|
||||
}
|
||||
|
||||
class HardwareFluxSource : public FluxSource
|
||||
{
|
||||
public:
|
||||
HardwareFluxSource(unsigned drive):
|
||||
_drive(drive)
|
||||
{
|
||||
}
|
||||
|
||||
~HardwareFluxSource()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
std::unique_ptr<Fluxmap> readFlux(int track, int side)
|
||||
{
|
||||
usbSetDrive(_drive, high_density);
|
||||
usbSeek(track);
|
||||
Bytes crunched = usbRead(side, revolutions);
|
||||
auto fluxmap = std::make_unique<Fluxmap>();
|
||||
fluxmap->appendBytes(crunched.uncrunch());
|
||||
return fluxmap;
|
||||
}
|
||||
|
||||
void recalibrate()
|
||||
{
|
||||
usbRecalibrate();
|
||||
}
|
||||
|
||||
bool retryable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned _drive;
|
||||
unsigned _revolutions;
|
||||
};
|
||||
|
||||
void setHardwareFluxSourceRevolutions(int revolutions)
|
||||
{
|
||||
::revolutions.value = ::revolutions.defaultValue = revolutions;
|
||||
}
|
||||
|
||||
std::unique_ptr<FluxSource> FluxSource::createHardwareFluxSource(unsigned drive)
|
||||
{
|
||||
return std::unique_ptr<FluxSource>(new HardwareFluxSource(drive));
|
||||
}
|
||||
|
||||
|
||||
|
||||
223
lib/fluxsource/kryoflux.cc
Normal file
223
lib/fluxsource/kryoflux.cc
Normal file
@@ -0,0 +1,223 @@
|
||||
#include "globals.h"
|
||||
#include "fluxmap.h"
|
||||
#include "kryoflux.h"
|
||||
#include "protocol.h"
|
||||
#include "fmt/format.h"
|
||||
#include <fstream>
|
||||
#include <glob.h>
|
||||
|
||||
#define MCLK_HZ (((18432000.0 * 73.0) / 14.0) / 2.0)
|
||||
#define SCLK_HZ (MCLK_HZ / 2)
|
||||
#define ICLK_HZ (MCLK_HZ / 16)
|
||||
|
||||
#define TICKS_PER_SCLK (TICK_FREQUENCY / SCLK_HZ)
|
||||
|
||||
std::unique_ptr<Fluxmap> readStream(const std::string& dir, unsigned track, unsigned side)
|
||||
{
|
||||
std::string suffix = fmt::format("{:02}.{}.raw", track, side);
|
||||
std::string pattern = fmt::format("{}*{}", dir, suffix);
|
||||
glob_t globdata;
|
||||
if (glob(pattern.c_str(), GLOB_NOSORT, NULL, &globdata))
|
||||
Error() << fmt::format("cannot access path '{}'", dir);
|
||||
if (globdata.gl_pathc != 1)
|
||||
Error() << fmt::format("data is ambiguous --- multiple files end in {}", suffix);
|
||||
std::string filename = globdata.gl_pathv[0];
|
||||
globfree(&globdata);
|
||||
|
||||
return readStream(filename);
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> readStream(const std::string& filename)
|
||||
{
|
||||
std::ifstream f(filename, std::ios::in | std::ios::binary);
|
||||
if (!f.is_open())
|
||||
Error() << fmt::format("cannot open input file '{}'", filename);
|
||||
|
||||
Bytes bytes;
|
||||
ByteWriter bw(bytes);
|
||||
bw.append(f);
|
||||
|
||||
return readStream(bytes);
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> readStream(const Bytes& bytes)
|
||||
{
|
||||
ByteReader br(bytes);
|
||||
|
||||
/* Pass 1: scan the stream looking for index marks. */
|
||||
|
||||
std::set<uint32_t> indexmarks;
|
||||
br.seek(0);
|
||||
while (!br.eof())
|
||||
{
|
||||
uint8_t b = br.read_8();
|
||||
unsigned len = 0;
|
||||
switch (b)
|
||||
{
|
||||
case 0x0d: /* OOB block */
|
||||
{
|
||||
int blocktype = br.read_8();
|
||||
len = br.read_le16();
|
||||
if (br.eof())
|
||||
goto finished_pass_1;
|
||||
|
||||
if (blocktype == 0x02)
|
||||
{
|
||||
/* index data, sent asynchronously */
|
||||
uint32_t streampos = br.read_le32();
|
||||
indexmarks.insert(streampos);
|
||||
len -= 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if ((b >= 0x00) && (b <= 0x07))
|
||||
{
|
||||
/* Flux2: double byte value */
|
||||
len = 1;
|
||||
}
|
||||
else if (b == 0x08)
|
||||
{
|
||||
/* Nop1: do nothing */
|
||||
len = 0;
|
||||
}
|
||||
else if (b == 0x09)
|
||||
{
|
||||
/* Nop2: skip one byte */
|
||||
len = 1;
|
||||
}
|
||||
else if (b == 0x0a)
|
||||
{
|
||||
/* Nop3: skip two bytes */
|
||||
len = 2;
|
||||
}
|
||||
else if (b == 0x0b)
|
||||
{
|
||||
/* Ovl16: the next block is 0x10000 sclks longer than normal. */
|
||||
len = 0;
|
||||
}
|
||||
else if (b == 0x0c)
|
||||
{
|
||||
/* Flux3: triple byte value */
|
||||
len = 2;
|
||||
}
|
||||
else if ((b >= 0x0e) && (b <= 0xff))
|
||||
{
|
||||
/* Flux1: single byte value */
|
||||
len = 0;
|
||||
}
|
||||
else
|
||||
Error() << fmt::format(
|
||||
"unknown stream block byte 0x{:02x} at 0x{:08x}", b, (uint64_t)br.pos-1);
|
||||
}
|
||||
}
|
||||
|
||||
br.skip(len);
|
||||
}
|
||||
finished_pass_1:
|
||||
|
||||
/* Pass 2: actually read the data. */
|
||||
|
||||
std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
|
||||
int streamdelta = 0;
|
||||
auto writeFlux = [&](uint32_t sclk)
|
||||
{
|
||||
const auto& nextindex = indexmarks.begin();
|
||||
if (nextindex != indexmarks.end())
|
||||
{
|
||||
uint32_t nextindexpos = *nextindex + streamdelta;
|
||||
if (br.pos >= nextindexpos)
|
||||
{
|
||||
fluxmap->appendIndex();
|
||||
indexmarks.erase(nextindex);
|
||||
}
|
||||
}
|
||||
int ticks = (double)sclk * TICKS_PER_SCLK;
|
||||
fluxmap->appendInterval(ticks);
|
||||
fluxmap->appendPulse();
|
||||
};
|
||||
|
||||
uint32_t extrasclks = 0;
|
||||
br.seek(0);
|
||||
while (!br.eof())
|
||||
{
|
||||
unsigned b = br.read_8();
|
||||
switch (b)
|
||||
{
|
||||
case 0x0d: /* OOB block */
|
||||
{
|
||||
int blocktype = br.read_8();
|
||||
uint16_t blocklen = br.read_le16();
|
||||
if (br.eof())
|
||||
goto finished_pass_2;
|
||||
|
||||
switch (blocktype)
|
||||
{
|
||||
case 0x01: /* streaminfo */
|
||||
{
|
||||
uint32_t blockpos = br.pos - 3;
|
||||
streamdelta = blockpos - br.read_le32();
|
||||
blocklen -= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
br.skip(blocklen);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if ((b >= 0x00) && (b <= 0x07))
|
||||
{
|
||||
/* Flux2: double byte value */
|
||||
b = (b<<8) | br.read_8();
|
||||
writeFlux(extrasclks + b);
|
||||
extrasclks = 0;
|
||||
}
|
||||
else if (b == 0x08)
|
||||
{
|
||||
/* Nop1: do nothing */
|
||||
}
|
||||
else if (b == 0x09)
|
||||
{
|
||||
/* Nop2: skip one byte */
|
||||
br.skip(1);
|
||||
}
|
||||
else if (b == 0x0a)
|
||||
{
|
||||
/* Nop3: skip two bytes */
|
||||
br.skip(2);
|
||||
}
|
||||
else if (b == 0x0b)
|
||||
{
|
||||
/* Ovl16: the next block is 0x10000 sclks longer than normal. */
|
||||
extrasclks += 0x10000;
|
||||
}
|
||||
else if (b == 0x0c)
|
||||
{
|
||||
/* Flux3: triple byte value */
|
||||
int ticks = br.read_be16(); /* yes, really big-endian */
|
||||
writeFlux(extrasclks + ticks);
|
||||
extrasclks = 0;
|
||||
}
|
||||
else if ((b >= 0x0e) && (b <= 0xff))
|
||||
{
|
||||
/* Flux1: single byte value */
|
||||
writeFlux(extrasclks + b);
|
||||
extrasclks = 0;
|
||||
}
|
||||
else
|
||||
Error() << fmt::format(
|
||||
"unknown stream block byte 0x{:02x} at 0x{:08x}", b, (uint64_t)br.pos-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finished_pass_2:
|
||||
if (!br.eof())
|
||||
Error() << "I/O error reading stream";
|
||||
return fluxmap;
|
||||
}
|
||||
8
lib/fluxsource/kryoflux.h
Normal file
8
lib/fluxsource/kryoflux.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef STREAM_H
|
||||
#define STREAM_H
|
||||
|
||||
extern std::unique_ptr<Fluxmap> readStream(const std::string& dir, unsigned track, unsigned side);
|
||||
extern std::unique_ptr<Fluxmap> readStream(const std::string& path);
|
||||
extern std::unique_ptr<Fluxmap> readStream(const Bytes& bytes);
|
||||
|
||||
#endif
|
||||
42
lib/fluxsource/sqlitefluxsource.cc
Normal file
42
lib/fluxsource/sqlitefluxsource.cc
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "globals.h"
|
||||
#include "fluxmap.h"
|
||||
#include "sql.h"
|
||||
#include "fluxsource.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
class SqliteFluxSource : public FluxSource
|
||||
{
|
||||
public:
|
||||
SqliteFluxSource(const std::string& filename)
|
||||
{
|
||||
_indb = sqlOpen(filename, SQLITE_OPEN_READONLY);
|
||||
int version = sqlGetVersion(_indb);
|
||||
if (version != FLUX_VERSION_CURRENT)
|
||||
Error() << fmt::format("that flux file is version {}, but this client is for version {}",
|
||||
version, FLUX_VERSION_CURRENT);
|
||||
}
|
||||
|
||||
~SqliteFluxSource()
|
||||
{
|
||||
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<FluxSource> FluxSource::createSqliteFluxSource(const std::string& filename)
|
||||
{
|
||||
return std::unique_ptr<FluxSource>(new SqliteFluxSource(filename));
|
||||
}
|
||||
|
||||
|
||||
33
lib/fluxsource/streamfluxsource.cc
Normal file
33
lib/fluxsource/streamfluxsource.cc
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "globals.h"
|
||||
#include "fluxmap.h"
|
||||
#include "kryoflux.h"
|
||||
#include "fluxsource.h"
|
||||
|
||||
class StreamFluxSource : public FluxSource
|
||||
{
|
||||
public:
|
||||
StreamFluxSource(const std::string& path):
|
||||
_path(path)
|
||||
{
|
||||
}
|
||||
|
||||
~StreamFluxSource()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
std::unique_ptr<Fluxmap> readFlux(int track, int side)
|
||||
{
|
||||
return readStream(_path, track, side);
|
||||
}
|
||||
|
||||
void recalibrate() {}
|
||||
|
||||
private:
|
||||
const std::string& _path;
|
||||
};
|
||||
|
||||
std::unique_ptr<FluxSource> FluxSource::createStreamFluxSource(const std::string& path)
|
||||
{
|
||||
return std::unique_ptr<FluxSource>(new StreamFluxSource(path));
|
||||
}
|
||||
Reference in New Issue
Block a user