mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-24 11:11:02 -07:00
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:
@@ -3,7 +3,7 @@ syntax = "proto2";
|
|||||||
import "lib/config/common.proto";
|
import "lib/config/common.proto";
|
||||||
import "lib/external/fl2.proto";
|
import "lib/external/fl2.proto";
|
||||||
|
|
||||||
// Next: 15
|
// Next: 14
|
||||||
message DriveProto
|
message DriveProto
|
||||||
{
|
{
|
||||||
optional int32 drive = 1
|
optional int32 drive = 1
|
||||||
@@ -22,20 +22,18 @@ message DriveProto
|
|||||||
optional double revolutions = 7
|
optional double revolutions = 7
|
||||||
[ default = 1.2, (help) = "number of revolutions to read" ];
|
[ default = 1.2, (help) = "number of revolutions to read" ];
|
||||||
|
|
||||||
optional int32 tracks = 8
|
optional string tracks = 8
|
||||||
[ default = 81, (help) = "Number of tracks supported by drive" ];
|
[ default = "c0-80h0-1", (help) = "Tracks supported by drive" ];
|
||||||
optional int32 heads = 9
|
optional int32 head_bias = 9 [
|
||||||
[ default = 2, (help) = "Number of heads supported by drive" ];
|
|
||||||
optional int32 head_bias = 10 [
|
|
||||||
default = 0,
|
default = 0,
|
||||||
(help) = "Bias to apply to the head position (in tracks)"
|
(help) = "Bias to apply to the head position (in tracks)"
|
||||||
];
|
];
|
||||||
optional int32 group_offset = 11 [
|
optional int32 group_offset = 10 [
|
||||||
default = 0,
|
default = 0,
|
||||||
(help) = "When writing groups, erase all tracks except this one in each group"
|
(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 DriveType drive_type = 11 [ default = DRIVETYPE_UNKNOWN, (help) = "Type of drive" ];
|
||||||
optional double rotational_period_ms = 13
|
optional double rotational_period_ms = 12
|
||||||
[ default = 0, (help) = "Rotational period of the drive in milliseconds (0 to autodetect)"];
|
[ default = 0, (help) = "Rotational period of the drive in milliseconds (0 to autodetect)"];
|
||||||
|
|
||||||
enum ErrorBehaviour {
|
enum ErrorBehaviour {
|
||||||
@@ -44,7 +42,7 @@ message DriveProto
|
|||||||
RECALIBRATE = 2;
|
RECALIBRATE = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional ErrorBehaviour error_behaviour = 14
|
optional ErrorBehaviour error_behaviour = 13
|
||||||
[ default = JIGGLE, (help) = "what to do when an error occurs during reads" ];
|
[ default = JIGGLE, (help) = "what to do when an error occurs during reads" ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <variant>
|
#include <variant>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <ranges>
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__WIN32__)
|
#if defined(_WIN32) || defined(__WIN32__)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <lexy/action/parse.hpp>
|
#include <lexy/action/parse.hpp>
|
||||||
#include <lexy_ext/report_error.hpp>
|
#include <lexy_ext/report_error.hpp>
|
||||||
#include "fmt/ranges.h"
|
#include "fmt/ranges.h"
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -142,5 +143,20 @@ std::vector<CylinderHead> parseCylinderHeadsString(const std::string& s)
|
|||||||
error(fmt::format("track descriptor parse error: {}",
|
error(fmt::format("track descriptor parse error: {}",
|
||||||
fmt::join(result.errors(), "; ")));
|
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);
|
||||||
|
}),
|
||||||
|
" "));
|
||||||
}
|
}
|
||||||
@@ -3,8 +3,11 @@
|
|||||||
struct CylinderHead
|
struct CylinderHead
|
||||||
{
|
{
|
||||||
bool operator==(const CylinderHead&) const = default;
|
bool operator==(const CylinderHead&) const = default;
|
||||||
|
std::strong_ordering operator<=>(const CylinderHead&) const = default;
|
||||||
|
|
||||||
unsigned cylinder, head;
|
unsigned cylinder, head;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::vector<CylinderHead> parseCylinderHeadsString(const std::string& s);
|
extern std::vector<CylinderHead> parseCylinderHeadsString(const std::string& s);
|
||||||
|
extern std::string convertCylinderHeadsToString(
|
||||||
|
const std::vector<CylinderHead>& chs);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "lib/core/globals.h"
|
#include "lib/core/globals.h"
|
||||||
#include "lib/config/flags.h"
|
#include "lib/config/flags.h"
|
||||||
|
#include "lib/config/config.h"
|
||||||
#include "lib/data/fluxmap.h"
|
#include "lib/data/fluxmap.h"
|
||||||
#include "lib/core/bytes.h"
|
#include "lib/core/bytes.h"
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
@@ -31,8 +32,6 @@ namespace
|
|||||||
_bytes{},
|
_bytes{},
|
||||||
_writer{_bytes.writer()}
|
_writer{_bytes.writer()}
|
||||||
{
|
{
|
||||||
log("A2R: collecting data");
|
|
||||||
|
|
||||||
time_t now{std::time(nullptr)};
|
time_t now{std::time(nullptr)};
|
||||||
auto t = gmtime(&now);
|
auto t = gmtime(&now);
|
||||||
_metadata["image_date"] = fmt::format("{:%FT%TZ}", *t);
|
_metadata["image_date"] = fmt::format("{:%FT%TZ}", *t);
|
||||||
@@ -88,7 +87,12 @@ namespace
|
|||||||
auto version_str_padded = fmt::format("{: <32}", "FluxEngine");
|
auto version_str_padded = fmt::format("{: <32}", "FluxEngine");
|
||||||
assert(version_str_padded.size() == 32);
|
assert(version_str_padded.size() == 32);
|
||||||
writer.append(version_str_padded);
|
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); // write protected
|
||||||
writer.write_8(1); // synchronized
|
writer.write_8(1); // synchronized
|
||||||
writeChunkAndData(A2R_CHUNK_INFO, info);
|
writeChunkAndData(A2R_CHUNK_INFO, info);
|
||||||
@@ -203,7 +207,11 @@ namespace
|
|||||||
|
|
||||||
uint32_t chunk_size = 10 + trackBytes.size();
|
uint32_t chunk_size = 10 + trackBytes.size();
|
||||||
|
|
||||||
|
if (globalConfig()->drive().drive_type() == DRIVETYPE_APPLE2)
|
||||||
|
_strmWriter.write_8(cylinder);
|
||||||
|
else
|
||||||
_strmWriter.write_8((cylinder << 1) | head);
|
_strmWriter.write_8((cylinder << 1) | head);
|
||||||
|
|
||||||
_strmWriter.write_8(A2R_TIMING);
|
_strmWriter.write_8(A2R_TIMING);
|
||||||
_strmWriter.write_le32(trackBytes.size());
|
_strmWriter.write_le32(trackBytes.size());
|
||||||
_strmWriter.write_le32(ticks_to_a2r(loopPoint));
|
_strmWriter.write_le32(ticks_to_a2r(loopPoint));
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "lib/config/proto.h"
|
#include "lib/config/proto.h"
|
||||||
#include "lib/external/fl2.pb.h"
|
#include "lib/external/fl2.pb.h"
|
||||||
#include "lib/external/fl2.h"
|
#include "lib/external/fl2.h"
|
||||||
|
#include "lib/core/logger.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@@ -34,6 +35,8 @@ public:
|
|||||||
|
|
||||||
~Fl2FluxSink()
|
~Fl2FluxSink()
|
||||||
{
|
{
|
||||||
|
log("FL2: writing {}", _filename);
|
||||||
|
|
||||||
FluxFileProto proto;
|
FluxFileProto proto;
|
||||||
for (const auto& e : _data)
|
for (const auto& e : _data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define FLUXSINK_H
|
#define FLUXSINK_H
|
||||||
|
|
||||||
#include "lib/config/flags.h"
|
#include "lib/config/flags.h"
|
||||||
|
#include "lib/data/locations.h"
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
class Fluxmap;
|
class Fluxmap;
|
||||||
@@ -42,6 +43,10 @@ public:
|
|||||||
/* Writes a fluxmap to a track and side. */
|
/* Writes a fluxmap to a track and side. */
|
||||||
|
|
||||||
virtual void writeFlux(int track, int side, const Fluxmap& fluxmap) = 0;
|
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. */
|
/* Returns whether this is writing to real hardware or not. */
|
||||||
|
|
||||||
|
|||||||
@@ -173,8 +173,7 @@ public:
|
|||||||
_fileheader.revolutions = revolution;
|
_fileheader.revolutions = revolution;
|
||||||
write_le32(
|
write_le32(
|
||||||
_fileheader.track[strack], trackdataWriter.pos + sizeof(ScpHeader));
|
_fileheader.track[strack], trackdataWriter.pos + sizeof(ScpHeader));
|
||||||
trackdataWriter +=
|
trackdataWriter += Bytes((uint8_t*)&trackHeader, sizeof(trackHeader));
|
||||||
Bytes((uint8_t*)&trackHeader, sizeof(trackHeader));
|
|
||||||
trackdataWriter += fluxdata;
|
trackdataWriter += fluxdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
#include "lib/core/globals.h"
|
#include "lib/core/globals.h"
|
||||||
#include "lib/data/fluxmap.h"
|
#include "lib/data/fluxmap.h"
|
||||||
|
#include "lib/data/layout.h"
|
||||||
#include "lib/fluxsource/fluxsource.pb.h"
|
#include "lib/fluxsource/fluxsource.pb.h"
|
||||||
#include "lib/fluxsource/fluxsource.h"
|
#include "lib/fluxsource/fluxsource.h"
|
||||||
#include "lib/config/proto.h"
|
#include "lib/config/proto.h"
|
||||||
|
#include "lib/data/locations.h"
|
||||||
|
#include "lib/core/logger.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
struct A2Rv2Flux
|
struct A2Rv2Flux
|
||||||
{
|
{
|
||||||
@@ -78,8 +82,6 @@ public:
|
|||||||
if (disktype == 1)
|
if (disktype == 1)
|
||||||
{
|
{
|
||||||
/* 5.25" with quarter stepping. */
|
/* 5.25" with quarter stepping. */
|
||||||
_extraConfig.mutable_drive()->set_tracks(160);
|
|
||||||
_extraConfig.mutable_drive()->set_heads(1);
|
|
||||||
_extraConfig.mutable_drive()->set_drive_type(
|
_extraConfig.mutable_drive()->set_drive_type(
|
||||||
DRIVETYPE_APPLE2);
|
DRIVETYPE_APPLE2);
|
||||||
}
|
}
|
||||||
@@ -94,12 +96,12 @@ public:
|
|||||||
ByteReader bsr(stream);
|
ByteReader bsr(stream);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
int location = bsr.read_8();
|
unsigned location = bsr.read_8();
|
||||||
if (location == 0xff)
|
if (location == 0xff)
|
||||||
break;
|
break;
|
||||||
auto key = (disktype == 1) ? std::make_pair(location, 0)
|
auto key = (disktype == 1)
|
||||||
: std::make_pair(location >> 1,
|
? CylinderHead{location, 0}
|
||||||
location & 1);
|
: CylinderHead{location >> 1, location & 1};
|
||||||
|
|
||||||
bsr.skip(1);
|
bsr.skip(1);
|
||||||
uint32_t len = bsr.read_le32();
|
uint32_t len = bsr.read_le32();
|
||||||
@@ -115,6 +117,20 @@ public:
|
|||||||
it->second->flux.push_back(bsr.read(len));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +146,8 @@ public:
|
|||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
auto i = _v2data.find(std::make_pair(track, head));
|
auto i =
|
||||||
|
_v2data.find(CylinderHead{(unsigned)track, (unsigned)head});
|
||||||
if (i != _v2data.end())
|
if (i != _v2data.end())
|
||||||
return std::make_unique<A2rv2FluxSourceIterator>(
|
return std::make_unique<A2rv2FluxSourceIterator>(
|
||||||
*i->second);
|
*i->second);
|
||||||
@@ -170,7 +187,7 @@ private:
|
|||||||
Bytes _data;
|
Bytes _data;
|
||||||
std::ifstream _if;
|
std::ifstream _if;
|
||||||
int _version;
|
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(
|
std::unique_ptr<FluxSource> FluxSource::createA2rFluxSource(
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
#include "lib/core/globals.h"
|
#include "lib/core/globals.h"
|
||||||
#include "lib/data/fluxmap.h"
|
#include "lib/data/fluxmap.h"
|
||||||
|
#include "lib/data/locations.h"
|
||||||
#include "lib/fluxsource/fluxsource.pb.h"
|
#include "lib/fluxsource/fluxsource.pb.h"
|
||||||
#include "lib/fluxsource/fluxsource.h"
|
#include "lib/fluxsource/fluxsource.h"
|
||||||
#include "lib/external/catweasel.h"
|
#include "lib/external/catweasel.h"
|
||||||
#include "lib/config/proto.h"
|
#include "lib/config/proto.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
struct CwfHeader
|
struct CwfHeader
|
||||||
{
|
{
|
||||||
@@ -14,8 +16,8 @@ struct CwfHeader
|
|||||||
uint8_t version; // version of this file
|
uint8_t version; // version of this file
|
||||||
uint8_t clock_rate; // clock rate used: 0, 1, 2 (2 = 28MHz)
|
uint8_t clock_rate; // clock rate used: 0, 1, 2 (2 = 28MHz)
|
||||||
uint8_t drive_type; // type of drive
|
uint8_t drive_type; // type of drive
|
||||||
uint8_t tracks; // number of tracks
|
uint8_t cylinders; // number of cylinders
|
||||||
uint8_t sides; // number of sides
|
uint8_t heads; // number of heads
|
||||||
uint8_t index_mark; // nonzero if index marks are included
|
uint8_t index_mark; // nonzero if index marks are included
|
||||||
uint8_t step; // track stepping interval
|
uint8_t step; // track stepping interval
|
||||||
uint8_t filler[15]; // reserved for expansion
|
uint8_t filler[15]; // reserved for expansion
|
||||||
@@ -24,8 +26,8 @@ struct CwfHeader
|
|||||||
|
|
||||||
struct CwfTrack
|
struct CwfTrack
|
||||||
{
|
{
|
||||||
uint8_t track; // sequential
|
uint8_t cylinder; // sequential
|
||||||
uint8_t side;
|
uint8_t head;
|
||||||
uint8_t unused[2];
|
uint8_t unused[2];
|
||||||
uint8_t length[4]; // little-endian
|
uint8_t length[4]; // little-endian
|
||||||
};
|
};
|
||||||
@@ -60,16 +62,16 @@ public:
|
|||||||
error("unsupported clock rate");
|
error("unsupported clock rate");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << fmt::format("CWF {}x{} = {} tracks, {} sides\n",
|
std::cout << fmt::format("CWF {}x{} = {} cylinders, {} heads\n",
|
||||||
_header.tracks,
|
_header.cylinders,
|
||||||
_header.step,
|
_header.heads,
|
||||||
_header.tracks * _header.step,
|
_header.cylinders * _header.step,
|
||||||
_header.sides);
|
_header.heads);
|
||||||
std::cout << fmt::format(
|
std::cout << fmt::format(
|
||||||
"CWF sample clock rate: {} MHz\n", 1e3 / _clockPeriod);
|
"CWF sample clock rate: {} MHz\n", 1e3 / _clockPeriod);
|
||||||
|
|
||||||
int tracks = _header.tracks * _header.sides;
|
int cylinders = _header.cylinders * _header.heads;
|
||||||
for (int i = 0; i < tracks; i++)
|
for (int i = 0; i < cylinders; i++)
|
||||||
{
|
{
|
||||||
CwfTrack trackHeader;
|
CwfTrack trackHeader;
|
||||||
_if.read((char*)&trackHeader, sizeof(trackHeader));
|
_if.read((char*)&trackHeader, sizeof(trackHeader));
|
||||||
@@ -78,19 +80,26 @@ public:
|
|||||||
uint32_t length =
|
uint32_t length =
|
||||||
Bytes(trackHeader.length, 4).reader().read_le32() -
|
Bytes(trackHeader.length, 4).reader().read_le32() -
|
||||||
sizeof(CwfTrack);
|
sizeof(CwfTrack);
|
||||||
unsigned track_number = trackHeader.track * _header.step;
|
unsigned track_number = trackHeader.cylinder * _header.step;
|
||||||
|
|
||||||
off_t pos = _if.tellg();
|
off_t pos = _if.tellg();
|
||||||
_trackOffsets[std::make_pair(track_number, trackHeader.side)] =
|
_trackOffsets[CylinderHead{track_number, trackHeader.head}] =
|
||||||
std::make_pair(pos, length);
|
std::make_pair(pos, length);
|
||||||
_if.seekg(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:
|
public:
|
||||||
std::unique_ptr<const Fluxmap> readSingleFlux(int track, int side) override
|
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())
|
if (p == _trackOffsets.end())
|
||||||
return std::make_unique<const Fluxmap>();
|
return std::make_unique<const Fluxmap>();
|
||||||
|
|
||||||
@@ -117,7 +126,7 @@ private:
|
|||||||
std::ifstream _if;
|
std::ifstream _if;
|
||||||
CwfHeader _header;
|
CwfHeader _header;
|
||||||
nanoseconds_t _clockPeriod;
|
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(
|
std::unique_ptr<FluxSource> FluxSource::createCwfFluxSource(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "lib/core/globals.h"
|
#include "lib/core/globals.h"
|
||||||
#include "lib/data/fluxmap.h"
|
#include "lib/data/fluxmap.h"
|
||||||
|
#include "lib/data/locations.h"
|
||||||
#include "lib/fluxsource/fluxsource.pb.h"
|
#include "lib/fluxsource/fluxsource.pb.h"
|
||||||
#include "lib/fluxsource/fluxsource.h"
|
#include "lib/fluxsource/fluxsource.h"
|
||||||
#include "lib/external/catweasel.h"
|
#include "lib/external/catweasel.h"
|
||||||
@@ -56,6 +57,20 @@ class DmkFluxSource : public FluxSource
|
|||||||
public:
|
public:
|
||||||
DmkFluxSource(const DmkFluxSourceProto& config): _path(config.directory())
|
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:
|
public:
|
||||||
|
|||||||
@@ -6,7 +6,11 @@
|
|||||||
class EraseFluxSource : public TrivialFluxSource
|
class EraseFluxSource : public TrivialFluxSource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EraseFluxSource(const EraseFluxSourceProto& config) {}
|
EraseFluxSource(const EraseFluxSourceProto& config)
|
||||||
|
{
|
||||||
|
_extraConfig.mutable_drive()->set_tracks("c0-255h0-1");
|
||||||
|
}
|
||||||
|
|
||||||
~EraseFluxSource() {}
|
~EraseFluxSource() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#include "lib/core/globals.h"
|
#include "lib/core/globals.h"
|
||||||
#include "lib/data/fluxmap.h"
|
#include "lib/data/fluxmap.h"
|
||||||
|
#include "lib/data/locations.h"
|
||||||
#include "lib/fluxsource/fluxsource.pb.h"
|
#include "lib/fluxsource/fluxsource.pb.h"
|
||||||
#include "lib/external/fl2.pb.h"
|
#include "lib/external/fl2.pb.h"
|
||||||
#include "lib/fluxsource/fluxsource.h"
|
#include "lib/fluxsource/fluxsource.h"
|
||||||
#include "lib/config/proto.h"
|
#include "lib/config/proto.h"
|
||||||
#include "lib/external/fl2.h"
|
#include "lib/external/fl2.h"
|
||||||
#include "lib/data/fluxmap.h"
|
#include "lib/data/fluxmap.h"
|
||||||
|
#include "lib/core/logger.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
class Fl2FluxSourceIterator : public FluxSourceIterator
|
class Fl2FluxSourceIterator : public FluxSourceIterator
|
||||||
@@ -35,12 +37,20 @@ class Fl2FluxSource : public FluxSource
|
|||||||
public:
|
public:
|
||||||
Fl2FluxSource(const Fl2FluxSourceProto& config): _config(config)
|
Fl2FluxSource(const Fl2FluxSourceProto& config): _config(config)
|
||||||
{
|
{
|
||||||
|
log("FL2: reading {}", _config.filename());
|
||||||
_proto = loadFl2File(_config.filename());
|
_proto = loadFl2File(_config.filename());
|
||||||
|
|
||||||
_extraConfig.mutable_drive()->set_rotational_period_ms(
|
_extraConfig.mutable_drive()->set_rotational_period_ms(
|
||||||
_proto.rotational_period_ms());
|
_proto.rotational_period_ms());
|
||||||
if (_proto.has_drive_type())
|
if (_proto.has_drive_type())
|
||||||
_extraConfig.mutable_drive()->set_drive_type(_proto.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:
|
public:
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ std::unique_ptr<FluxSource> FluxSource::create(Config& config)
|
|||||||
{
|
{
|
||||||
if (!config.hasFluxSource())
|
if (!config.hasFluxSource())
|
||||||
error("no flux source configured");
|
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)
|
std::unique_ptr<FluxSource> FluxSource::create(const FluxSourceProto& config)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define FLUXSOURCE_H
|
#define FLUXSOURCE_H
|
||||||
|
|
||||||
#include "lib/config/flags.h"
|
#include "lib/config/flags.h"
|
||||||
|
#include "lib/data/locations.h"
|
||||||
#include "lib/config/config.pb.h"
|
#include "lib/config/config.pb.h"
|
||||||
|
|
||||||
class A2rFluxSourceProto;
|
class A2rFluxSourceProto;
|
||||||
@@ -71,19 +72,23 @@ public:
|
|||||||
return _extraConfig;
|
return _extraConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read flux from a given track and side. */
|
/* Read flux from a given cylinder and head. */
|
||||||
|
|
||||||
virtual std::unique_ptr<FluxSourceIterator> readFlux(
|
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. */
|
* place. */
|
||||||
|
|
||||||
virtual void recalibrate() {}
|
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
|
/* Is this real hardware? If so, then flux can be read indefinitely (among
|
||||||
* other things). */
|
* other things). */
|
||||||
@@ -113,9 +118,10 @@ class EmptyFluxSourceIterator : public FluxSourceIterator
|
|||||||
class TrivialFluxSource : public FluxSource
|
class TrivialFluxSource : public FluxSource
|
||||||
{
|
{
|
||||||
public:
|
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(
|
virtual std::unique_ptr<const Fluxmap> readSingleFlux(
|
||||||
int track, int side) = 0;
|
int cylinder, int head) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,14 +1,31 @@
|
|||||||
#include "lib/core/globals.h"
|
#include "lib/core/globals.h"
|
||||||
#include "lib/data/fluxmap.h"
|
#include "lib/data/fluxmap.h"
|
||||||
|
#include "lib/data/locations.h"
|
||||||
#include "lib/fluxsource/fluxsource.pb.h"
|
#include "lib/fluxsource/fluxsource.pb.h"
|
||||||
#include "lib/fluxsource/fluxsource.h"
|
#include "lib/fluxsource/fluxsource.h"
|
||||||
#include "lib/external/flx.h"
|
#include "lib/external/flx.h"
|
||||||
|
#include "lib/core/logger.h"
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
class FlxFluxSource : public TrivialFluxSource
|
class FlxFluxSource : public TrivialFluxSource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FlxFluxSource(const FlxFluxSourceProto& config): _path(config.directory())
|
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:
|
public:
|
||||||
@@ -16,6 +33,7 @@ public:
|
|||||||
{
|
{
|
||||||
std::string path =
|
std::string path =
|
||||||
fmt::format("{}/@TR{:02}S{}@.FLX", _path, track, side + 1);
|
fmt::format("{}/@TR{:02}S{}@.FLX", _path, track, side + 1);
|
||||||
|
log("FLX: reading {}", path);
|
||||||
return readFlxBytes(Bytes::readFromFile(path));
|
return readFlxBytes(Bytes::readFromFile(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
#include "lib/core/globals.h"
|
#include "lib/core/globals.h"
|
||||||
#include "lib/data/fluxmap.h"
|
#include "lib/data/fluxmap.h"
|
||||||
|
#include "lib/data/locations.h"
|
||||||
#include "lib/external/kryoflux.h"
|
#include "lib/external/kryoflux.h"
|
||||||
#include "lib/fluxsource/fluxsource.pb.h"
|
#include "lib/fluxsource/fluxsource.pb.h"
|
||||||
#include "lib/fluxsource/fluxsource.h"
|
#include "lib/fluxsource/fluxsource.h"
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
class KryofluxFluxSource : public TrivialFluxSource
|
class KryofluxFluxSource : public TrivialFluxSource
|
||||||
{
|
{
|
||||||
@@ -10,6 +12,19 @@ public:
|
|||||||
KryofluxFluxSource(const KryofluxFluxSourceProto& config):
|
KryofluxFluxSource(const KryofluxFluxSourceProto& config):
|
||||||
_path(config.directory())
|
_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:
|
public:
|
||||||
|
|||||||
@@ -31,7 +31,16 @@ private:
|
|||||||
class MemoryFluxSource : public FluxSource
|
class MemoryFluxSource : public FluxSource
|
||||||
{
|
{
|
||||||
public:
|
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:
|
public:
|
||||||
std::unique_ptr<FluxSourceIterator> readFlux(
|
std::unique_ptr<FluxSourceIterator> readFlux(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "lib/core/globals.h"
|
#include "lib/core/globals.h"
|
||||||
#include "lib/data/fluxmap.h"
|
#include "lib/data/fluxmap.h"
|
||||||
|
#include "lib/data/locations.h"
|
||||||
#include "lib/external/kryoflux.h"
|
#include "lib/external/kryoflux.h"
|
||||||
#include "lib/fluxsource/fluxsource.pb.h"
|
#include "lib/fluxsource/fluxsource.pb.h"
|
||||||
#include "lib/core/utils.h"
|
#include "lib/core/utils.h"
|
||||||
@@ -53,6 +54,15 @@ public:
|
|||||||
if ((_header.cell_width != 0) && (_header.cell_width != 16))
|
if ((_header.cell_width != 0) && (_header.cell_width != 16))
|
||||||
error("currently only 16-bit cells in SCP files are supported");
|
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 {}-{}",
|
log("SCP tracks {}-{}, heads {}-{}",
|
||||||
trackno(_header.start_track),
|
trackno(_header.start_track),
|
||||||
trackno(_header.end_track),
|
trackno(_header.end_track),
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ public:
|
|||||||
TestPatternFluxSource(const TestPatternFluxSourceProto& config):
|
TestPatternFluxSource(const TestPatternFluxSourceProto& config):
|
||||||
_config(config)
|
_config(config)
|
||||||
{
|
{
|
||||||
|
_extraConfig.mutable_drive()->set_tracks("c0-255h0-1");
|
||||||
}
|
}
|
||||||
|
|
||||||
~TestPatternFluxSource() {}
|
~TestPatternFluxSource() {}
|
||||||
|
|||||||
@@ -78,8 +78,7 @@ public:
|
|||||||
trackHeaderWriter.write_8(recordingMode);
|
trackHeaderWriter.write_8(recordingMode);
|
||||||
trackHeaderWriter.write_8(0); /* format gap length */
|
trackHeaderWriter.write_8(0); /* format gap length */
|
||||||
trackHeaderWriter.write_8(0); /* filler byte */
|
trackHeaderWriter.write_8(0); /* filler byte */
|
||||||
trackHeaderWriter.write_le16(
|
trackHeaderWriter.write_le16(0); /* approximate track length */
|
||||||
0); /* approximate track length */
|
|
||||||
|
|
||||||
for (int sectorId = 0; sectorId < geometry.numSectors;
|
for (int sectorId = 0; sectorId < geometry.numSectors;
|
||||||
sectorId++)
|
sectorId++)
|
||||||
@@ -114,8 +113,7 @@ public:
|
|||||||
|
|
||||||
uint32_t trackLabel = (('T') << 24) | ((track & 0xff) << 16) |
|
uint32_t trackLabel = (('T') << 24) | ((track & 0xff) << 16) |
|
||||||
((track >> 8) << 8) | side;
|
((track >> 8) << 8) | side;
|
||||||
uint32_t trackHeaderAddress =
|
uint32_t trackHeaderAddress = ldbs.put(trackHeader, trackLabel);
|
||||||
ldbs.put(trackHeader, trackLabel);
|
|
||||||
trackDirectoryWriter.write_be32(trackLabel);
|
trackDirectoryWriter.write_be32(trackLabel);
|
||||||
trackDirectoryWriter.write_le32(trackHeaderAddress);
|
trackDirectoryWriter.write_le32(trackHeaderAddress);
|
||||||
trackDirectorySize++;
|
trackDirectorySize++;
|
||||||
|
|||||||
@@ -28,44 +28,26 @@ int mainConvert(int argc, const char* argv[])
|
|||||||
globalConfig().setFluxSink(filenames[1]);
|
globalConfig().setFluxSink(filenames[1]);
|
||||||
|
|
||||||
auto fluxSource = FluxSource::create(globalConfig());
|
auto fluxSource = FluxSource::create(globalConfig());
|
||||||
|
auto locations = globalConfig()->drive().tracks();
|
||||||
|
globalConfig().overrides()->set_tracks(locations);
|
||||||
|
|
||||||
#if 0
|
auto physicalLocations = Layout::computePhysicalLocations();
|
||||||
std::vector<std::shared_ptr<const TrackInfo>> locations;
|
auto [minCylinder, maxCylinder, minHead, maxHead] =
|
||||||
std::map<std::shared_ptr<const TrackInfo>,
|
Layout::getBounds(physicalLocations);
|
||||||
std::vector<std::shared_ptr<const Fluxmap>>>
|
log("CONVERT: seen cylinders {}..{}, heads {}..{}",
|
||||||
data;
|
minCylinder,
|
||||||
for (int track = 0; track < 255; track++)
|
maxCylinder,
|
||||||
for (int side = 0; side < 2; side++)
|
minHead,
|
||||||
{
|
maxHead);
|
||||||
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 fluxSink = FluxSink::create(globalConfig());
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ fluxengine read ibm --180 40track_drive
|
|||||||
>>>
|
>>>
|
||||||
|
|
||||||
drive {
|
drive {
|
||||||
tracks: 40
|
tracks: "c0-40h0-1"
|
||||||
drive_type: DRIVETYPE_40TRACK
|
drive_type: DRIVETYPE_40TRACK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ usb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
drive {
|
drive {
|
||||||
tracks: 160
|
tracks: "c0-159h0"
|
||||||
heads: 1
|
|
||||||
drive_type: DRIVETYPE_APPLE2
|
drive_type: DRIVETYPE_APPLE2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ usb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
drive {
|
drive {
|
||||||
tracks: 160
|
tracks: "c0-159h0"
|
||||||
heads: 1
|
|
||||||
drive_type: DRIVETYPE_APPLE2
|
drive_type: DRIVETYPE_APPLE2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user