mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Looks like we're going to have to rework the reader/writer/source/sink
interfaces, so do fluxsink. This lets us test for overwriting a flux file on writing in the GUI. HG: Enter commit message.
This commit is contained in:
@@ -52,7 +52,7 @@ need to apply extra options to change the format if desired.
|
|||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
- :
|
- $format:
|
||||||
- `143`: 143kB 5.25" SSDD hard-sectored; Micropolis MetaFloppy Mod I
|
- `143`: 143kB 5.25" SSDD hard-sectored; Micropolis MetaFloppy Mod I
|
||||||
- `287`: 287kB 5.25" DSDD hard-sectored; Micropolis MetaFloppy Mod I
|
- `287`: 287kB 5.25" DSDD hard-sectored; Micropolis MetaFloppy Mod I
|
||||||
- `315`: 315kB 5.25" SSDD hard-sectored; Micropolis MetaFloppy Mod II
|
- `315`: 315kB 5.25" SSDD hard-sectored; Micropolis MetaFloppy Mod II
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ static ReadGroupResult readGroup(const DiskLayout& diskLayout,
|
|||||||
|
|
||||||
void writeTracks(const DiskLayout& diskLayout,
|
void writeTracks(const DiskLayout& diskLayout,
|
||||||
|
|
||||||
FluxSink& fluxSink,
|
FluxSink& fluxSinkFactory,
|
||||||
std::function<std::unique_ptr<const Fluxmap>(
|
std::function<std::unique_ptr<const Fluxmap>(
|
||||||
const std::shared_ptr<const LogicalTrackLayout>&)> producer,
|
const std::shared_ptr<const LogicalTrackLayout>&)> producer,
|
||||||
std::function<bool(const std::shared_ptr<const LogicalTrackLayout>&)>
|
std::function<bool(const std::shared_ptr<const LogicalTrackLayout>&)>
|
||||||
@@ -419,8 +419,10 @@ void writeTracks(const DiskLayout& diskLayout,
|
|||||||
{
|
{
|
||||||
log(BeginOperationLogMessage{"Encoding and writing to disk"});
|
log(BeginOperationLogMessage{"Encoding and writing to disk"});
|
||||||
|
|
||||||
if (fluxSink.isHardware())
|
if (fluxSinkFactory.isHardware())
|
||||||
measureDiskRotation();
|
measureDiskRotation();
|
||||||
|
{
|
||||||
|
auto fluxSink = fluxSinkFactory.create();
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (auto& ch : logicalLocations)
|
for (auto& ch : logicalLocations)
|
||||||
{
|
{
|
||||||
@@ -449,7 +451,7 @@ void writeTracks(const DiskLayout& diskLayout,
|
|||||||
if (!fluxmap)
|
if (!fluxmap)
|
||||||
goto erase;
|
goto erase;
|
||||||
|
|
||||||
fluxSink.writeFlux(
|
fluxSink->addFlux(
|
||||||
physicalCylinder, physicalHead, *fluxmap);
|
physicalCylinder, physicalHead, *fluxmap);
|
||||||
log("writing {0} ms in {1} bytes",
|
log("writing {0} ms in {1} bytes",
|
||||||
int(fluxmap->duration() / 1e6),
|
int(fluxmap->duration() / 1e6),
|
||||||
@@ -461,7 +463,8 @@ void writeTracks(const DiskLayout& diskLayout,
|
|||||||
/* Erase this track rather than writing. */
|
/* Erase this track rather than writing. */
|
||||||
|
|
||||||
Fluxmap blank;
|
Fluxmap blank;
|
||||||
fluxSink.writeFlux(physicalCylinder, physicalHead, blank);
|
fluxSink->addFlux(
|
||||||
|
physicalCylinder, physicalHead, blank);
|
||||||
log("erased");
|
log("erased");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,6 +481,7 @@ void writeTracks(const DiskLayout& diskLayout,
|
|||||||
retriesRemaining--;
|
retriesRemaining--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log(EndOperationLogMessage{"Write complete"});
|
log(EndOperationLogMessage{"Write complete"});
|
||||||
}
|
}
|
||||||
@@ -672,17 +676,22 @@ void readDiskCommand(const DiskLayout& diskLayout,
|
|||||||
Decoder& decoder,
|
Decoder& decoder,
|
||||||
DecodedDisk& decodedDisk)
|
DecodedDisk& decodedDisk)
|
||||||
{
|
{
|
||||||
std::unique_ptr<FluxSink> outputFluxSink;
|
std::unique_ptr<FluxSink> outputFluxSinkFactory;
|
||||||
if (globalConfig()->decoder().has_copy_flux_to())
|
if (globalConfig()->decoder().has_copy_flux_to())
|
||||||
outputFluxSink =
|
outputFluxSinkFactory =
|
||||||
FluxSink::create(globalConfig()->decoder().copy_flux_to());
|
FluxSink::create(globalConfig()->decoder().copy_flux_to());
|
||||||
|
|
||||||
log(BeginOperationLogMessage{"Reading and decoding disk"});
|
log(BeginOperationLogMessage{"Reading and decoding disk"});
|
||||||
|
{
|
||||||
|
std::unique_ptr<FluxSink::Sink> outputFluxSink;
|
||||||
|
if (outputFluxSinkFactory)
|
||||||
|
outputFluxSink = outputFluxSinkFactory->create();
|
||||||
unsigned index = 0;
|
unsigned index = 0;
|
||||||
for (auto& [logicalLocation, ltl] : diskLayout.layoutByLogicalLocation)
|
for (auto& [logicalLocation, ltl] : diskLayout.layoutByLogicalLocation)
|
||||||
{
|
{
|
||||||
log(OperationProgressLogMessage{
|
log(OperationProgressLogMessage{
|
||||||
index * 100 / (unsigned)diskLayout.layoutByLogicalLocation.size()});
|
index * 100 /
|
||||||
|
(unsigned)diskLayout.layoutByLogicalLocation.size()});
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
testForEmergencyStop();
|
testForEmergencyStop();
|
||||||
@@ -701,7 +710,7 @@ void readDiskCommand(const DiskLayout& diskLayout,
|
|||||||
if (outputFluxSink)
|
if (outputFluxSink)
|
||||||
{
|
{
|
||||||
for (const auto& data : trackFluxes)
|
for (const auto& data : trackFluxes)
|
||||||
outputFluxSink->writeFlux(data->ptl->physicalCylinder,
|
outputFluxSink->addFlux(data->ptl->physicalCylinder,
|
||||||
data->ptl->physicalHead,
|
data->ptl->physicalHead,
|
||||||
*data->fluxmap);
|
*data->fluxmap);
|
||||||
}
|
}
|
||||||
@@ -768,10 +777,11 @@ void readDiskCommand(const DiskLayout& diskLayout,
|
|||||||
all_sectors = collectSectors(all_sectors);
|
all_sectors = collectSectors(all_sectors);
|
||||||
decodedDisk.image = std::make_shared<Image>(all_sectors);
|
decodedDisk.image = std::make_shared<Image>(all_sectors);
|
||||||
|
|
||||||
/* Log a _copy_ of the decodedDisk structure so that the logger doesn't
|
/* Log a _copy_ of the decodedDisk structure so that the logger
|
||||||
* see the decodedDisk get mutated in subsequent reads. */
|
* doesn't see the decodedDisk get mutated in subsequent reads. */
|
||||||
log(DiskReadLogMessage{std::make_shared<DecodedDisk>(decodedDisk)});
|
log(DiskReadLogMessage{std::make_shared<DecodedDisk>(decodedDisk)});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!decodedDisk.image)
|
if (!decodedDisk.image)
|
||||||
decodedDisk.image = std::make_shared<Image>();
|
decodedDisk.image = std::make_shared<Image>();
|
||||||
|
|||||||
@@ -17,27 +17,25 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include "fmt/chrono.h"
|
#include "fmt/chrono.h"
|
||||||
|
|
||||||
namespace
|
static uint32_t ticks_to_a2r(uint32_t ticks)
|
||||||
{
|
|
||||||
uint32_t ticks_to_a2r(uint32_t ticks)
|
|
||||||
{
|
{
|
||||||
return ticks * NS_PER_TICK / A2R_NS_PER_TICK;
|
return ticks * NS_PER_TICK / A2R_NS_PER_TICK;
|
||||||
}
|
}
|
||||||
|
|
||||||
class A2RFluxSink : public FluxSink
|
class A2RSink : public FluxSink::Sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
A2RFluxSink(const A2RFluxSinkProto& lconfig):
|
A2RSink(const std::string& filename):
|
||||||
_config(lconfig),
|
_filename(filename),
|
||||||
_bytes{},
|
_bytes{},
|
||||||
_writer{_bytes.writer()}
|
_writer(_bytes.writer())
|
||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
~A2RFluxSink()
|
~A2RSink()
|
||||||
{
|
{
|
||||||
// FIXME: should use a passed-in DiskLayout object.
|
// FIXME: should use a passed-in DiskLayout object.
|
||||||
auto diskLayout = createDiskLayout();
|
auto diskLayout = createDiskLayout();
|
||||||
@@ -58,8 +56,7 @@ namespace
|
|||||||
writeStream();
|
writeStream();
|
||||||
writeMeta();
|
writeMeta();
|
||||||
|
|
||||||
std::ofstream of(
|
std::ofstream of(_filename, std::ios::out | std::ios::binary);
|
||||||
_config.filename(), std::ios::out | std::ios::binary);
|
|
||||||
if (!of.is_open())
|
if (!of.is_open())
|
||||||
error("cannot open output file");
|
error("cannot open output file");
|
||||||
_bytes.writeTo(of);
|
_bytes.writeTo(of);
|
||||||
@@ -123,21 +120,22 @@ namespace
|
|||||||
writeChunkAndData(A2R_CHUNK_STRM, _strmBytes);
|
writeChunkAndData(A2R_CHUNK_STRM, _strmBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeFlux(int cylinder, int head, const Fluxmap& fluxmap) override
|
public:
|
||||||
|
void addFlux(int cylinder, int head, const Fluxmap& fluxmap) override
|
||||||
{
|
{
|
||||||
if (!fluxmap.bytes())
|
if (!fluxmap.bytes())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writing from an image (as opposed to from a floppy) will contain
|
// Writing from an image (as opposed to from a floppy) will
|
||||||
// exactly one revolution and no index events.
|
// contain exactly one revolution and no index events.
|
||||||
auto is_image = [](auto& fluxmap)
|
auto is_image = [](auto& fluxmap)
|
||||||
{
|
{
|
||||||
FluxmapReader fmr(fluxmap);
|
FluxmapReader fmr(fluxmap);
|
||||||
fmr.skipToEvent(F_BIT_INDEX);
|
fmr.skipToEvent(F_BIT_INDEX);
|
||||||
// but maybe there is no index, if we're writing from an image
|
// but maybe there is no index, if we're writing from an
|
||||||
// to an a2r
|
// image to an a2r
|
||||||
return fmr.eof();
|
return fmr.eof();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -191,8 +189,8 @@ namespace
|
|||||||
if (is_image(fluxmap))
|
if (is_image(fluxmap))
|
||||||
{
|
{
|
||||||
// A timing stream with no index represents exactly one
|
// A timing stream with no index represents exactly one
|
||||||
// revolution with no index. However, a2r nominally contains 450
|
// revolution with no index. However, a2r nominally contains
|
||||||
// degress of rotation, 250ms at 300rpm.
|
// 450 degress of rotation, 250ms at 300rpm.
|
||||||
write_flux();
|
write_flux();
|
||||||
loopPoint = totalTicks;
|
loopPoint = totalTicks;
|
||||||
fmr.rewind();
|
fmr.rewind();
|
||||||
@@ -201,8 +199,8 @@ namespace
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We have an index, so this is a real read from a floppy and
|
// We have an index, so this is a real read from a floppy
|
||||||
// should be "one revolution plus a bit"
|
// and should be "one revolution plus a bit"
|
||||||
fmr.skipToEvent(F_BIT_INDEX);
|
fmr.skipToEvent(F_BIT_INDEX);
|
||||||
write_flux();
|
write_flux();
|
||||||
}
|
}
|
||||||
@@ -220,13 +218,8 @@ namespace
|
|||||||
_strmWriter += trackBytes;
|
_strmWriter += trackBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator std::string() const override
|
|
||||||
{
|
|
||||||
return fmt::format("a2r({})", _config.filename());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const A2RFluxSinkProto& _config;
|
std::string _filename;
|
||||||
Bytes _bytes;
|
Bytes _bytes;
|
||||||
ByteWriter _writer;
|
ByteWriter _writer;
|
||||||
Bytes _strmBytes;
|
Bytes _strmBytes;
|
||||||
@@ -237,7 +230,30 @@ namespace
|
|||||||
int _minCylinder;
|
int _minCylinder;
|
||||||
int _maxCylinder;
|
int _maxCylinder;
|
||||||
};
|
};
|
||||||
} // namespace
|
|
||||||
|
class A2RFluxSink : public FluxSink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
A2RFluxSink(const A2RFluxSinkProto& lconfig): _config(lconfig) {}
|
||||||
|
|
||||||
|
std::unique_ptr<Sink> create() override
|
||||||
|
{
|
||||||
|
return std::make_unique<A2RSink>(_config.filename());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::filesystem::path> getPath() const override
|
||||||
|
{
|
||||||
|
return std::make_optional(_config.filename());
|
||||||
|
}
|
||||||
|
|
||||||
|
operator std::string() const override
|
||||||
|
{
|
||||||
|
return fmt::format("a2r({})", _config.filename());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const A2RFluxSinkProto& _config;
|
||||||
|
};
|
||||||
|
|
||||||
std::unique_ptr<FluxSink> FluxSink::createA2RFluxSink(
|
std::unique_ptr<FluxSink> FluxSink::createA2RFluxSink(
|
||||||
const A2RFluxSinkProto& config)
|
const A2RFluxSinkProto& config)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "lib/core/globals.h"
|
#include "lib/core/globals.h"
|
||||||
|
#include "lib/core/logger.h"
|
||||||
#include "lib/config/flags.h"
|
#include "lib/config/flags.h"
|
||||||
#include "lib/data/fluxmap.h"
|
#include "lib/data/fluxmap.h"
|
||||||
#include "lib/core/bytes.h"
|
#include "lib/core/bytes.h"
|
||||||
@@ -11,27 +12,29 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
class AuFluxSink : public FluxSink
|
class AuSink : public FluxSink::Sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AuFluxSink(const AuFluxSinkProto& config): _config(config) {}
|
AuSink(const std::string& directory, bool indexMarkers):
|
||||||
|
_directory(directory),
|
||||||
~AuFluxSink()
|
_indexMarkers(indexMarkers)
|
||||||
{
|
{
|
||||||
std::cerr << "Warning: do not play these files, or you will break your "
|
|
||||||
"speakers and/or ears!\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
~AuSink()
|
||||||
void writeFlux(int track, int head, const Fluxmap& fluxmap) override
|
{
|
||||||
|
log("Warning: do not play these files, or you will break your "
|
||||||
|
"speakers and/or ears!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void addFlux(int track, int head, const Fluxmap& fluxmap) override
|
||||||
{
|
{
|
||||||
unsigned totalTicks = fluxmap.ticks() + 2;
|
unsigned totalTicks = fluxmap.ticks() + 2;
|
||||||
unsigned channels = _config.index_markers() ? 2 : 1;
|
unsigned channels = _indexMarkers ? 2 : 1;
|
||||||
|
|
||||||
mkdir(_config.directory().c_str(), 0744);
|
mkdir(_directory.c_str(), 0744);
|
||||||
std::ofstream of(
|
std::ofstream of(
|
||||||
fmt::format(
|
fmt::format("{}/c{:02d}.h{:01d}.au", _directory, track, head),
|
||||||
"{}/c{:02d}.h{:01d}.au", _config.directory(), track, head),
|
|
||||||
std::ios::out | std::ios::binary);
|
std::ios::out | std::ios::binary);
|
||||||
if (!of.is_open())
|
if (!of.is_open())
|
||||||
error("cannot open output file");
|
error("cannot open output file");
|
||||||
@@ -73,7 +76,7 @@ public:
|
|||||||
|
|
||||||
if (event & F_BIT_PULSE)
|
if (event & F_BIT_PULSE)
|
||||||
data[timestamp * channels + 0] = 0x7f;
|
data[timestamp * channels + 0] = 0x7f;
|
||||||
if (_config.index_markers() && (event & F_BIT_INDEX))
|
if (_indexMarkers && (event & F_BIT_INDEX))
|
||||||
data[timestamp * channels + 1] = 0x7f;
|
data[timestamp * channels + 1] = 0x7f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +84,27 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string _directory;
|
||||||
|
bool _indexMarkers;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AuFluxSink : public FluxSink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AuFluxSink(const AuFluxSinkProto& config): _config(config) {}
|
||||||
|
|
||||||
|
std::unique_ptr<Sink> create() override
|
||||||
|
{
|
||||||
|
return std::make_unique<AuSink>(
|
||||||
|
_config.directory(), _config.index_markers());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::filesystem::path> getPath() const override
|
||||||
|
{
|
||||||
|
return std::make_optional(_config.directory());
|
||||||
|
}
|
||||||
|
|
||||||
operator std::string() const override
|
operator std::string() const override
|
||||||
{
|
{
|
||||||
return fmt::format("au({})", _config.directory());
|
return fmt::format("au({})", _config.directory());
|
||||||
|
|||||||
@@ -16,15 +16,10 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
class Fl2FluxSink : public FluxSink
|
class Fl2Sink : public FluxSink::Sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Fl2FluxSink(const Fl2FluxSinkProto& lconfig):
|
Fl2Sink(const std::string& filename): _filename(filename)
|
||||||
Fl2FluxSink(lconfig.filename())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Fl2FluxSink(const std::string& filename): _filename(filename)
|
|
||||||
{
|
{
|
||||||
std::ofstream of(filename);
|
std::ofstream of(filename);
|
||||||
if (!of.is_open())
|
if (!of.is_open())
|
||||||
@@ -33,7 +28,7 @@ public:
|
|||||||
std::filesystem::remove(filename);
|
std::filesystem::remove(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Fl2FluxSink()
|
~Fl2Sink()
|
||||||
{
|
{
|
||||||
log("FL2: writing {}", _filename);
|
log("FL2: writing {}", _filename);
|
||||||
|
|
||||||
@@ -54,27 +49,46 @@ public:
|
|||||||
saveFl2File(_filename, proto);
|
saveFl2File(_filename, proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
void addFlux(int track, int head, const Fluxmap& fluxmap) override
|
||||||
void writeFlux(int track, int head, const Fluxmap& fluxmap) override
|
|
||||||
{
|
{
|
||||||
auto& vector = _data[std::make_pair(track, head)];
|
auto& vector = _data[std::make_pair(track, head)];
|
||||||
vector.push_back(fluxmap.rawBytes());
|
vector.push_back(fluxmap.rawBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
operator std::string() const override
|
|
||||||
{
|
|
||||||
return fmt::format("fl2({})", _filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _filename;
|
std::string _filename;
|
||||||
std::map<std::pair<unsigned, unsigned>, std::vector<Bytes>> _data;
|
std::map<std::pair<unsigned, unsigned>, std::vector<Bytes>> _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Fl2FluxSink : public FluxSink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Fl2FluxSink(const std::string& filename): _filename(filename) {}
|
||||||
|
|
||||||
|
std::unique_ptr<Sink> create() override
|
||||||
|
{
|
||||||
|
return std::make_unique<Fl2Sink>(_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::filesystem::path> getPath() const override
|
||||||
|
{
|
||||||
|
return std::make_optional(_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
operator std::string() const override
|
||||||
|
{
|
||||||
|
return fmt::format("fl2({})", _filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string _filename;
|
||||||
|
};
|
||||||
|
|
||||||
std::unique_ptr<FluxSink> FluxSink::createFl2FluxSink(
|
std::unique_ptr<FluxSink> FluxSink::createFl2FluxSink(
|
||||||
const Fl2FluxSinkProto& config)
|
const Fl2FluxSinkProto& config)
|
||||||
{
|
{
|
||||||
return std::unique_ptr<FluxSink>(new Fl2FluxSink(config));
|
return std::unique_ptr<FluxSink>(new Fl2FluxSink(config.filename()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<FluxSink> FluxSink::createFl2FluxSink(
|
std::unique_ptr<FluxSink> FluxSink::createFl2FluxSink(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "lib/config/flags.h"
|
#include "lib/config/flags.h"
|
||||||
#include "lib/data/locations.h"
|
#include "lib/data/locations.h"
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
class Fluxmap;
|
class Fluxmap;
|
||||||
class FluxSinkProto;
|
class FluxSinkProto;
|
||||||
@@ -40,14 +41,27 @@ public:
|
|||||||
static std::unique_ptr<FluxSink> create(Config& config);
|
static std::unique_ptr<FluxSink> create(Config& config);
|
||||||
static std::unique_ptr<FluxSink> create(const FluxSinkProto& config);
|
static std::unique_ptr<FluxSink> create(const FluxSinkProto& config);
|
||||||
|
|
||||||
|
public:
|
||||||
|
class Sink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sink() {}
|
||||||
|
virtual ~Sink() {}
|
||||||
|
|
||||||
public:
|
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 addFlux(int track, int side, const Fluxmap& fluxmap) = 0;
|
||||||
void writeFlux(const CylinderHead& location, const Fluxmap& fluxmap)
|
void addFlux(const CylinderHead& location, const Fluxmap& fluxmap)
|
||||||
{
|
{
|
||||||
writeFlux(location.cylinder, location.head, fluxmap);
|
addFlux(location.cylinder, location.head, fluxmap);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
/* Creates a writer object. */
|
||||||
|
|
||||||
|
virtual std::unique_ptr<Sink> create() = 0;
|
||||||
|
|
||||||
/* Returns whether this is writing to real hardware or not. */
|
/* Returns whether this is writing to real hardware or not. */
|
||||||
|
|
||||||
@@ -56,6 +70,14 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns the path (filename or directory) being written to, if there is
|
||||||
|
* one. */
|
||||||
|
|
||||||
|
virtual std::optional<std::filesystem::path> getPath() const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
virtual operator std::string() const = 0;
|
virtual operator std::string() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,15 +8,9 @@
|
|||||||
#include "lib/fluxsink/fluxsink.h"
|
#include "lib/fluxsink/fluxsink.h"
|
||||||
#include "lib/fluxsink/fluxsink.pb.h"
|
#include "lib/fluxsink/fluxsink.pb.h"
|
||||||
|
|
||||||
class HardwareFluxSink : public FluxSink
|
class HardwareSink : public FluxSink::Sink
|
||||||
{
|
{
|
||||||
public:
|
void addFlux(int track, int side, const Fluxmap& fluxmap) override
|
||||||
HardwareFluxSink(const HardwareFluxSinkProto& conf): _config(conf) {}
|
|
||||||
|
|
||||||
~HardwareFluxSink() {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
void writeFlux(int track, int side, const Fluxmap& fluxmap) override
|
|
||||||
{
|
{
|
||||||
auto& drive = globalConfig()->drive();
|
auto& drive = globalConfig()->drive();
|
||||||
usbSetDrive(drive.drive(), drive.high_density(), drive.index_mode());
|
usbSetDrive(drive.drive(), drive.high_density(), drive.index_mode());
|
||||||
@@ -25,6 +19,15 @@ public:
|
|||||||
return usbWrite(
|
return usbWrite(
|
||||||
side, fluxmap.rawBytes(), drive.hard_sector_threshold_ns());
|
side, fluxmap.rawBytes(), drive.hard_sector_threshold_ns());
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class HardwareFluxSink : public FluxSink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::unique_ptr<Sink> create() override
|
||||||
|
{
|
||||||
|
return std::make_unique<HardwareSink>();
|
||||||
|
}
|
||||||
|
|
||||||
bool isHardware() const override
|
bool isHardware() const override
|
||||||
{
|
{
|
||||||
@@ -33,15 +36,12 @@ public:
|
|||||||
|
|
||||||
operator std::string() const override
|
operator std::string() const override
|
||||||
{
|
{
|
||||||
return fmt::format("drive {}", globalConfig()->drive().drive());
|
return "hardware {}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
const HardwareFluxSinkProto& _config;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<FluxSink> FluxSink::createHardwareFluxSink(
|
std::unique_ptr<FluxSink> FluxSink::createHardwareFluxSink(
|
||||||
const HardwareFluxSinkProto& config)
|
const HardwareFluxSinkProto& config)
|
||||||
{
|
{
|
||||||
return std::unique_ptr<FluxSink>(new HardwareFluxSink(config));
|
return std::unique_ptr<FluxSink>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,10 +36,13 @@ static void appendChecksum(uint32_t& checksum, const Bytes& bytes)
|
|||||||
checksum += br.read_8();
|
checksum += br.read_8();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScpFluxSink : public FluxSink
|
class ScpSink : public FluxSink::Sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ScpFluxSink(const ScpFluxSinkProto& lconfig): _config(lconfig)
|
ScpSink(const std::string& filename, uint8_t typeByte, bool alignWithIndex):
|
||||||
|
_filename(filename),
|
||||||
|
_typeByte(typeByte),
|
||||||
|
_alignWithIndex(alignWithIndex)
|
||||||
{
|
{
|
||||||
// FIXME: should use a passed-in DiskLayout object.
|
// FIXME: should use a passed-in DiskLayout object.
|
||||||
auto diskLayout = createDiskLayout();
|
auto diskLayout = createDiskLayout();
|
||||||
@@ -50,7 +53,7 @@ public:
|
|||||||
_fileheader.file_id[1] = 'C';
|
_fileheader.file_id[1] = 'C';
|
||||||
_fileheader.file_id[2] = 'P';
|
_fileheader.file_id[2] = 'P';
|
||||||
_fileheader.version = 0x18; /* Version 1.8 of the spec */
|
_fileheader.version = 0x18; /* Version 1.8 of the spec */
|
||||||
_fileheader.type = _config.type_byte();
|
_fileheader.type = _typeByte;
|
||||||
_fileheader.start_track = strackno(minCylinder, minHead);
|
_fileheader.start_track = strackno(minCylinder, minHead);
|
||||||
_fileheader.end_track = strackno(maxCylinder, maxHead);
|
_fileheader.end_track = strackno(maxCylinder, maxHead);
|
||||||
_fileheader.flags = SCP_FLAG_INDEXED;
|
_fileheader.flags = SCP_FLAG_INDEXED;
|
||||||
@@ -72,7 +75,7 @@ public:
|
|||||||
_fileheader.end_track - _fileheader.start_track + 1);
|
_fileheader.end_track - _fileheader.start_track + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
~ScpFluxSink()
|
~ScpSink()
|
||||||
{
|
{
|
||||||
uint32_t checksum = 0;
|
uint32_t checksum = 0;
|
||||||
appendChecksum(checksum,
|
appendChecksum(checksum,
|
||||||
@@ -82,7 +85,7 @@ public:
|
|||||||
write_le32(_fileheader.checksum, checksum);
|
write_le32(_fileheader.checksum, checksum);
|
||||||
|
|
||||||
log("SCP: writing output file");
|
log("SCP: writing output file");
|
||||||
std::ofstream of(_config.filename(), std::ios::out | std::ios::binary);
|
std::ofstream of(_filename, std::ios::out | std::ios::binary);
|
||||||
if (!of.is_open())
|
if (!of.is_open())
|
||||||
error("cannot open output file");
|
error("cannot open output file");
|
||||||
of.write((const char*)&_fileheader, sizeof(_fileheader));
|
of.write((const char*)&_fileheader, sizeof(_fileheader));
|
||||||
@@ -90,8 +93,7 @@ public:
|
|||||||
of.close();
|
of.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
void addFlux(int track, int head, const Fluxmap& fluxmap) override
|
||||||
void writeFlux(int track, int head, const Fluxmap& fluxmap) override
|
|
||||||
{
|
{
|
||||||
ByteWriter trackdataWriter(_trackdata);
|
ByteWriter trackdataWriter(_trackdata);
|
||||||
trackdataWriter.seekToEnd();
|
trackdataWriter.seekToEnd();
|
||||||
@@ -99,7 +101,8 @@ public:
|
|||||||
|
|
||||||
if (strack >= std::size(_fileheader.track))
|
if (strack >= std::size(_fileheader.track))
|
||||||
{
|
{
|
||||||
log("SCP: cannot write track {} head {}, there are not not enough "
|
log("SCP: cannot write track {} head {}, there are not not "
|
||||||
|
"enough "
|
||||||
"Track Data Headers.",
|
"Track Data Headers.",
|
||||||
track,
|
track,
|
||||||
head);
|
head);
|
||||||
@@ -117,7 +120,7 @@ public:
|
|||||||
|
|
||||||
int revolution =
|
int revolution =
|
||||||
-1; // -1 indicates that we are before the first index pulse
|
-1; // -1 indicates that we are before the first index pulse
|
||||||
if (_config.align_with_index())
|
if (_alignWithIndex)
|
||||||
{
|
{
|
||||||
fmr.skipToEvent(F_BIT_INDEX);
|
fmr.skipToEvent(F_BIT_INDEX);
|
||||||
revolution = 0;
|
revolution = 0;
|
||||||
@@ -136,9 +139,9 @@ public:
|
|||||||
totalTicks += ticks;
|
totalTicks += ticks;
|
||||||
revTicks += ticks;
|
revTicks += ticks;
|
||||||
|
|
||||||
// if we haven't output any revolutions yet by the end of the track,
|
// if we haven't output any revolutions yet by the end of the
|
||||||
// assume that the whole track is one rev
|
// track, assume that the whole track is one rev also discard
|
||||||
// also discard any duplicate index pulses
|
// any duplicate index pulses
|
||||||
if (((fmr.eof() && revolution <= 0) ||
|
if (((fmr.eof() && revolution <= 0) ||
|
||||||
((event & F_BIT_INDEX)) && revTicks > 0))
|
((event & F_BIT_INDEX)) && revTicks > 0))
|
||||||
{
|
{
|
||||||
@@ -181,6 +184,32 @@ public:
|
|||||||
trackdataWriter += fluxdata;
|
trackdataWriter += fluxdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string _filename;
|
||||||
|
uint8_t _typeByte;
|
||||||
|
bool _alignWithIndex;
|
||||||
|
ScpHeader _fileheader = {0};
|
||||||
|
Bytes _trackdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScpFluxSink : public FluxSink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScpFluxSink(const ScpFluxSinkProto& lconfig): _config(lconfig) {}
|
||||||
|
|
||||||
|
std::unique_ptr<Sink> create() override
|
||||||
|
{
|
||||||
|
return std::make_unique<ScpSink>(_config.filename(),
|
||||||
|
_config.type_byte(),
|
||||||
|
_config.align_with_index());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::filesystem::path> getPath() const override
|
||||||
|
{
|
||||||
|
return std::make_optional(_config.filename());
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
operator std::string() const override
|
operator std::string() const override
|
||||||
{
|
{
|
||||||
return fmt::format("scp({})", _config.filename());
|
return fmt::format("scp({})", _config.filename());
|
||||||
@@ -188,8 +217,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const ScpFluxSinkProto& _config;
|
const ScpFluxSinkProto& _config;
|
||||||
ScpHeader _fileheader = {0};
|
|
||||||
Bytes _trackdata;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<FluxSink> FluxSink::createScpFluxSink(
|
std::unique_ptr<FluxSink> FluxSink::createScpFluxSink(
|
||||||
|
|||||||
@@ -11,18 +11,16 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
class VcdFluxSink : public FluxSink
|
class VcdSink : public FluxSink::Sink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VcdFluxSink(const VcdFluxSinkProto& config): _config(config) {}
|
VcdSink(const std::string& directory): _directory(directory) {}
|
||||||
|
|
||||||
public:
|
void addFlux(int track, int head, const Fluxmap& fluxmap) override
|
||||||
void writeFlux(int track, int head, const Fluxmap& fluxmap) override
|
|
||||||
{
|
{
|
||||||
mkdir(_config.directory().c_str(), 0744);
|
mkdir(_directory.c_str(), 0744);
|
||||||
std::ofstream of(
|
std::ofstream of(
|
||||||
fmt::format(
|
fmt::format("{}/c{:02d}.h{:01d}.vcd", _directory, track, head),
|
||||||
"{}/c{:02d}.h{:01d}.vcd", _config.directory(), track, head),
|
|
||||||
std::ios::out | std::ios::binary);
|
std::ios::out | std::ios::binary);
|
||||||
if (!of.is_open())
|
if (!of.is_open())
|
||||||
error("cannot open output file");
|
error("cannot open output file");
|
||||||
@@ -64,6 +62,26 @@ public:
|
|||||||
of << "\n";
|
of << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string _directory;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VcdFluxSink : public FluxSink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VcdFluxSink(const VcdFluxSinkProto& config): _config(config) {}
|
||||||
|
|
||||||
|
std::unique_ptr<Sink> create() override
|
||||||
|
{
|
||||||
|
return std::make_unique<VcdSink>(_config.directory());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::filesystem::path> getPath() const override
|
||||||
|
{
|
||||||
|
return std::make_optional(_config.directory());
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
operator std::string() const override
|
operator std::string() const override
|
||||||
{
|
{
|
||||||
return fmt::format("vcd({})", _config.directory());
|
return fmt::format("vcd({})", _config.directory());
|
||||||
|
|||||||
@@ -53,13 +53,14 @@ int mainConvert(int argc, const char* argv[])
|
|||||||
minHead,
|
minHead,
|
||||||
maxHead);
|
maxHead);
|
||||||
|
|
||||||
auto fluxSink = FluxSink::create(globalConfig());
|
auto fluxSinkFactory = FluxSink::create(globalConfig());
|
||||||
|
auto fluxSink = fluxSinkFactory->create();
|
||||||
|
|
||||||
for (const auto& physicalLocation : diskLayout->physicalLocations)
|
for (const auto& physicalLocation : diskLayout->physicalLocations)
|
||||||
{
|
{
|
||||||
auto fi = fluxSource->readFlux(physicalLocation);
|
auto fi = fluxSource->readFlux(physicalLocation);
|
||||||
while (fi->hasNext())
|
while (fi->hasNext())
|
||||||
fluxSink->writeFlux(physicalLocation, *fi->next());
|
fluxSink->addFlux(physicalLocation, *fi->next());
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <hex/api/imhex_api/hex_editor.hpp>
|
#include <hex/api/imhex_api/hex_editor.hpp>
|
||||||
#include <hex/api/content_registry/settings.hpp>
|
#include <hex/api/content_registry/settings.hpp>
|
||||||
#include <hex/api/task_manager.hpp>
|
#include <hex/api/task_manager.hpp>
|
||||||
|
#include <popups/popup_question.hpp>
|
||||||
#include <toasts/toast_notification.hpp>
|
#include <toasts/toast_notification.hpp>
|
||||||
#include "lib/core/globals.h"
|
#include "lib/core/globals.h"
|
||||||
#include "lib/core/utils.h"
|
#include "lib/core/utils.h"
|
||||||
@@ -580,6 +581,29 @@ void Datastore::beginWrite()
|
|||||||
globalConfig().getVerificationFluxSourceProto());
|
globalConfig().getVerificationFluxSourceProto());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto path = fluxSink->getPath();
|
||||||
|
if (path.has_value() && std::filesystem::exists(*path))
|
||||||
|
{
|
||||||
|
{
|
||||||
|
bool result;
|
||||||
|
wtRunSynchronouslyOnUiThread((
|
||||||
|
std::function<void()>)[&] {
|
||||||
|
hex::ui::PopupQuestion::open(
|
||||||
|
"fluxengine.messages.writingFluxToFile"_lang,
|
||||||
|
[&]
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
},
|
||||||
|
[&]
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (!result)
|
||||||
|
throw EmergencyStopException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto image = diskFlux->image;
|
auto image = diskFlux->image;
|
||||||
writeDiskCommand(*diskLayout,
|
writeDiskCommand(*diskLayout,
|
||||||
*image,
|
*image,
|
||||||
@@ -717,7 +741,9 @@ void Datastore::writeFluxFile(const std::fs::path& path)
|
|||||||
error("no loaded image");
|
error("no loaded image");
|
||||||
if (diskFlux->image->getGeometry().totalBytes !=
|
if (diskFlux->image->getGeometry().totalBytes !=
|
||||||
diskLayout->totalBytes)
|
diskLayout->totalBytes)
|
||||||
error("loaded image is not the right size for this format");
|
error(
|
||||||
|
"loaded image is not the right size for this "
|
||||||
|
"format");
|
||||||
|
|
||||||
globalConfig().setFluxSink(path.string());
|
globalConfig().setFluxSink(path.string());
|
||||||
auto fluxSource = FluxSource::createMemoryFluxSource(*diskFlux);
|
auto fluxSource = FluxSource::createMemoryFluxSource(*diskFlux);
|
||||||
|
|||||||
@@ -101,9 +101,9 @@ void DiskProvider::writeRaw(u64 offset, const void* buffer, size_t size)
|
|||||||
|
|
||||||
[[nodiscard]] u64 DiskProvider::getActualSize() const
|
[[nodiscard]] u64 DiskProvider::getActualSize() const
|
||||||
{
|
{
|
||||||
const auto& diskFlux = Datastore::getDecodedDisk();
|
const auto& diskLayout = Datastore::getDiskLayout();
|
||||||
if (diskFlux && diskFlux->image)
|
if (diskLayout)
|
||||||
return diskFlux->image->getGeometry().totalBytes;
|
return diskLayout->totalBytes;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,5 +52,7 @@
|
|||||||
"fluxengine.view.status.writeFlux": "Writing flux file to disk",
|
"fluxengine.view.status.writeFlux": "Writing flux file to disk",
|
||||||
"fluxengine.view.status.readImage": "Reading image file from disk",
|
"fluxengine.view.status.readImage": "Reading image file from disk",
|
||||||
"fluxengine.view.status.writeImage": "Writing image file to disk",
|
"fluxengine.view.status.writeImage": "Writing image file to disk",
|
||||||
"fluxengine.view.status.blankFilesystem": "Creating blank filesystem"
|
"fluxengine.view.status.blankFilesystem": "Creating blank filesystem",
|
||||||
|
|
||||||
|
"fluxengine.messages.writingFluxToFile": "The current configuration is to write to a flux file rather than to hardware. Is this what you intended?"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,7 +271,8 @@ int main(int argc, const char* argv[])
|
|||||||
int version = sqlGetVersion(db);
|
int version = sqlGetVersion(db);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto fluxsink = FluxSink::createFl2FluxSink(outFilename);
|
auto fluxSink = FluxSink::createFl2FluxSink(outFilename)->create();
|
||||||
|
|
||||||
for (const auto& locations : sqlFindFlux(db))
|
for (const auto& locations : sqlFindFlux(db))
|
||||||
{
|
{
|
||||||
unsigned cylinder = locations.first;
|
unsigned cylinder = locations.first;
|
||||||
@@ -295,7 +296,7 @@ int main(int argc, const char* argv[])
|
|||||||
"bug)",
|
"bug)",
|
||||||
version);
|
version);
|
||||||
}
|
}
|
||||||
fluxsink->writeFlux(cylinder, head, fluxmap);
|
fluxSink->addFlux(cylinder, head, fluxmap);
|
||||||
std::cout << '.' << std::flush;
|
std::cout << '.' << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user