mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Add read support for A2R v2 files.
This commit is contained in:
@@ -19,6 +19,7 @@ LIBFLUXENGINE_SRCS = \
|
|||||||
lib/fluxsink/hardwarefluxsink.cc \
|
lib/fluxsink/hardwarefluxsink.cc \
|
||||||
lib/fluxsink/scpfluxsink.cc \
|
lib/fluxsink/scpfluxsink.cc \
|
||||||
lib/fluxsink/vcdfluxsink.cc \
|
lib/fluxsink/vcdfluxsink.cc \
|
||||||
|
lib/fluxsource/a2rfluxsource.cc \
|
||||||
lib/fluxsource/cwffluxsource.cc \
|
lib/fluxsource/cwffluxsource.cc \
|
||||||
lib/fluxsource/erasefluxsource.cc \
|
lib/fluxsource/erasefluxsource.cc \
|
||||||
lib/fluxsource/fl2fluxsource.cc \
|
lib/fluxsource/fl2fluxsource.cc \
|
||||||
|
|||||||
@@ -47,6 +47,12 @@ Bytes::Bytes(const std::string& s):
|
|||||||
_high(s.size())
|
_high(s.size())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
Bytes::Bytes(const char* s):
|
||||||
|
_data(createVector((const uint8_t*)s, strlen(s))),
|
||||||
|
_low(0),
|
||||||
|
_high(strlen(s))
|
||||||
|
{}
|
||||||
|
|
||||||
Bytes::Bytes(std::initializer_list<uint8_t> data):
|
Bytes::Bytes(std::initializer_list<uint8_t> data):
|
||||||
_data(createVector(data)),
|
_data(createVector(data)),
|
||||||
_low(0),
|
_low(0),
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ public:
|
|||||||
Bytes();
|
Bytes();
|
||||||
Bytes(unsigned size);
|
Bytes(unsigned size);
|
||||||
Bytes(const uint8_t* ptr, size_t len);
|
Bytes(const uint8_t* ptr, size_t len);
|
||||||
|
Bytes(const char* data);
|
||||||
Bytes(const std::string& data);
|
Bytes(const std::string& data);
|
||||||
Bytes(std::initializer_list<uint8_t> data);
|
Bytes(std::initializer_list<uint8_t> data);
|
||||||
Bytes(std::shared_ptr<std::vector<uint8_t>> data);
|
Bytes(std::shared_ptr<std::vector<uint8_t>> data);
|
||||||
|
|||||||
182
lib/fluxsource/a2rfluxsource.cc
Normal file
182
lib/fluxsource/a2rfluxsource.cc
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
#include "globals.h"
|
||||||
|
#include "fluxmap.h"
|
||||||
|
#include "lib/fluxsource/fluxsource.pb.h"
|
||||||
|
#include "fluxsource/fluxsource.h"
|
||||||
|
#include "proto.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
struct A2Rv2Flux
|
||||||
|
{
|
||||||
|
std::vector<Bytes> flux;
|
||||||
|
nanoseconds_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
class A2rv2FluxSourceIterator : public FluxSourceIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
A2rv2FluxSourceIterator(A2Rv2Flux& flux): _flux(flux) {}
|
||||||
|
|
||||||
|
bool hasNext() const override
|
||||||
|
{
|
||||||
|
return _count != _flux.flux.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<const Fluxmap> next() override
|
||||||
|
{
|
||||||
|
nanoseconds_t index = _flux.index;
|
||||||
|
Bytes& asbytes = _flux.flux[_count++];
|
||||||
|
ByteReader br(asbytes);
|
||||||
|
|
||||||
|
auto fluxmap = std::make_unique<Fluxmap>();
|
||||||
|
while (!br.eof())
|
||||||
|
{
|
||||||
|
unsigned aticks = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
unsigned i = br.read_8();
|
||||||
|
aticks += i;
|
||||||
|
if (i != 0xff)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nanoseconds_t interval = aticks * 125;
|
||||||
|
if ((index >= 0) && (index < interval))
|
||||||
|
{
|
||||||
|
fluxmap->appendInterval(index);
|
||||||
|
fluxmap->appendIndex();
|
||||||
|
interval -= index;
|
||||||
|
}
|
||||||
|
index -= interval;
|
||||||
|
|
||||||
|
fluxmap->appendInterval(interval / NS_PER_TICK);
|
||||||
|
fluxmap->appendPulse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return fluxmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
A2Rv2Flux& _flux;
|
||||||
|
int _count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class A2rFluxSource : public FluxSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
A2rFluxSource(const A2rFluxSourceProto& config): _config(config)
|
||||||
|
{
|
||||||
|
_data = Bytes::readFromFile(_config.filename());
|
||||||
|
ByteReader br(_data);
|
||||||
|
|
||||||
|
switch (br.read_be32())
|
||||||
|
{
|
||||||
|
case 0x41325232:
|
||||||
|
{
|
||||||
|
_version = 2;
|
||||||
|
Bytes info = findChunk("INFO");
|
||||||
|
int disktype = info[33];
|
||||||
|
if (disktype == 1)
|
||||||
|
{
|
||||||
|
/* 5.25" with quarter stepping. */
|
||||||
|
::config.set_tpi(48);
|
||||||
|
::config.mutable_drive()->set_tracks(160);
|
||||||
|
::config.mutable_drive()->set_heads(1);
|
||||||
|
::config.mutable_drive()->set_head_width(4);
|
||||||
|
::config.mutable_drive()->set_tpi(48 * 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* 3.5". 96 is wrong but that's what we use. */
|
||||||
|
::config.set_tpi(96);
|
||||||
|
::config.mutable_drive()->set_tpi(96);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bytes stream = findChunk("STRM");
|
||||||
|
ByteReader bsr(stream);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int location = bsr.read_8();
|
||||||
|
if (location == 0xff)
|
||||||
|
break;
|
||||||
|
auto key = (disktype == 1) ? std::make_pair(location, 0)
|
||||||
|
: std::make_pair(location >> 1,
|
||||||
|
location & 1);
|
||||||
|
|
||||||
|
bsr.skip(1);
|
||||||
|
uint32_t len = bsr.read_le32();
|
||||||
|
nanoseconds_t index = (nanoseconds_t)bsr.read_le32() * 125;
|
||||||
|
auto it = _v2data.find(key);
|
||||||
|
if (it == _v2data.end())
|
||||||
|
{
|
||||||
|
_v2data[key] = std::make_unique<A2Rv2Flux>();
|
||||||
|
it = _v2data.find(key);
|
||||||
|
it->second->index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
it->second->flux.push_back(bsr.read(len));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
Error() << "unsupported A2R version";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::unique_ptr<FluxSourceIterator> readFlux(int track, int head) override
|
||||||
|
{
|
||||||
|
switch (_version)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
auto i = _v2data.find(std::make_pair(track, head));
|
||||||
|
if (i != _v2data.end())
|
||||||
|
return std::make_unique<A2rv2FluxSourceIterator>(
|
||||||
|
*i->second);
|
||||||
|
else
|
||||||
|
return std::make_unique<EmptyFluxSourceIterator>();
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
Error() << "unsupported A2R version";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void recalibrate() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Bytes findChunk(Bytes id)
|
||||||
|
{
|
||||||
|
uint32_t offset = 8;
|
||||||
|
while (offset < _data.size())
|
||||||
|
{
|
||||||
|
ByteReader br(_data);
|
||||||
|
br.seek(offset);
|
||||||
|
if (br.read(4) == id)
|
||||||
|
{
|
||||||
|
uint32_t size = br.read_le32();
|
||||||
|
return br.read(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += br.read_le32() + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error() << "A2R file missing chunk";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const A2rFluxSourceProto& _config;
|
||||||
|
Bytes _data;
|
||||||
|
std::ifstream _if;
|
||||||
|
int _version;
|
||||||
|
std::map<std::pair<int, int>, std::unique_ptr<A2Rv2Flux>> _v2data;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<FluxSource> FluxSource::createA2rFluxSource(
|
||||||
|
const A2rFluxSourceProto& config)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<FluxSource>(new A2rFluxSource(config));
|
||||||
|
}
|
||||||
@@ -31,19 +31,6 @@ private:
|
|||||||
int _count = 0;
|
int _count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EmptyFluxSourceIterator : public FluxSourceIterator
|
|
||||||
{
|
|
||||||
bool hasNext() const override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<const Fluxmap> next() override
|
|
||||||
{
|
|
||||||
Error() << "no flux to read";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Fl2FluxSource : public FluxSource
|
class Fl2FluxSource : public FluxSource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ std::unique_ptr<FluxSource> FluxSource::create(const FluxSourceProto& config)
|
|||||||
case FluxSourceProto::SCP:
|
case FluxSourceProto::SCP:
|
||||||
return createScpFluxSource(config.scp());
|
return createScpFluxSource(config.scp());
|
||||||
|
|
||||||
|
case FluxSourceProto::A2R:
|
||||||
|
return createA2rFluxSource(config.a2r());
|
||||||
|
|
||||||
case FluxSourceProto::CWF:
|
case FluxSourceProto::CWF:
|
||||||
return createCwfFluxSource(config.cwf());
|
return createCwfFluxSource(config.cwf());
|
||||||
|
|
||||||
@@ -68,6 +71,12 @@ void FluxSource::updateConfigForFilename(
|
|||||||
proto->set_type(FluxSourceProto::SCP);
|
proto->set_type(FluxSourceProto::SCP);
|
||||||
proto->mutable_scp()->set_filename(s);
|
proto->mutable_scp()->set_filename(s);
|
||||||
}},
|
}},
|
||||||
|
{std::regex("^(.*\\.a2r)$"),
|
||||||
|
[](auto& s, auto* proto)
|
||||||
|
{
|
||||||
|
proto->set_type(FluxSourceProto::A2R);
|
||||||
|
proto->mutable_a2r()->set_filename(s);
|
||||||
|
}},
|
||||||
{std::regex("^(.*\\.cwf)$"),
|
{std::regex("^(.*\\.cwf)$"),
|
||||||
[](auto& s, auto* proto)
|
[](auto& s, auto* proto)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "flags.h"
|
#include "flags.h"
|
||||||
|
|
||||||
|
class A2rFluxSourceProto;
|
||||||
class CwfFluxSourceProto;
|
class CwfFluxSourceProto;
|
||||||
class DiskFlux;
|
class DiskFlux;
|
||||||
class EraseFluxSourceProto;
|
class EraseFluxSourceProto;
|
||||||
@@ -31,6 +32,8 @@ public:
|
|||||||
virtual ~FluxSource() {}
|
virtual ~FluxSource() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static std::unique_ptr<FluxSource> createA2rFluxSource(
|
||||||
|
const A2rFluxSourceProto& config);
|
||||||
static std::unique_ptr<FluxSource> createCwfFluxSource(
|
static std::unique_ptr<FluxSource> createCwfFluxSource(
|
||||||
const CwfFluxSourceProto& config);
|
const CwfFluxSourceProto& config);
|
||||||
static std::unique_ptr<FluxSource> createEraseFluxSource(
|
static std::unique_ptr<FluxSource> createEraseFluxSource(
|
||||||
@@ -67,6 +70,19 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EmptyFluxSourceIterator : public FluxSourceIterator
|
||||||
|
{
|
||||||
|
bool hasNext() const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<const Fluxmap> next() override
|
||||||
|
{
|
||||||
|
Error() << "no flux to read";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class TrivialFluxSource : public FluxSource
|
class TrivialFluxSource : public FluxSource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ message ScpFluxSourceProto {
|
|||||||
(help) = ".scp file to read flux from"];
|
(help) = ".scp file to read flux from"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message A2rFluxSourceProto {
|
||||||
|
optional string filename = 1 [default = "flux.a2r",
|
||||||
|
(help) = ".a2r file to read flux from"];
|
||||||
|
}
|
||||||
|
|
||||||
message CwfFluxSourceProto {
|
message CwfFluxSourceProto {
|
||||||
optional string filename = 1 [default = "flux.cwf",
|
optional string filename = 1 [default = "flux.cwf",
|
||||||
(help) = ".cwf file to read flux from"];
|
(help) = ".cwf file to read flux from"];
|
||||||
@@ -34,7 +39,7 @@ message FlxFluxSourceProto {
|
|||||||
optional string directory = 1 [(help) = "path to FLX stream directory"];
|
optional string directory = 1 [(help) = "path to FLX stream directory"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEXT: 11
|
// NEXT: 12
|
||||||
message FluxSourceProto {
|
message FluxSourceProto {
|
||||||
enum FluxSourceType {
|
enum FluxSourceType {
|
||||||
NOT_SET = 0;
|
NOT_SET = 0;
|
||||||
@@ -46,17 +51,19 @@ message FluxSourceProto {
|
|||||||
CWF = 6;
|
CWF = 6;
|
||||||
FLUX = 7;
|
FLUX = 7;
|
||||||
FLX = 8;
|
FLX = 8;
|
||||||
|
A2R = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional FluxSourceType type = 9 [default = NOT_SET, (help) = "flux source type"];
|
optional FluxSourceType type = 9 [default = NOT_SET, (help) = "flux source type"];
|
||||||
|
|
||||||
optional HardwareFluxSourceProto drive = 2;
|
optional A2rFluxSourceProto a2r = 11;
|
||||||
optional TestPatternFluxSourceProto test_pattern = 3;
|
|
||||||
optional EraseFluxSourceProto erase = 4;
|
|
||||||
optional KryofluxFluxSourceProto kryoflux = 5;
|
|
||||||
optional ScpFluxSourceProto scp = 6;
|
|
||||||
optional CwfFluxSourceProto cwf = 7;
|
optional CwfFluxSourceProto cwf = 7;
|
||||||
|
optional EraseFluxSourceProto erase = 4;
|
||||||
optional Fl2FluxSourceProto fl2 = 8;
|
optional Fl2FluxSourceProto fl2 = 8;
|
||||||
optional FlxFluxSourceProto flx = 10;
|
optional FlxFluxSourceProto flx = 10;
|
||||||
|
optional HardwareFluxSourceProto drive = 2;
|
||||||
|
optional KryofluxFluxSourceProto kryoflux = 5;
|
||||||
|
optional ScpFluxSourceProto scp = 6;
|
||||||
|
optional TestPatternFluxSourceProto test_pattern = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,20 +31,6 @@ private:
|
|||||||
int _count = 0;
|
int _count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EmptyFluxSourceIterator : public FluxSourceIterator
|
|
||||||
{
|
|
||||||
bool hasNext() const override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<const Fluxmap> next() override
|
|
||||||
{
|
|
||||||
Error() << "no flux to read";
|
|
||||||
throw nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MemoryFluxSource : public FluxSource
|
class MemoryFluxSource : public FluxSource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -42,7 +42,9 @@ public:
|
|||||||
(_header.file_id[2] != 'P'))
|
(_header.file_id[2] != 'P'))
|
||||||
Error() << "input not a SCP file";
|
Error() << "input not a SCP file";
|
||||||
|
|
||||||
::config.set_tpi((_header.flags & SCP_FLAG_96TPI) ? 96 : 48);
|
int tpi = (_header.flags & SCP_FLAG_96TPI) ? 96 : 48;
|
||||||
|
::config.set_tpi(tpi);
|
||||||
|
::config.mutable_drive()->set_tpi(tpi);
|
||||||
|
|
||||||
_resolution = 25 * (_header.resolution + 1);
|
_resolution = 25 * (_header.resolution + 1);
|
||||||
int startSide = (_header.heads == 2) ? 1 : 0;
|
int startSide = (_header.heads == 2) ? 1 : 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user