From eade2e279eb004821a793167bc7edbbea5bcd32d Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 24 Feb 2022 22:46:10 +0100 Subject: [PATCH] Make the internal disk data structures all const, to allow us to pass them to the GUI UI thread safely. --- arch/amiga/encoder.cc | 8 +- arch/brother/encoder.cc | 6 +- arch/c64/encoder.cc | 8 +- arch/ibm/encoder.cc | 6 +- arch/macintosh/encoder.cc | 8 +- arch/micropolis/encoder.cc | 8 +- arch/northstar/encoder.cc | 8 +- arch/tids990/encoder.cc | 6 +- arch/victor9k/encoder.cc | 6 +- lib/decoders/decoders.cc | 4 +- lib/decoders/decoders.h | 2 +- lib/encoders/encoders.h | 15 +- lib/flux.h | 10 +- lib/globals.h | 1 + lib/image.cc | 13 +- lib/image.h | 12 +- lib/logger.cc | 6 +- lib/logger.h | 4 +- lib/reader.cc | 345 ++++++++++++++++++++----------------- lib/sector.cc | 78 +++++---- lib/sector.h | 49 +++--- lib/writer.cc | 4 +- 22 files changed, 331 insertions(+), 276 deletions(-) diff --git a/arch/amiga/encoder.cc b/arch/amiga/encoder.cc index cc8cc2f2..cf5ac3e4 100644 --- a/arch/amiga/encoder.cc +++ b/arch/amiga/encoder.cc @@ -51,7 +51,7 @@ static void write_bits(std::vector& bits, unsigned& cursor, const Bytes& b } } -static void write_sector(std::vector& bits, unsigned& cursor, const std::shared_ptr& sector) +static void write_sector(std::vector& bits, unsigned& cursor, const std::shared_ptr& sector) { if ((sector->data.size() != 512) && (sector->data.size() != 528)) Error() << "unsupported sector size --- you must pick 512 or 528"; @@ -105,9 +105,9 @@ public: _config(config.amiga()) {} public: - std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override + std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override { - std::vector> sectors; + std::vector> sectors; if ((physicalTrack >= 0) && (physicalTrack < AMIGA_TRACKS_PER_DISK)) { @@ -123,7 +123,7 @@ public: } std::unique_ptr encode(int physicalTrack, int physicalSide, - const std::vector>& sectors, const Image& image) override + const std::vector>& sectors, const Image& image) override { if ((physicalTrack < 0) || (physicalTrack >= AMIGA_TRACKS_PER_DISK)) return std::unique_ptr(); diff --git a/arch/brother/encoder.cc b/arch/brother/encoder.cc index 87428462..cce7e4f4 100644 --- a/arch/brother/encoder.cc +++ b/arch/brother/encoder.cc @@ -109,9 +109,9 @@ public: {} public: - std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override + std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override { - std::vector> sectors; + std::vector> sectors; int logicalTrack; if (physicalSide != 0) @@ -144,7 +144,7 @@ public: } std::unique_ptr encode(int physicalTrack, int physicalSide, - const std::vector>& sectors, const Image& image) override + const std::vector>& sectors, const Image& image) override { int logicalTrack; if (physicalSide != 0) diff --git a/arch/c64/encoder.cc b/arch/c64/encoder.cc index 4f0c96be..ac1c451f 100644 --- a/arch/c64/encoder.cc +++ b/arch/c64/encoder.cc @@ -211,9 +211,9 @@ public: {} public: - std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override + std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override { - std::vector> sectors; + std::vector> sectors; if (physicalSide == 0) { @@ -231,7 +231,7 @@ public: } std::unique_ptr encode(int physicalTrack, int physicalSide, - const std::vector>& sectors, const Image& image) override + const std::vector>& sectors, const Image& image) override { /* The format ID Character # 1 and # 2 are in the .d64 image only present * in track 18 sector zero which contains the BAM info in byte 162 and 163. @@ -278,7 +278,7 @@ public: } private: - void writeSector(std::vector& bits, unsigned& cursor, const std::shared_ptr& sector) const + void writeSector(std::vector& bits, unsigned& cursor, std::shared_ptr sector) const { /* Source: http://www.unusedino.de/ec64/technical/formats/g64.html * 1. Header sync FF FF FF FF FF (40 'on' bits, not GCR) diff --git a/arch/ibm/encoder.cc b/arch/ibm/encoder.cc index c982776e..9a188c98 100644 --- a/arch/ibm/encoder.cc +++ b/arch/ibm/encoder.cc @@ -123,9 +123,9 @@ private: } public: - std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override + std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override { - std::vector> sectors; + std::vector> sectors; IbmEncoderProto::TrackdataProto trackdata; getTrackFormat(trackdata, physicalTrack, physicalSide); @@ -141,7 +141,7 @@ public: } std::unique_ptr encode(int physicalTrack, int physicalSide, - const std::vector>& sectors, const Image& image) override + const std::vector>& sectors, const Image& image) override { IbmEncoderProto::TrackdataProto trackdata; getTrackFormat(trackdata, physicalTrack, physicalSide); diff --git a/arch/macintosh/encoder.cc b/arch/macintosh/encoder.cc index 8f6614c8..7b4a9e38 100644 --- a/arch/macintosh/encoder.cc +++ b/arch/macintosh/encoder.cc @@ -164,7 +164,7 @@ static uint8_t encode_side(uint8_t track, uint8_t side) return (side ? 0x20 : 0x00) | ((track>0x3f) ? 0x01 : 0x00); } -static void write_sector(std::vector& bits, unsigned& cursor, const std::shared_ptr& sector) +static void write_sector(std::vector& bits, unsigned& cursor, const std::shared_ptr& sector) { if ((sector->data.size() != 512) && (sector->data.size() != 524)) Error() << "unsupported sector size --- you must pick 512 or 524"; @@ -208,9 +208,9 @@ public: {} public: - std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override + std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override { - std::vector> sectors; + std::vector> sectors; if ((physicalTrack >= 0) && (physicalTrack < MAC_TRACKS_PER_DISK)) { @@ -227,7 +227,7 @@ public: } std::unique_ptr encode(int physicalTrack, int physicalSide, - const std::vector>& sectors, const Image& image) override + const std::vector>& sectors, const Image& image) override { if ((physicalTrack < 0) || (physicalTrack >= MAC_TRACKS_PER_DISK)) return std::unique_ptr(); diff --git a/arch/micropolis/encoder.cc b/arch/micropolis/encoder.cc index 77719222..e81b76b9 100644 --- a/arch/micropolis/encoder.cc +++ b/arch/micropolis/encoder.cc @@ -6,7 +6,7 @@ #include "image.h" #include "lib/encoders/encoders.pb.h" -static void write_sector(std::vector& bits, unsigned& cursor, const std::shared_ptr& sector) +static void write_sector(std::vector& bits, unsigned& cursor, const std::shared_ptr& sector) { if ((sector->data.size() != 256) && (sector->data.size() != MICROPOLIS_ENCODED_SECTOR_SIZE)) Error() << "unsupported sector size --- you must pick 256 or 275"; @@ -70,9 +70,9 @@ public: _config(config.micropolis()) {} - std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override + std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override { - std::vector> sectors; + std::vector> sectors; if ((physicalTrack >= 0) && (physicalTrack < 77)) { @@ -88,7 +88,7 @@ public: } std::unique_ptr encode(int physicalTrack, int physicalSide, - const std::vector>& sectors, const Image& image) override + const std::vector>& sectors, const Image& image) override { int bitsPerRevolution = 100000; double clockRateUs = 2.00; diff --git a/arch/northstar/encoder.cc b/arch/northstar/encoder.cc index 44c09d4f..4172ba72 100644 --- a/arch/northstar/encoder.cc +++ b/arch/northstar/encoder.cc @@ -17,7 +17,7 @@ #define TOTAL_SECTOR_BYTES () -static void write_sector(std::vector& bits, unsigned& cursor, const std::shared_ptr& sector) +static void write_sector(std::vector& bits, unsigned& cursor, const std::shared_ptr& sector) { int preambleSize = 0; int encodedSectorSize = 0; @@ -108,9 +108,9 @@ public: _config(config.northstar()) {} - std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override + std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override { - std::vector> sectors; + std::vector> sectors; if ((physicalTrack >= 0) && (physicalTrack < 35)) { @@ -126,7 +126,7 @@ public: } std::unique_ptr encode(int physicalTrack, int physicalSide, - const std::vector>& sectors, const Image& image) override + const std::vector>& sectors, const Image& image) override { int bitsPerRevolution = 100000; double clockRateUs = 4.00; diff --git a/arch/tids990/encoder.cc b/arch/tids990/encoder.cc index 4d56cd20..915f03b1 100644 --- a/arch/tids990/encoder.cc +++ b/arch/tids990/encoder.cc @@ -59,9 +59,9 @@ private: } public: - std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override + std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override { - std::vector> sectors; + std::vector> sectors; for (char sectorChar : _config.sector_skew()) { @@ -75,7 +75,7 @@ public: } std::unique_ptr encode(int physicalTrack, int physicalSide, - const std::vector>& sectors, const Image& image) override + const std::vector>& sectors, const Image& image) override { double clockRateUs = 1e3 / _config.clock_rate_khz() / 2.0; int bitsPerRevolution = (_config.track_length_ms() * 1000.0) / clockRateUs; diff --git a/arch/victor9k/encoder.cc b/arch/victor9k/encoder.cc index 5f98328e..779a8234 100644 --- a/arch/victor9k/encoder.cc +++ b/arch/victor9k/encoder.cc @@ -143,9 +143,9 @@ private: } public: - std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override + std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override { - std::vector> sectors; + std::vector> sectors; Victor9kEncoderProto::TrackdataProto trackdata; getTrackFormat(trackdata, physicalTrack, physicalSide); @@ -162,7 +162,7 @@ public: } std::unique_ptr encode(int physicalTrack, int physicalSide, - const std::vector>& sectors, const Image& image) override + const std::vector>& sectors, const Image& image) override { Victor9kEncoderProto::TrackdataProto trackdata; getTrackFormat(trackdata, physicalTrack, physicalSide); diff --git a/lib/decoders/decoders.cc b/lib/decoders/decoders.cc index 0b622c0f..8032dc09 100644 --- a/lib/decoders/decoders.cc +++ b/lib/decoders/decoders.cc @@ -57,7 +57,7 @@ std::unique_ptr AbstractDecoder::create(const DecoderProto& con return (decoder->second)(config); } -std::shared_ptr AbstractDecoder::decodeToSectors( +std::shared_ptr AbstractDecoder::decodeToSectors( std::shared_ptr fluxmap, unsigned physicalCylinder, unsigned physicalHead) { _trackdata = std::make_shared(); @@ -84,7 +84,7 @@ std::shared_ptr AbstractDecoder::decodeToSectors( Fluxmap::Position recordStart = fmr.tell(); _sector->clock = advanceToNextRecord(); if (fmr.eof() || !_sector->clock) - return std::move(_trackdata); + return _trackdata; /* Read the sector record. */ diff --git a/lib/decoders/decoders.h b/lib/decoders/decoders.h index dc8db7bb..f559539c 100644 --- a/lib/decoders/decoders.h +++ b/lib/decoders/decoders.h @@ -45,7 +45,7 @@ public: }; public: - std::shared_ptr decodeToSectors(std::shared_ptr fluxmap, unsigned cylinder, unsigned head); + std::shared_ptr decodeToSectors(std::shared_ptr fluxmap, unsigned cylinder, unsigned head); void pushRecord(const Fluxmap::Position& start, const Fluxmap::Position& end); void resetFluxDecoder(); diff --git a/lib/encoders/encoders.h b/lib/encoders/encoders.h index c38f8568..902aacec 100644 --- a/lib/encoders/encoders.h +++ b/lib/encoders/encoders.h @@ -10,17 +10,18 @@ class AbstractEncoder { public: AbstractEncoder(const EncoderProto& config) {} - virtual ~AbstractEncoder() {} + virtual ~AbstractEncoder() {} - static std::unique_ptr create(const EncoderProto& config); + static std::unique_ptr create(const EncoderProto& config); public: - virtual std::vector> collectSectors( - int physicalCylinder, int physicalHead, const Image& image) = 0; + virtual std::vector> collectSectors( + int physicalCylinder, int physicalHead, const Image& image) = 0; - virtual std::unique_ptr encode( - int physicalCylinder, int physicalHead, const std::vector>& sectors, const Image& image) = 0; + virtual std::unique_ptr encode(int physicalCylinder, + int physicalHead, + const std::vector>& sectors, + const Image& image) = 0; }; #endif - diff --git a/lib/flux.h b/lib/flux.h index d4248479..f55c778f 100644 --- a/lib/flux.h +++ b/lib/flux.h @@ -17,7 +17,7 @@ struct TrackDataFlux unsigned physicalCylinder; unsigned physicalHead; std::shared_ptr fluxmap; - std::vector> records; + std::vector> records; std::vector> sectors; }; @@ -25,14 +25,14 @@ struct TrackFlux { unsigned physicalCylinder; unsigned physicalHead; - std::vector> trackDatas; - std::set> sectors; + std::vector> trackDatas; + std::set> sectors; }; struct DiskFlux { - std::vector> tracks; - std::unique_ptr image; + std::vector> tracks; + std::unique_ptr image; }; #endif diff --git a/lib/globals.h b/lib/globals.h index 702d84a2..addd98ca 100644 --- a/lib/globals.h +++ b/lib/globals.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/lib/image.cc b/lib/image.cc index 9831dcbd..d8b9ede6 100644 --- a/lib/image.cc +++ b/lib/image.cc @@ -5,9 +5,9 @@ Image::Image() {} -Image::Image(std::set>& sectors) +Image::Image(std::set>& sectors) { - for (std::shared_ptr sector : sectors) + for (auto& sector : sectors) { key_t key = std::make_tuple(sector->logicalTrack, sector->logicalSide, sector->logicalSector); _sectors[key] = sector; @@ -15,9 +15,9 @@ Image::Image(std::set>& sectors) calculateSize(); } -const std::shared_ptr& Image::get(unsigned track, unsigned side, unsigned sectorid) const +std::shared_ptr Image::get(unsigned track, unsigned side, unsigned sectorid) const { - const static std::shared_ptr NONE; + static std::shared_ptr NONE; key_t key = std::make_tuple(track, side, sectorid); auto i = _sectors.find(key); @@ -26,14 +26,15 @@ const std::shared_ptr& Image::get(unsigned track, unsigned side, unsigne return i->second; } -const std::shared_ptr& Image::put(unsigned track, unsigned side, unsigned sectorid) +std::shared_ptr Image::put(unsigned track, unsigned side, unsigned sectorid) { key_t key = std::make_tuple(track, side, sectorid); std::shared_ptr sector = std::make_shared(); sector->logicalTrack = track; sector->logicalSide = side; sector->logicalSector = sectorid; - return _sectors[key] = sector; + _sectors[key] = sector; + return sector; } void Image::calculateSize() diff --git a/lib/image.h b/lib/image.h index 80aa5c70..fc85d93d 100644 --- a/lib/image.h +++ b/lib/image.h @@ -18,16 +18,16 @@ private: public: Image(); - Image(std::set>& sectors); + Image(std::set>& sectors); public: class const_iterator { - typedef std::map>::const_iterator wrapped_iterator_t; + typedef std::map>::const_iterator wrapped_iterator_t; public: const_iterator(const wrapped_iterator_t& it): _it(it) {} - Sector* operator* () { return _it->second.get(); } + const Sector* operator* () { return _it->second.get(); } void operator++ () { _it++; } bool operator== (const const_iterator& other) const { return _it == other._it; } bool operator!= (const const_iterator& other) const { return _it != other._it; } @@ -39,8 +39,8 @@ public: public: void calculateSize(); - const std::shared_ptr& get(unsigned track, unsigned side, unsigned sectorId) const; - const std::shared_ptr& put(unsigned track, unsigned side, unsigned sectorId); + std::shared_ptr get(unsigned track, unsigned side, unsigned sectorId) const; + std::shared_ptr put(unsigned track, unsigned side, unsigned sectorId); const_iterator begin() const { return const_iterator(_sectors.cbegin()); } const_iterator end() const { return const_iterator(_sectors.cend()); } @@ -50,7 +50,7 @@ public: private: Geometry _geometry = {0, 0, 0}; - std::map> _sectors; + std::map> _sectors; }; #endif diff --git a/lib/logger.cc b/lib/logger.cc index 823d800e..a1808445 100644 --- a/lib/logger.cc +++ b/lib/logger.cc @@ -88,12 +88,12 @@ std::string Logger::toString(const AnyLogMessage& message) indent(); stream << "sectors:"; - std::vector> sectors( + std::vector> sectors( m.sectors.begin(), m.sectors.end()); std::sort(sectors.begin(), sectors.end(), - [](const std::shared_ptr& s1, - const std::shared_ptr& s2) + [](const std::shared_ptr& s1, + const std::shared_ptr& s2) { return s1->logicalSector < s2->logicalSector; }); diff --git a/lib/logger.h b/lib/logger.h index 391c6a08..295fa47d 100644 --- a/lib/logger.h +++ b/lib/logger.h @@ -21,8 +21,8 @@ struct DiskContextLogMessage struct SingleReadLogMessage { - std::shared_ptr trackDataFlux; - std::set> sectors; + std::shared_ptr trackDataFlux; + std::set> sectors; }; struct TrackReadLogMessage diff --git a/lib/reader.cc b/lib/reader.cc index 3aa67306..0d0aac20 100644 --- a/lib/reader.cc +++ b/lib/reader.cc @@ -21,179 +21,210 @@ static std::unique_ptr outputFluxSink; -static std::shared_ptr readFluxmap(FluxSource& fluxsource, unsigned cylinder, unsigned head) +static std::shared_ptr readFluxmap( + FluxSource& fluxsource, unsigned cylinder, unsigned head) { - Logger() << DiskContextLogMessage { cylinder, head } - << BeginReadOperationLogMessage(); - std::shared_ptr fluxmap = fluxsource.readFlux(cylinder, head); - fluxmap->rescale(1.0/config.flux_source().rescale()); - Logger() << EndReadOperationLogMessage() - << fmt::format("{0:.0} ms in {1} bytes", fluxmap->duration()/1e6, fluxmap->bytes()); - return fluxmap; + Logger() << DiskContextLogMessage{cylinder, head} + << BeginReadOperationLogMessage(); + std::shared_ptr fluxmap = fluxsource.readFlux(cylinder, head); + fluxmap->rescale(1.0 / config.flux_source().rescale()); + Logger() << EndReadOperationLogMessage() + << fmt::format("{0:.0} ms in {1} bytes", + fluxmap->duration() / 1e6, + fluxmap->bytes()); + return fluxmap; } static bool conflictable(Sector::Status status) { - return (status == Sector::OK) || (status == Sector::CONFLICT); + return (status == Sector::OK) || (status == Sector::CONFLICT); } -static std::set> collect_sectors(std::set>& track_sectors) +static std::set> collect_sectors( + std::set>& track_sectors) { - typedef std::tuple key_t; - std::map> sectors; + typedef std::tuple key_t; + std::multimap> sectors; - for (auto& replacement : track_sectors) - { - key_t sectorid = {replacement->logicalTrack, replacement->logicalSide, replacement->logicalSector}; - auto replacing = sectors[sectorid]; - if (replacing && conflictable(replacing->status) && conflictable(replacement->status)) - { - if (replacement->data != replacing->data) - { - Logger() << fmt::format("multiple conflicting copies of sector {} seen", - std::get<2>(sectorid)); - replacing->status = replacement->status = Sector::CONFLICT; - } - } - if (!replacing || ((replacing->status != Sector::OK) && (replacement->status == Sector::OK))) - sectors[sectorid] = replacement; - } - - std::set> sector_set; - for (auto& i : sectors) - sector_set.insert(i.second); - return sector_set; -} - -void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWriter& writer) -{ - if (config.decoder().has_copy_flux_to()) - outputFluxSink = FluxSink::create(config.decoder().copy_flux_to()); - - auto diskflux = std::make_unique(); - bool failures = false; - for (int cylinder : iterate(config.cylinders())) - { - for (int head : iterate(config.heads())) - { - auto track = std::make_shared(); - std::set> track_sectors; - std::set> track_records; - Fluxmap totalFlux; - - for (int retry = config.decoder().retries(); retry >= 0; retry--) - { - auto fluxmap = readFluxmap(fluxsource, cylinder, head); - totalFlux.appendDesync().appendBytes(fluxmap->rawBytes()); - - auto trackdataflux = decoder.decodeToSectors(fluxmap, cylinder, head); - track->trackDatas.push_back(trackdataflux); - - track_sectors.insert(trackdataflux->sectors.begin(), trackdataflux->sectors.end()); - track_records.insert(trackdataflux->records.begin(), trackdataflux->records.end()); - - auto collected_sectors = collect_sectors(track_sectors); - - bool hasBadSectors = false; - std::set required_sectors = decoder.requiredSectors(cylinder, head); - std::set> result_sectors; - for (const auto& sector : collected_sectors) - { - result_sectors.insert(sector); - required_sectors.erase(sector->logicalSector); - - if (sector->status != Sector::OK) - hasBadSectors = true; - } - for (unsigned logical_sector : required_sectors) - { - auto sector = std::make_shared(); - sector->logicalSector = logical_sector; - sector->status = Sector::MISSING; - result_sectors.insert(sector); - - hasBadSectors = true; - } - - Logger() << SingleReadLogMessage { trackdataflux, result_sectors }; - - if (hasBadSectors) - failures = false; - - if (!hasBadSectors) - break; - - if (!fluxsource.retryable()) - break; - if (retry == 0) - Logger() << fmt::format("giving up"); - else - Logger() << fmt::format("retrying; {} retries remaining", retry); - } - - if (outputFluxSink) - outputFluxSink->writeFlux(cylinder, head, totalFlux); - - if (config.decoder().dump_records()) - { - std::cout << "\nRaw (undecoded) records follow:\n\n"; - for (const auto& record : track_records) - { - std::cout << fmt::format("I+{:.2f}us with {:.2f}us clock\n", - record->startTime / 1000.0, - record->clock / 1000.0); - hexdump(std::cout, record->rawData); - std::cout << std::endl; - } - } - - if (config.decoder().dump_sectors()) - { - std::cout << "\nDecoded sectors follow:\n\n"; - for (const auto& sector : track_sectors) - { - std::cout << fmt::format("{}.{:02}.{:02}: I+{:.2f}us with {:.2f}us clock: status {}\n", - sector->logicalTrack, - sector->logicalSide, - sector->logicalSector, - sector->headerStartTime / 1000.0, - sector->clock / 1000.0, - Sector::statusToString(sector->status)); - hexdump(std::cout, sector->data); - std::cout << std::endl; - } - } - - track->sectors = collect_sectors(track_sectors); - Logger() << TrackReadLogMessage { track }; - diskflux->tracks.push_back(track); - } + for (const auto& sector : track_sectors) + { + key_t sectorid = { + sector->logicalTrack, sector->logicalSide, sector->logicalSector}; + sectors.insert({sectorid, sector}); } - std::set> all_sectors; - for (auto& track : diskflux->tracks) - for (auto& sector : track->sectors) - all_sectors.insert(sector); - all_sectors = collect_sectors(all_sectors); - diskflux->image.reset(new Image(all_sectors)); + std::set> sector_set; + auto it = sectors.begin(); + while (it != sectors.end()) + { + auto ub = sectors.upper_bound(it->first); + auto new_sector = std::accumulate(it, + ub, + it->second, + [&](auto left, auto& rightit) -> std::shared_ptr + { + auto& right = rightit.second; + if ((left->status == Sector::OK) && + (right->status == Sector::OK) && + (left->data != right->data)) + { + auto s = std::make_shared(*left); + s->status = Sector::CONFLICT; + return s; + } + if (left->status == Sector::CONFLICT) + return left; + if (right->status == Sector::CONFLICT) + return right; + if (left->status == Sector::OK) + return left; + if (right->status == Sector::OK) + return right; + return left; + }); + sector_set.insert(new_sector); + it = ub; + } + return sector_set; +} - writer.printMap(*diskflux->image); - if (config.decoder().has_write_csv_to()) - writer.writeCsv(*diskflux->image, config.decoder().write_csv_to()); - writer.writeImage(*diskflux->image); +void readDiskCommand( + FluxSource& fluxsource, AbstractDecoder& decoder, ImageWriter& writer) +{ + if (config.decoder().has_copy_flux_to()) + outputFluxSink = FluxSink::create(config.decoder().copy_flux_to()); - if (failures) - std::cerr << "Warning: some sectors could not be decoded." << std::endl; + auto diskflux = std::make_unique(); + bool failures = false; + for (int cylinder : iterate(config.cylinders())) + { + for (int head : iterate(config.heads())) + { + auto track = std::make_shared(); + std::set> track_sectors; + std::set> track_records; + Fluxmap totalFlux; + + for (int retry = config.decoder().retries(); retry >= 0; retry--) + { + auto fluxmap = readFluxmap(fluxsource, cylinder, head); + totalFlux.appendDesync().appendBytes(fluxmap->rawBytes()); + + auto trackdataflux = + decoder.decodeToSectors(fluxmap, cylinder, head); + track->trackDatas.push_back(trackdataflux); + + track_sectors.insert(trackdataflux->sectors.begin(), + trackdataflux->sectors.end()); + track_records.insert(trackdataflux->records.begin(), + trackdataflux->records.end()); + + bool hasBadSectors = false; + std::set required_sectors = + decoder.requiredSectors(cylinder, head); + std::set> result_sectors; + for (const auto& sector : collect_sectors(track_sectors)) + { + result_sectors.insert(sector); + required_sectors.erase(sector->logicalSector); + + if (sector->status != Sector::OK) + hasBadSectors = true; + } + for (unsigned logical_sector : required_sectors) + { + auto sector = std::make_shared(); + sector->logicalSector = logical_sector; + sector->status = Sector::MISSING; + result_sectors.insert(sector); + + hasBadSectors = true; + } + + Logger() << SingleReadLogMessage{trackdataflux, result_sectors}; + + if (hasBadSectors) + failures = false; + + if (!hasBadSectors) + break; + + if (!fluxsource.retryable()) + break; + if (retry == 0) + Logger() << fmt::format("giving up"); + else + Logger() + << fmt::format("retrying; {} retries remaining", retry); + } + + if (outputFluxSink) + outputFluxSink->writeFlux(cylinder, head, totalFlux); + + if (config.decoder().dump_records()) + { + std::cout << "\nRaw (undecoded) records follow:\n\n"; + for (const auto& record : track_records) + { + std::cout << fmt::format("I+{:.2f}us with {:.2f}us clock\n", + record->startTime / 1000.0, + record->clock / 1000.0); + hexdump(std::cout, record->rawData); + std::cout << std::endl; + } + } + + if (config.decoder().dump_sectors()) + { + std::cout << "\nDecoded sectors follow:\n\n"; + for (const auto& sector : track_sectors) + { + std::cout << fmt::format( + "{}.{:02}.{:02}: I+{:.2f}us with {:.2f}us clock: " + "status {}\n", + sector->logicalTrack, + sector->logicalSide, + sector->logicalSector, + sector->headerStartTime / 1000.0, + sector->clock / 1000.0, + Sector::statusToString(sector->status)); + hexdump(std::cout, sector->data); + std::cout << std::endl; + } + } + + for (const auto& sector : collect_sectors(track_sectors)) + track->sectors.insert(sector); + + Logger() << TrackReadLogMessage{track}; + diskflux->tracks.push_back(track); + } + } + + std::set> all_sectors; + for (auto& track : diskflux->tracks) + for (auto& sector : track->sectors) + all_sectors.insert(sector); + all_sectors = collect_sectors(all_sectors); + diskflux->image.reset(new Image(all_sectors)); + + writer.printMap(*diskflux->image); + if (config.decoder().has_write_csv_to()) + writer.writeCsv(*diskflux->image, config.decoder().write_csv_to()); + writer.writeImage(*diskflux->image); + + if (failures) + std::cerr << "Warning: some sectors could not be decoded." << std::endl; } void rawReadDiskCommand(FluxSource& fluxsource, FluxSink& fluxsink) { - for (int cylinder : iterate(config.cylinders())) - { - for (int head : iterate(config.heads())) - { - auto fluxmap = readFluxmap(fluxsource, cylinder, head); - fluxsink.writeFlux(cylinder, head, *fluxmap); - } + for (int cylinder : iterate(config.cylinders())) + { + for (int head : iterate(config.heads())) + { + auto fluxmap = readFluxmap(fluxsource, cylinder, head); + fluxsink.writeFlux(cylinder, head, *fluxmap); + } } } diff --git a/lib/sector.cc b/lib/sector.cc index f654b7a8..c499bf83 100644 --- a/lib/sector.cc +++ b/lib/sector.cc @@ -6,12 +6,18 @@ std::string Sector::statusToString(Status status) { switch (status) { - case Status::OK: return "OK"; - case Status::BAD_CHECKSUM: return "bad checksum"; - case Status::MISSING: return "sector not found"; - case Status::DATA_MISSING: return "present but no data found"; - case Status::CONFLICT: return "conflicting data"; - default: return fmt::format("unknown error {}", status); + case Status::OK: + return "OK"; + case Status::BAD_CHECKSUM: + return "bad checksum"; + case Status::MISSING: + return "sector not found"; + case Status::DATA_MISSING: + return "present but no data found"; + case Status::CONFLICT: + return "conflicting data"; + default: + return fmt::format("unknown error {}", status); } } @@ -19,42 +25,48 @@ std::string Sector::statusToChar(Status status) { switch (status) { - case Status::OK: return ""; - case Status::MISSING: return "?"; - case Status::BAD_CHECKSUM: return "!"; - case Status::DATA_MISSING: return "!"; - case Status::CONFLICT: return "*"; - default: return "?"; + case Status::OK: + return ""; + case Status::MISSING: + return "?"; + case Status::BAD_CHECKSUM: + return "!"; + case Status::DATA_MISSING: + return "!"; + case Status::CONFLICT: + return "*"; + default: + return "?"; } } Sector::Status Sector::stringToStatus(const std::string& value) { - if (value == "OK") - return Status::OK; - if (value == "bad checksum") - return Status::BAD_CHECKSUM; - if ((value == "sector not found") || (value == "MISSING")) - return Status::MISSING; - if (value == "present but no data found") - return Status::DATA_MISSING; - if (value == "conflicting data") - return Status::CONFLICT; - return Status::INTERNAL_ERROR; + if (value == "OK") + return Status::OK; + if (value == "bad checksum") + return Status::BAD_CHECKSUM; + if ((value == "sector not found") || (value == "MISSING")) + return Status::MISSING; + if (value == "present but no data found") + return Status::DATA_MISSING; + if (value == "conflicting data") + return Status::CONFLICT; + return Status::INTERNAL_ERROR; } -bool sectorPointerSortPredicate(std::shared_ptr& lhs, std::shared_ptr& rhs) +bool sectorPointerSortPredicate( + std::shared_ptr& lhs, std::shared_ptr& rhs) { - return *lhs < *rhs; + return *lhs < *rhs; } -bool sectorPointerEqualsPredicate(std::shared_ptr& lhs, std::shared_ptr& rhs) +bool sectorPointerEqualsPredicate( + std::shared_ptr& lhs, std::shared_ptr& rhs) { - if (!lhs && !rhs) - return true; - if (!lhs || !rhs) - return false; - return *lhs == *rhs; + if (!lhs && !rhs) + return true; + if (!lhs || !rhs) + return false; + return *lhs == *rhs; } - - diff --git a/lib/sector.h b/lib/sector.h index 8a6a84e8..8061ceae 100644 --- a/lib/sector.h +++ b/lib/sector.h @@ -6,7 +6,7 @@ class Record; -/* +/* * Note that sectors here used zero-based numbering throughout (to make the * maths easier); traditionally floppy disk use 0-based track numbering and * 1-based sector numbering, which makes no sense. @@ -14,21 +14,21 @@ class Record; class Sector { public: - enum Status - { - OK, - BAD_CHECKSUM, + enum Status + { + OK, + BAD_CHECKSUM, MISSING, DATA_MISSING, CONFLICT, INTERNAL_ERROR - }; + }; static std::string statusToString(Status status); static std::string statusToChar(Status status); static Status stringToStatus(const std::string& value); - Status status = Status::INTERNAL_ERROR; + Status status = Status::INTERNAL_ERROR; uint32_t position; nanoseconds_t clock = 0; nanoseconds_t headerStartTime = 0; @@ -41,24 +41,33 @@ public: unsigned logicalSide = 0; unsigned logicalSector = 0; Bytes data; - std::vector> records; + std::vector> records; - std::tuple key() const - { return std::make_tuple(logicalTrack, logicalSide, logicalSector, status); } + std::tuple key() const + { + return std::make_tuple( + logicalTrack, logicalSide, logicalSector, status); + } - bool operator == (const Sector& rhs) const - { return key() == rhs.key(); } + bool operator==(const Sector& rhs) const + { + return key() == rhs.key(); + } - bool operator != (const Sector& rhs) const - { return key() != rhs.key(); } - - bool operator < (const Sector& rhs) const - { return key() < rhs.key(); } + bool operator!=(const Sector& rhs) const + { + return key() != rhs.key(); + } + bool operator<(const Sector& rhs) const + { + return key() < rhs.key(); + } }; -extern bool sectorPointerSortPredicate(std::shared_ptr& lhs, std::shared_ptr& rhs); -extern bool sectorPointerEqualsPredicate(std::shared_ptr& lhs, std::shared_ptr& rhs); +extern bool sectorPointerSortPredicate( + std::shared_ptr& lhs, std::shared_ptr& rhs); +extern bool sectorPointerEqualsPredicate( + std::shared_ptr& lhs, std::shared_ptr& rhs); #endif - diff --git a/lib/writer.cc b/lib/writer.cc index 00aade64..fd16d90f 100644 --- a/lib/writer.cc +++ b/lib/writer.cc @@ -109,8 +109,8 @@ void writeTracksAndVerify(FluxSink& fluxSink, const auto trackdata = decoder.decodeToSectors(writtenFluxmap, cylinder, head); - std::vector> gotSectors = - trackdata->sectors; + std::vector> gotSectors( + trackdata->sectors.begin(), trackdata->sectors.end()); gotSectors.erase(std::remove_if(gotSectors.begin(), gotSectors.end(), [](const auto& s)