From 5af22189e974459137455db0e17194e3a676e0f8 Mon Sep 17 00:00:00 2001 From: Thomas Daede Date: Wed, 10 Aug 2022 10:00:13 -0700 Subject: [PATCH] WIP: Add solved/reconstructed fluxmap support. This proof of concept adds an optional encoder and fluxsink that runs after the image is written. This currently exposes the config of the solvedEncoder, though I think I ultimately don't want it to be exposed as part of the config proto. Another way to do this would be by extending the decoders and/or directly reading their records. That is actually closer to what I want in many ways, however those records would need to be deduplicated from multiple reads, etc. The ultimate goal is to exactly replicate the timing of the original sectors, but with a stable clock, sectors reread if a bad read happens, and garbage between sectors removed. This requires extending the sector struct to have more information than it currently holds. --- arch/ibm/encoder.cc | 30 ++++++++++++++++++++++++++++++ arch/ibm/ibm.h | 1 + lib/config.proto | 4 +++- lib/encoders/encoders.cc | 18 ++++++++++++++++++ lib/encoders/encoders.h | 3 +++ lib/readerwriter.cc | 7 ++++++- lib/readerwriter.h | 2 +- src/fe-read.cc | 16 +++++++++++++++- 8 files changed, 77 insertions(+), 4 deletions(-) diff --git a/arch/ibm/encoder.cc b/arch/ibm/encoder.cc index 73eb4897..b53c6f9e 100644 --- a/arch/ibm/encoder.cc +++ b/arch/ibm/encoder.cc @@ -315,3 +315,33 @@ std::unique_ptr createIbmEncoder(const EncoderProto& config) { return std::unique_ptr(new IbmEncoder(config)); } + +std::unique_ptr createIbmEncoderFromImage(EncoderProto& config, const Image& image) +{ + IbmEncoderProto* ibm; + Geometry geometry; + ibm = config.mutable_ibm(); + geometry = image.getGeometry(); + std::map>> tracks_heads; + for (const auto& sector : image) { + tracks_heads[sector->logicalTrack][sector->logicalSide].push_back(sector.get()); + } + for (const auto& track: tracks_heads) { + for (const auto& head : track.second) { + auto trackdata = ibm->mutable_trackdata()->Add(); + for (const auto& sector : head.second) { + trackdata->mutable_sectors()->mutable_sector()->Add(sector->logicalSector); + trackdata->set_sector_size(sector->data.size()); + // note: this currently only uses the last sector's parameters + trackdata->set_target_clock_period_us(sector->clock / 1000.0 * 2.0); + } + trackdata->set_track(track.first); + trackdata->set_head(head.first); + trackdata->set_gap0(0x1b); + trackdata->set_gap2(0x09); + trackdata->set_gap3(0x1b); + trackdata->set_target_rotational_period_ms(167); + } + } + return createIbmEncoder(config); +} diff --git a/arch/ibm/ibm.h b/arch/ibm/ibm.h index fe804354..7d0caf54 100644 --- a/arch/ibm/ibm.h +++ b/arch/ibm/ibm.h @@ -33,5 +33,6 @@ class EncoderProto; extern std::unique_ptr createIbmDecoder(const DecoderProto& config); extern std::unique_ptr createIbmEncoder(const EncoderProto& config); +extern std::unique_ptr createIbmEncoderFromImage(EncoderProto& config, const Image& image); #endif diff --git a/lib/config.proto b/lib/config.proto index 29309f34..39fd968a 100644 --- a/lib/config.proto +++ b/lib/config.proto @@ -11,7 +11,7 @@ import "lib/drive.proto"; import "lib/mapper.proto"; import "lib/common.proto"; -// NEXT_TAG: 17 +// NEXT_TAG: 19 message ConfigProto { optional string comment = 8; optional bool is_extension = 13; @@ -21,9 +21,11 @@ message ConfigProto { optional FluxSourceProto flux_source = 10; optional FluxSinkProto flux_sink = 11; + optional FluxSinkProto solved_flux = 17; optional DriveProto drive = 15; optional EncoderProto encoder = 3; + optional EncoderProto solved_encoder = 18; optional DecoderProto decoder = 4; optional UsbProto usb = 5; diff --git a/lib/encoders/encoders.cc b/lib/encoders/encoders.cc index 30faf3b7..e00bb25c 100644 --- a/lib/encoders/encoders.cc +++ b/lib/encoders/encoders.cc @@ -13,6 +13,8 @@ #include "arch/tids990/tids990.h" #include "arch/victor9k/victor9k.h" #include "lib/encoders/encoders.pb.h" +#include "lib/decoders/decoders.pb.h" +#include "lib/image.h" #include "protocol.h" std::unique_ptr AbstractEncoder::create( @@ -40,6 +42,22 @@ std::unique_ptr AbstractEncoder::create( return (encoder->second)(config); } +std::unique_ptr AbstractEncoder::createFromImage(EncoderProto& encoderConfig, + const DecoderProto& decoderConfig, const Image& image) +{ + static const std::map(EncoderProto&, const Image&)>> + encoders = { + {DecoderProto::kIbm, createIbmEncoderFromImage}, + }; + + auto encoder = encoders.find(decoderConfig.format_case()); + if (encoder == encoders.end()) + Error() << "solved fluxmaps not supported for this format"; + + return (encoder->second)(encoderConfig, image); +} + Fluxmap& Fluxmap::appendBits(const std::vector& bits, nanoseconds_t clock) { nanoseconds_t now = duration(); diff --git a/lib/encoders/encoders.h b/lib/encoders/encoders.h index c2859c34..e76fc8b9 100644 --- a/lib/encoders/encoders.h +++ b/lib/encoders/encoders.h @@ -2,6 +2,7 @@ #define ENCODERS_H class EncoderProto; +class DecoderProto; class Fluxmap; class Image; class Location; @@ -14,6 +15,8 @@ class AbstractEncoder virtual ~AbstractEncoder() {} static std::unique_ptr create(const EncoderProto& config); + static std::unique_ptr createFromImage(EncoderProto& encoderConfig, + const DecoderProto& decoderConfig, const Image& image); public: virtual std::vector> collectSectors( diff --git a/lib/readerwriter.cc b/lib/readerwriter.cc index c80539d9..3c9fbf63 100644 --- a/lib/readerwriter.cc +++ b/lib/readerwriter.cc @@ -470,7 +470,7 @@ std::shared_ptr readDiskCommand( } void readDiskCommand( - FluxSource& fluxsource, AbstractDecoder& decoder, ImageWriter& writer) + FluxSource& fluxsource, AbstractDecoder& decoder, ImageWriter& writer,FluxSink* solvedFlux) { auto diskflux = readDiskCommand(fluxsource, decoder); @@ -478,6 +478,11 @@ void readDiskCommand( if (config.decoder().has_write_csv_to()) writer.writeCsv(*diskflux->image, config.decoder().write_csv_to()); writer.writeImage(*diskflux->image); + if (config.has_solved_flux()) { + std::unique_ptr solvedEncoder = AbstractEncoder::createFromImage(*config.mutable_encoder(), + config.decoder(), *diskflux->image); + writeTracks(*solvedFlux, *solvedEncoder, *diskflux->image); + } } void rawReadDiskCommand(FluxSource& fluxsource, FluxSink& fluxsink) diff --git a/lib/readerwriter.h b/lib/readerwriter.h index 8bf1ace4..e9f3fe65 100644 --- a/lib/readerwriter.h +++ b/lib/readerwriter.h @@ -34,7 +34,7 @@ extern std::unique_ptr readAndDecodeTrack( FluxSource& source, AbstractDecoder& decoder, unsigned track, unsigned head); extern std::shared_ptr readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder); -extern void readDiskCommand(FluxSource& source, AbstractDecoder& decoder, ImageWriter& writer); +extern void readDiskCommand(FluxSource& source, AbstractDecoder& decoder, ImageWriter& writer, FluxSink* solvedFlux); extern void rawReadDiskCommand(FluxSource& source, FluxSink& sink); #endif diff --git a/src/fe-read.cc b/src/fe-read.cc index 0e3f0f61..59be9a1b 100644 --- a/src/fe-read.cc +++ b/src/fe-read.cc @@ -3,6 +3,7 @@ #include "readerwriter.h" #include "fluxmap.h" #include "decoders/decoders.h" +#include "encoders/encoders.h" #include "macintosh/macintosh.h" #include "sector.h" #include "proto.h" @@ -45,6 +46,15 @@ static StringFlag copyFluxTo( FluxSink::updateConfigForFilename(config.mutable_decoder()->mutable_copy_flux_to(), value); }); +static StringFlag solvedFlux( + { "-r", "--solved" }, + "after reading, write a reconstructed/solved fluxmap to this file", + "", + [](const auto& value) + { + FluxSink::updateConfigForFilename(config.mutable_solved_flux(), value); + }); + static StringFlag srcTracks( { "--cylinders", "-c" }, "tracks to read from", @@ -76,8 +86,12 @@ int mainRead(int argc, const char* argv[]) std::unique_ptr fluxSource(FluxSource::create(config.flux_source())); std::unique_ptr decoder(AbstractDecoder::create(config.decoder())); std::unique_ptr writer(ImageWriter::create(config.image_writer())); + std::unique_ptr solvedFlux; + std::unique_ptr solvedEncoder; + if (config.has_solved_flux()) { + solvedFlux = FluxSink::create(config.solved_flux()); } - readDiskCommand(*fluxSource, *decoder, *writer); + readDiskCommand(*fluxSource, *decoder, *writer, solvedFlux.get()); return 0; }