Flux sources now add the locations of their data to _extraConfig ---

which is now honoured. Fix a bunch of bugs in some of the flux sources
and sinks. The converter now actually works, maybe.
This commit is contained in:
David Given
2025-08-17 00:38:25 +02:00
parent 4ebda29171
commit f24e4029b4
25 changed files with 225 additions and 98 deletions

View File

@@ -3,7 +3,7 @@ syntax = "proto2";
import "lib/config/common.proto";
import "lib/external/fl2.proto";
// Next: 15
// Next: 14
message DriveProto
{
optional int32 drive = 1
@@ -22,20 +22,18 @@ message DriveProto
optional double revolutions = 7
[ default = 1.2, (help) = "number of revolutions to read" ];
optional int32 tracks = 8
[ default = 81, (help) = "Number of tracks supported by drive" ];
optional int32 heads = 9
[ default = 2, (help) = "Number of heads supported by drive" ];
optional int32 head_bias = 10 [
optional string tracks = 8
[ default = "c0-80h0-1", (help) = "Tracks supported by drive" ];
optional int32 head_bias = 9 [
default = 0,
(help) = "Bias to apply to the head position (in tracks)"
];
optional int32 group_offset = 11 [
optional int32 group_offset = 10 [
default = 0,
(help) = "When writing groups, erase all tracks except this one in each group"
];
optional DriveType drive_type = 12 [ default = DRIVETYPE_UNKNOWN, (help) = "Type of drive" ];
optional double rotational_period_ms = 13
optional DriveType drive_type = 11 [ default = DRIVETYPE_UNKNOWN, (help) = "Type of drive" ];
optional double rotational_period_ms = 12
[ default = 0, (help) = "Rotational period of the drive in milliseconds (0 to autodetect)"];
enum ErrorBehaviour {
@@ -44,7 +42,7 @@ message DriveProto
RECALIBRATE = 2;
}
optional ErrorBehaviour error_behaviour = 14
optional ErrorBehaviour error_behaviour = 13
[ default = JIGGLE, (help) = "what to do when an error occurs during reads" ];
}

View File

@@ -16,6 +16,7 @@
#include <variant>
#include <optional>
#include <regex>
#include <ranges>
#include "fmt/format.h"
#if defined(_WIN32) || defined(__WIN32__)

View File

@@ -9,6 +9,7 @@
#include <lexy/action/parse.hpp>
#include <lexy_ext/report_error.hpp>
#include "fmt/ranges.h"
#include <ranges>
namespace
{
@@ -142,5 +143,20 @@ std::vector<CylinderHead> parseCylinderHeadsString(const std::string& s)
error(fmt::format("track descriptor parse error: {}",
fmt::join(result.errors(), "; ")));
}
return result.value();
}
std::vector<CylinderHead> results = result.value();
std::sort(results.begin(), results.end());
return results;
}
std::string convertCylinderHeadsToString(const std::vector<CylinderHead>& chs)
{
return fmt::format("{}",
fmt::join(chs | std::views::transform(
[](const auto& ch)
{
return fmt::format(
"c{}h{}", ch.cylinder, ch.head);
}),
" "));
}

View File

@@ -3,8 +3,11 @@
struct CylinderHead
{
bool operator==(const CylinderHead&) const = default;
std::strong_ordering operator<=>(const CylinderHead&) const = default;
unsigned cylinder, head;
};
extern std::vector<CylinderHead> parseCylinderHeadsString(const std::string& s);
extern std::string convertCylinderHeadsToString(
const std::vector<CylinderHead>& chs);

View File

@@ -1,5 +1,6 @@
#include "lib/core/globals.h"
#include "lib/config/flags.h"
#include "lib/config/config.h"
#include "lib/data/fluxmap.h"
#include "lib/core/bytes.h"
#include "protocol.h"
@@ -31,8 +32,6 @@ namespace
_bytes{},
_writer{_bytes.writer()}
{
log("A2R: collecting data");
time_t now{std::time(nullptr)};
auto t = gmtime(&now);
_metadata["image_date"] = fmt::format("{:%FT%TZ}", *t);
@@ -88,7 +87,12 @@ namespace
auto version_str_padded = fmt::format("{: <32}", "FluxEngine");
assert(version_str_padded.size() == 32);
writer.append(version_str_padded);
writer.write_8(A2R_DISK_35);
writer.write_8(
(globalConfig()->drive().drive_type() == DRIVETYPE_APPLE2)
? A2R_DISK_525
: A2R_DISK_35);
writer.write_8(1); // write protected
writer.write_8(1); // synchronized
writeChunkAndData(A2R_CHUNK_INFO, info);
@@ -203,7 +207,11 @@ namespace
uint32_t chunk_size = 10 + trackBytes.size();
_strmWriter.write_8((cylinder << 1) | head);
if (globalConfig()->drive().drive_type() == DRIVETYPE_APPLE2)
_strmWriter.write_8(cylinder);
else
_strmWriter.write_8((cylinder << 1) | head);
_strmWriter.write_8(A2R_TIMING);
_strmWriter.write_le32(trackBytes.size());
_strmWriter.write_le32(ticks_to_a2r(loopPoint));

View File

@@ -10,6 +10,7 @@
#include "lib/config/proto.h"
#include "lib/external/fl2.pb.h"
#include "lib/external/fl2.h"
#include "lib/core/logger.h"
#include <fstream>
#include <sys/stat.h>
#include <sys/types.h>
@@ -34,6 +35,8 @@ public:
~Fl2FluxSink()
{
log("FL2: writing {}", _filename);
FluxFileProto proto;
for (const auto& e : _data)
{

View File

@@ -2,6 +2,7 @@
#define FLUXSINK_H
#include "lib/config/flags.h"
#include "lib/data/locations.h"
#include <ostream>
class Fluxmap;
@@ -42,6 +43,10 @@ public:
/* Writes a fluxmap to a track and side. */
virtual void writeFlux(int track, int side, const Fluxmap& fluxmap) = 0;
void writeFlux(const CylinderHead& location, const Fluxmap& fluxmap)
{
writeFlux(location.cylinder, location.head, fluxmap);
}
/* Returns whether this is writing to real hardware or not. */

View File

@@ -173,8 +173,7 @@ public:
_fileheader.revolutions = revolution;
write_le32(
_fileheader.track[strack], trackdataWriter.pos + sizeof(ScpHeader));
trackdataWriter +=
Bytes((uint8_t*)&trackHeader, sizeof(trackHeader));
trackdataWriter += Bytes((uint8_t*)&trackHeader, sizeof(trackHeader));
trackdataWriter += fluxdata;
}

View File

@@ -1,9 +1,13 @@
#include "lib/core/globals.h"
#include "lib/data/fluxmap.h"
#include "lib/data/layout.h"
#include "lib/fluxsource/fluxsource.pb.h"
#include "lib/fluxsource/fluxsource.h"
#include "lib/config/proto.h"
#include "lib/data/locations.h"
#include "lib/core/logger.h"
#include <fstream>
#include <ranges>
struct A2Rv2Flux
{
@@ -78,8 +82,6 @@ public:
if (disktype == 1)
{
/* 5.25" with quarter stepping. */
_extraConfig.mutable_drive()->set_tracks(160);
_extraConfig.mutable_drive()->set_heads(1);
_extraConfig.mutable_drive()->set_drive_type(
DRIVETYPE_APPLE2);
}
@@ -94,12 +96,12 @@ public:
ByteReader bsr(stream);
for (;;)
{
int location = bsr.read_8();
unsigned location = bsr.read_8();
if (location == 0xff)
break;
auto key = (disktype == 1) ? std::make_pair(location, 0)
: std::make_pair(location >> 1,
location & 1);
auto key = (disktype == 1)
? CylinderHead{location, 0}
: CylinderHead{location >> 1, location & 1};
bsr.skip(1);
uint32_t len = bsr.read_le32();
@@ -115,6 +117,20 @@ public:
it->second->flux.push_back(bsr.read(len));
}
auto keys = std::views::keys(_v2data);
std::vector<CylinderHead> chs{keys.begin(), keys.end()};
auto [minCylinder, maxCylinder, minHead, maxHead] =
Layout::getBounds(chs);
log("A2R: reading A2R {} file with {} cylinders and {} head{}",
(disktype == 1) ? "Apple II"
: (disktype == 2) ? "normal"
: "unknown",
maxCylinder - minCylinder + 1,
maxHead - minHead + 1,
(maxHead == minHead) ? "" : "s");
_extraConfig.mutable_drive()->set_tracks(
convertCylinderHeadsToString(chs));
break;
}
@@ -130,7 +146,8 @@ public:
{
case 2:
{
auto i = _v2data.find(std::make_pair(track, head));
auto i =
_v2data.find(CylinderHead{(unsigned)track, (unsigned)head});
if (i != _v2data.end())
return std::make_unique<A2rv2FluxSourceIterator>(
*i->second);
@@ -170,7 +187,7 @@ private:
Bytes _data;
std::ifstream _if;
int _version;
std::map<std::pair<int, int>, std::unique_ptr<A2Rv2Flux>> _v2data;
std::map<CylinderHead, std::unique_ptr<A2Rv2Flux>> _v2data;
};
std::unique_ptr<FluxSource> FluxSource::createA2rFluxSource(

View File

@@ -1,10 +1,12 @@
#include "lib/core/globals.h"
#include "lib/data/fluxmap.h"
#include "lib/data/locations.h"
#include "lib/fluxsource/fluxsource.pb.h"
#include "lib/fluxsource/fluxsource.h"
#include "lib/external/catweasel.h"
#include "lib/config/proto.h"
#include <fstream>
#include <ranges>
struct CwfHeader
{
@@ -14,8 +16,8 @@ struct CwfHeader
uint8_t version; // version of this file
uint8_t clock_rate; // clock rate used: 0, 1, 2 (2 = 28MHz)
uint8_t drive_type; // type of drive
uint8_t tracks; // number of tracks
uint8_t sides; // number of sides
uint8_t cylinders; // number of cylinders
uint8_t heads; // number of heads
uint8_t index_mark; // nonzero if index marks are included
uint8_t step; // track stepping interval
uint8_t filler[15]; // reserved for expansion
@@ -24,8 +26,8 @@ struct CwfHeader
struct CwfTrack
{
uint8_t track; // sequential
uint8_t side;
uint8_t cylinder; // sequential
uint8_t head;
uint8_t unused[2];
uint8_t length[4]; // little-endian
};
@@ -60,16 +62,16 @@ public:
error("unsupported clock rate");
}
std::cout << fmt::format("CWF {}x{} = {} tracks, {} sides\n",
_header.tracks,
_header.step,
_header.tracks * _header.step,
_header.sides);
std::cout << fmt::format("CWF {}x{} = {} cylinders, {} heads\n",
_header.cylinders,
_header.heads,
_header.cylinders * _header.step,
_header.heads);
std::cout << fmt::format(
"CWF sample clock rate: {} MHz\n", 1e3 / _clockPeriod);
int tracks = _header.tracks * _header.sides;
for (int i = 0; i < tracks; i++)
int cylinders = _header.cylinders * _header.heads;
for (int i = 0; i < cylinders; i++)
{
CwfTrack trackHeader;
_if.read((char*)&trackHeader, sizeof(trackHeader));
@@ -78,19 +80,26 @@ public:
uint32_t length =
Bytes(trackHeader.length, 4).reader().read_le32() -
sizeof(CwfTrack);
unsigned track_number = trackHeader.track * _header.step;
unsigned track_number = trackHeader.cylinder * _header.step;
off_t pos = _if.tellg();
_trackOffsets[std::make_pair(track_number, trackHeader.side)] =
_trackOffsets[CylinderHead{track_number, trackHeader.head}] =
std::make_pair(pos, length);
_if.seekg(pos + length);
}
std::vector<CylinderHead> chs;
for (auto& [key, value] : _trackOffsets)
chs.push_back(key);
_extraConfig.mutable_drive()->set_tracks(
convertCylinderHeadsToString(chs));
}
public:
std::unique_ptr<const Fluxmap> readSingleFlux(int track, int side) override
{
const auto& p = _trackOffsets.find(std::make_pair(track, side));
const auto& p =
_trackOffsets.find(CylinderHead{(unsigned)track, (unsigned)side});
if (p == _trackOffsets.end())
return std::make_unique<const Fluxmap>();
@@ -117,7 +126,7 @@ private:
std::ifstream _if;
CwfHeader _header;
nanoseconds_t _clockPeriod;
std::map<std::pair<int, int>, std::pair<off_t, size_t>> _trackOffsets;
std::map<CylinderHead, std::pair<off_t, size_t>> _trackOffsets;
};
std::unique_ptr<FluxSource> FluxSource::createCwfFluxSource(

View File

@@ -1,5 +1,6 @@
#include "lib/core/globals.h"
#include "lib/data/fluxmap.h"
#include "lib/data/locations.h"
#include "lib/fluxsource/fluxsource.pb.h"
#include "lib/fluxsource/fluxsource.h"
#include "lib/external/catweasel.h"
@@ -56,6 +57,20 @@ class DmkFluxSource : public FluxSource
public:
DmkFluxSource(const DmkFluxSourceProto& config): _path(config.directory())
{
std::vector<CylinderHead> chs;
for (const auto& di : std::filesystem::directory_iterator(_path))
{
static const std::regex FILENAME_REGEX(
"C_S([0-9]+)T([0-9]+)\\.[0-9]+");
std::string filename = di.path().filename();
std::smatch dmatch;
if (std::regex_match(filename, dmatch, FILENAME_REGEX))
chs.push_back(CylinderHead{(unsigned)std::stoi(dmatch[2]),
(unsigned)std::stoi(dmatch[1])});
}
_extraConfig.mutable_drive()->set_tracks(
convertCylinderHeadsToString(chs));
}
public:

View File

@@ -6,7 +6,11 @@
class EraseFluxSource : public TrivialFluxSource
{
public:
EraseFluxSource(const EraseFluxSourceProto& config) {}
EraseFluxSource(const EraseFluxSourceProto& config)
{
_extraConfig.mutable_drive()->set_tracks("c0-255h0-1");
}
~EraseFluxSource() {}
public:

View File

@@ -1,11 +1,13 @@
#include "lib/core/globals.h"
#include "lib/data/fluxmap.h"
#include "lib/data/locations.h"
#include "lib/fluxsource/fluxsource.pb.h"
#include "lib/external/fl2.pb.h"
#include "lib/fluxsource/fluxsource.h"
#include "lib/config/proto.h"
#include "lib/external/fl2.h"
#include "lib/data/fluxmap.h"
#include "lib/core/logger.h"
#include <fstream>
class Fl2FluxSourceIterator : public FluxSourceIterator
@@ -35,12 +37,20 @@ class Fl2FluxSource : public FluxSource
public:
Fl2FluxSource(const Fl2FluxSourceProto& config): _config(config)
{
log("FL2: reading {}", _config.filename());
_proto = loadFl2File(_config.filename());
_extraConfig.mutable_drive()->set_rotational_period_ms(
_proto.rotational_period_ms());
if (_proto.has_drive_type())
_extraConfig.mutable_drive()->set_drive_type(_proto.drive_type());
std::vector<CylinderHead> chs;
for (const auto& trackFlux : _proto.track())
chs.push_back(CylinderHead{
(unsigned)trackFlux.track(), (unsigned)trackFlux.head()});
_extraConfig.mutable_drive()->set_tracks(
convertCylinderHeadsToString(chs));
}
public:

View File

@@ -11,7 +11,9 @@ std::unique_ptr<FluxSource> FluxSource::create(Config& config)
{
if (!config.hasFluxSource())
error("no flux source configured");
return create(config->flux_source());
auto fluxSource = create(config->flux_source());
globalConfig().base()->MergeFrom(fluxSource->getExtraConfig());
return fluxSource;
}
std::unique_ptr<FluxSource> FluxSource::create(const FluxSourceProto& config)

View File

@@ -2,6 +2,7 @@
#define FLUXSOURCE_H
#include "lib/config/flags.h"
#include "lib/data/locations.h"
#include "lib/config/config.pb.h"
class A2rFluxSourceProto;
@@ -71,19 +72,23 @@ public:
return _extraConfig;
}
/* Read flux from a given track and side. */
/* Read flux from a given cylinder and head. */
virtual std::unique_ptr<FluxSourceIterator> readFlux(
int track, int side) = 0;
int cylinder, int head) = 0;
std::unique_ptr<FluxSourceIterator> readFlux(const CylinderHead& location)
{
return readFlux(location.cylinder, location.head);
}
/* Recalibrates; seeks to track 0 and ensures the head is in the right
/* Recalibrates; seeks to cylinder 0 and ensures the head is in the right
* place. */
virtual void recalibrate() {}
/* Seeks to a given track (without recalibrating). */
/* Seeks to a given cylinder (without recalibrating). */
virtual void seek(int track) {}
virtual void seek(int cylinder) {}
/* Is this real hardware? If so, then flux can be read indefinitely (among
* other things). */
@@ -113,9 +118,10 @@ class EmptyFluxSourceIterator : public FluxSourceIterator
class TrivialFluxSource : public FluxSource
{
public:
std::unique_ptr<FluxSourceIterator> readFlux(int track, int side) override;
std::unique_ptr<FluxSourceIterator> readFlux(
int cylinder, int head) override;
virtual std::unique_ptr<const Fluxmap> readSingleFlux(
int track, int side) = 0;
int cylinder, int head) = 0;
};
#endif

View File

@@ -1,14 +1,31 @@
#include "lib/core/globals.h"
#include "lib/data/fluxmap.h"
#include "lib/data/locations.h"
#include "lib/fluxsource/fluxsource.pb.h"
#include "lib/fluxsource/fluxsource.h"
#include "lib/external/flx.h"
#include "lib/core/logger.h"
#include <filesystem>
class FlxFluxSource : public TrivialFluxSource
{
public:
FlxFluxSource(const FlxFluxSourceProto& config): _path(config.directory())
{
std::vector<CylinderHead> chs;
for (const auto& di : std::filesystem::directory_iterator(_path))
{
static const std::regex FILENAME_REGEX(
"@TR([0-9]+)S([0-9]+)@\\.FLX");
std::string filename = di.path().filename();
std::smatch dmatch;
if (std::regex_match(filename, dmatch, FILENAME_REGEX))
chs.push_back(CylinderHead{(unsigned)std::stoi(dmatch[1]),
(unsigned)std::stoi(dmatch[2]) - 1});
}
_extraConfig.mutable_drive()->set_tracks(
convertCylinderHeadsToString(chs));
}
public:
@@ -16,6 +33,7 @@ public:
{
std::string path =
fmt::format("{}/@TR{:02}S{}@.FLX", _path, track, side + 1);
log("FLX: reading {}", path);
return readFlxBytes(Bytes::readFromFile(path));
}

View File

@@ -1,8 +1,10 @@
#include "lib/core/globals.h"
#include "lib/data/fluxmap.h"
#include "lib/data/locations.h"
#include "lib/external/kryoflux.h"
#include "lib/fluxsource/fluxsource.pb.h"
#include "lib/fluxsource/fluxsource.h"
#include <filesystem>
class KryofluxFluxSource : public TrivialFluxSource
{
@@ -10,6 +12,19 @@ public:
KryofluxFluxSource(const KryofluxFluxSourceProto& config):
_path(config.directory())
{
std::vector<CylinderHead> chs;
for (const auto& di : std::filesystem::directory_iterator(_path))
{
static const std::regex FILENAME_REGEX("([0-9]+)\\.([0-9]+)\\.raw");
std::string filename = di.path().filename();
std::smatch dmatch;
if (std::regex_match(filename, dmatch, FILENAME_REGEX))
chs.push_back(CylinderHead{(unsigned)std::stoi(dmatch[1]),
(unsigned)std::stoi(dmatch[2])});
}
_extraConfig.mutable_drive()->set_tracks(
convertCylinderHeadsToString(chs));
}
public:

View File

@@ -31,7 +31,16 @@ private:
class MemoryFluxSource : public FluxSource
{
public:
MemoryFluxSource(const DiskFlux& flux): _flux(flux) {}
MemoryFluxSource(const DiskFlux& flux): _flux(flux)
{
std::vector<CylinderHead> chs;
for (const auto& trackFlux : flux.tracks)
chs.push_back(
CylinderHead{(unsigned)trackFlux->trackInfo->physicalTrack,
(unsigned)trackFlux->trackInfo->logicalTrack});
_extraConfig.mutable_drive()->set_tracks(
convertCylinderHeadsToString(chs));
}
public:
std::unique_ptr<FluxSourceIterator> readFlux(

View File

@@ -1,5 +1,6 @@
#include "lib/core/globals.h"
#include "lib/data/fluxmap.h"
#include "lib/data/locations.h"
#include "lib/external/kryoflux.h"
#include "lib/fluxsource/fluxsource.pb.h"
#include "lib/core/utils.h"
@@ -53,6 +54,15 @@ public:
if ((_header.cell_width != 0) && (_header.cell_width != 16))
error("currently only 16-bit cells in SCP files are supported");
std::vector<CylinderHead> chs;
for (unsigned cylinder = trackno(_header.start_track);
cylinder <= trackno(_header.end_track);
cylinder++)
for (unsigned head = startSide; head <= endSide; head++)
chs.push_back(CylinderHead{cylinder, head});
_extraConfig.mutable_drive()->set_tracks(
convertCylinderHeadsToString(chs));
log("SCP tracks {}-{}, heads {}-{}",
trackno(_header.start_track),
trackno(_header.end_track),

View File

@@ -9,6 +9,7 @@ public:
TestPatternFluxSource(const TestPatternFluxSourceProto& config):
_config(config)
{
_extraConfig.mutable_drive()->set_tracks("c0-255h0-1");
}
~TestPatternFluxSource() {}

View File

@@ -76,10 +76,9 @@ public:
trackHeaderWriter.write_le16(actualSectors);
trackHeaderWriter.write_8(dataRate);
trackHeaderWriter.write_8(recordingMode);
trackHeaderWriter.write_8(0); /* format gap length */
trackHeaderWriter.write_8(0); /* filler byte */
trackHeaderWriter.write_le16(
0); /* approximate track length */
trackHeaderWriter.write_8(0); /* format gap length */
trackHeaderWriter.write_8(0); /* filler byte */
trackHeaderWriter.write_le16(0); /* approximate track length */
for (int sectorId = 0; sectorId < geometry.numSectors;
sectorId++)
@@ -100,7 +99,7 @@ public:
trackHeaderWriter.write_8(
(sector->status == Sector::OK)
? 0x00
: 0x20); /* 8272 status 1 */
: 0x20); /* 8272 status 1 */
trackHeaderWriter.write_8(0); /* 8272 status 2 */
trackHeaderWriter.write_8(1); /* number of copies */
trackHeaderWriter.write_8(0); /* filler byte */
@@ -114,8 +113,7 @@ public:
uint32_t trackLabel = (('T') << 24) | ((track & 0xff) << 16) |
((track >> 8) << 8) | side;
uint32_t trackHeaderAddress =
ldbs.put(trackHeader, trackLabel);
uint32_t trackHeaderAddress = ldbs.put(trackHeader, trackLabel);
trackDirectoryWriter.write_be32(trackLabel);
trackDirectoryWriter.write_le32(trackHeaderAddress);
trackDirectorySize++;

View File

@@ -28,44 +28,26 @@ int mainConvert(int argc, const char* argv[])
globalConfig().setFluxSink(filenames[1]);
auto fluxSource = FluxSource::create(globalConfig());
auto locations = globalConfig()->drive().tracks();
globalConfig().overrides()->set_tracks(locations);
#if 0
std::vector<std::shared_ptr<const TrackInfo>> locations;
std::map<std::shared_ptr<const TrackInfo>,
std::vector<std::shared_ptr<const Fluxmap>>>
data;
for (int track = 0; track < 255; track++)
for (int side = 0; side < 2; side++)
{
auto ti = std::make_shared<TrackInfo>();
ti->physicalTrack = track;
ti->physicalSide = side;
auto fsi = fluxSource->readFlux(track, side);
std::vector<std::shared_ptr<const Fluxmap>> fluxes;
while (fsi->hasNext())
fluxes.push_back(fsi->next());
if (!fluxes.empty())
{
data[ti] = fluxes;
locations.push_back(ti);
}
}
auto [minTrack, maxTrack, minSide, maxSide] = Layout::getBounds(locations);
log("CONVERT: seen tracks {}..{}, sides {}..{}",
minTrack,
maxTrack,
minSide,
maxSide);
globalConfig().set("tracks", fmt::format("{}-{}", minTrack, maxTrack));
globalConfig().set("heads", fmt::format("{}-{}", minSide, maxSide));
auto physicalLocations = Layout::computePhysicalLocations();
auto [minCylinder, maxCylinder, minHead, maxHead] =
Layout::getBounds(physicalLocations);
log("CONVERT: seen cylinders {}..{}, heads {}..{}",
minCylinder,
maxCylinder,
minHead,
maxHead);
auto fluxSink = FluxSink::create(globalConfig());
#endif
for (const auto& physicalLocation : physicalLocations)
{
auto fi = fluxSource->readFlux(physicalLocation);
while (fi->hasNext())
fluxSink->writeFlux(physicalLocation, *fi->next());
}
return 0;
}

View File

@@ -15,7 +15,7 @@ fluxengine read ibm --180 40track_drive
>>>
drive {
tracks: 40
tracks: "c0-40h0-1"
drive_type: DRIVETYPE_40TRACK
}

View File

@@ -22,8 +22,7 @@ usb {
}
drive {
tracks: 160
heads: 1
tracks: "c0-159h0"
drive_type: DRIVETYPE_APPLE2
}

View File

@@ -7,8 +7,7 @@ usb {
}
drive {
tracks: 160
heads: 1
tracks: "c0-159h0"
drive_type: DRIVETYPE_APPLE2
}