From 87ce3ad61d15dd85f83a1b57685535cc2f103eac Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 16 Oct 2025 00:52:37 +0200 Subject: [PATCH] Fluxmaps can now be queried for a (cached) list of index marks. Tracks now contain both the raw list of sectors and a deduplicated list, suitable for the visualiser. --- lib/algorithms/readerwriter.cc | 14 ++++++++++---- lib/algorithms/readerwriter.h | 2 -- lib/data/disk.cc | 3 ++- lib/data/disk.h | 13 ++++++++++++- lib/data/fluxmap.cc | 29 +++++++++++++++++++++++++++++ lib/data/fluxmap.h | 4 ++++ lib/data/fluxmapreader.cc | 7 +++++++ lib/data/fluxmapreader.h | 1 + lib/decoders/decoders.cc | 2 +- tests/fluxmapreader.cc | 18 ++++++++++++++---- 10 files changed, 80 insertions(+), 13 deletions(-) diff --git a/lib/algorithms/readerwriter.cc b/lib/algorithms/readerwriter.cc index 5123919b..33ee1dc6 100644 --- a/lib/algorithms/readerwriter.cc +++ b/lib/algorithms/readerwriter.cc @@ -88,7 +88,7 @@ void renderLogMessage( std::set> rawRecords; for (const auto& track : m->tracks) { - rawSectors.insert(track->sectors.begin(), track->sectors.end()); + rawSectors.insert(track->allSectors.begin(), track->allSectors.end()); rawRecords.insert(track->records.begin(), track->records.end()); } @@ -113,7 +113,7 @@ void renderLogMessage( m->sectors.begin(), m->sectors.end()); std::sort(sectors.begin(), sectors.end(), sectorPointerSortPredicate); - for (const auto& sector : sectors) + for (const auto& sector : rawSectors) r.add(fmt::format("{}.{}.{}{}", sector->logicalCylinder, sector->logicalHead, @@ -180,7 +180,7 @@ private: _cache; }; -void measureDiskRotation() +static nanoseconds_t measureDiskRotation() { log(BeginSpeedOperationLogMessage()); @@ -220,6 +220,7 @@ void measureDiskRotation() error("Failed\nIs a disk in the drive?"); log(EndSpeedOperationLogMessage{oneRevolution}); + return oneRevolution; } /* Given a set of sectors, deduplicates them sensibly (e.g. if there is a good @@ -298,7 +299,7 @@ static CombinationResult combineRecordAndSectors( /* Add the sectors which were there. */ for (auto& track : tracks) - for (auto& sector : track->sectors) + for (auto& sector : track->allSectors) track_sectors.push_back(sector); /* Add the sectors which should be there. */ @@ -399,6 +400,7 @@ static ReadGroupResult readGroup(const DiskLayout& diskLayout, fluxmap->bytes()); auto flux = decoder.decodeToSectors(std::move(fluxmap), ptl); + flux->normalisedSectors = collectSectors(flux->allSectors); tracks.push_back(flux); /* Decode what we've got so far. */ @@ -707,6 +709,10 @@ void readDiskCommand(const DiskLayout& diskLayout, .push_back(track); log(BeginOperationLogMessage{"Reading and decoding disk"}); + + if (fluxSource.isHardware()) + disk.rotationalPeriod = measureDiskRotation(); + { std::unique_ptr outputFluxSink; if (outputFluxSinkFactory) diff --git a/lib/algorithms/readerwriter.h b/lib/algorithms/readerwriter.h index 36c0a63a..b3df203d 100644 --- a/lib/algorithms/readerwriter.h +++ b/lib/algorithms/readerwriter.h @@ -76,8 +76,6 @@ struct OperationProgressLogMessage unsigned progress; }; -extern void measureDiskRotation(); - extern void writeTracks(const DiskLayout& diskLayout, FluxSinkFactory& fluxSinkFactory, const std::function( diff --git a/lib/data/disk.cc b/lib/data/disk.cc index 9fd7e05a..17a55fea 100644 --- a/lib/data/disk.cc +++ b/lib/data/disk.cc @@ -47,7 +47,8 @@ Disk::Disk( for (auto& [ch, sector] : sectorsGroupedByTrack.equal_range(physicalLocation) | pair_to_range) { - decodedTrack->sectors.push_back(sector); + decodedTrack->allSectors.push_back(sector); + decodedTrack->normalisedSectors.push_back(sector); sectorsByPhysicalLocation.insert( std::make_pair(physicalLocation, sector)); } diff --git a/lib/data/disk.h b/lib/data/disk.h index 414bcbde..ba3c12c4 100644 --- a/lib/data/disk.h +++ b/lib/data/disk.h @@ -26,7 +26,14 @@ struct Track std::shared_ptr ptl; std::shared_ptr fluxmap; std::vector> records; - std::vector> sectors; + + /* All sectors, valid or not, including duplicates. */ + + std::vector> allSectors; + + /* Zero or one sector for each ID, preferring good ones. */ + + std::vector> normalisedSectors; }; struct Disk @@ -46,6 +53,10 @@ struct Disk std::multimap> sectorsByPhysicalLocation; std::shared_ptr image; + + /* 0 if the period is unknown (e.g. if this Disk was made from an image). */ + + nanoseconds_t rotationalPeriod = 0; }; #endif diff --git a/lib/data/fluxmap.cc b/lib/data/fluxmap.cc index 5c12c02a..f5e8e8d9 100644 --- a/lib/data/fluxmap.cc +++ b/lib/data/fluxmap.cc @@ -1,6 +1,8 @@ #include "lib/core/globals.h" #include "lib/data/fluxmap.h" +#include "lib/data/fluxmapreader.h" #include "protocol.h" +#include Fluxmap& Fluxmap::appendBytes(const Bytes& bytes) { @@ -12,6 +14,8 @@ Fluxmap& Fluxmap::appendBytes(const Bytes& bytes) Fluxmap& Fluxmap::appendBytes(const uint8_t* ptr, size_t len) { + flushIndexMarks(); + ByteWriter bw(_bytes); bw.seekToEnd(); @@ -52,6 +56,7 @@ Fluxmap& Fluxmap::appendPulse() Fluxmap& Fluxmap::appendIndex() { + flushIndexMarks(); findLastByte() |= 0x40; return *this; } @@ -75,3 +80,27 @@ std::vector> Fluxmap::split() const return maps; } + +const std::vector& Fluxmap::getIndexMarks() const +{ + std::scoped_lock lock(_mutationMutex); + if (!_indexMarks.has_value()) + { + _indexMarks = std::make_optional>(); + FluxmapReader fmr(*this); + for (;;) + { + unsigned ticks; + if (!fmr.findEvent(F_BIT_INDEX, ticks)) + break; + _indexMarks->push_back(fmr.tell().ns()); + } + } + return *_indexMarks; +} + +void Fluxmap::flushIndexMarks() +{ + std::scoped_lock lock(_mutationMutex); + _indexMarks = {}; +} diff --git a/lib/data/fluxmap.h b/lib/data/fluxmap.h index 52322007..8f9b0bbc 100644 --- a/lib/data/fluxmap.h +++ b/lib/data/fluxmap.h @@ -82,14 +82,18 @@ public: std::unique_ptr precompensate( int threshold_ticks, int amount_ticks); std::vector> split() const; + const std::vector& getIndexMarks() const; private: uint8_t& findLastByte(); + void flushIndexMarks(); private: nanoseconds_t _duration = 0; int _ticks = 0; Bytes _bytes; + mutable std::mutex _mutationMutex; + mutable std::optional> _indexMarks; }; #endif diff --git a/lib/data/fluxmapreader.cc b/lib/data/fluxmapreader.cc index 12921f76..477e6fa8 100644 --- a/lib/data/fluxmapreader.cc +++ b/lib/data/fluxmapreader.cc @@ -44,6 +44,13 @@ void FluxmapReader::skipToEvent(int event) findEvent(event, ticks); } +int FluxmapReader::getCurrentEvent() +{ + if (eof()) + return F_EOF; + return _bytes[_pos.bytes] & 0xc0; +} + bool FluxmapReader::findEvent(int event, unsigned& ticks) { ticks = 0; diff --git a/lib/data/fluxmapreader.h b/lib/data/fluxmapreader.h index 29a73062..ee99ccdb 100644 --- a/lib/data/fluxmapreader.h +++ b/lib/data/fluxmapreader.h @@ -42,6 +42,7 @@ public: return (_fluxmap.duration()); } + int getCurrentEvent(); void getNextEvent(int& event, unsigned& ticks); void skipToEvent(int event); bool findEvent(int event, unsigned& ticks); diff --git a/lib/decoders/decoders.cc b/lib/decoders/decoders.cc index 4c9a2ca8..443b9658 100644 --- a/lib/decoders/decoders.cc +++ b/lib/decoders/decoders.cc @@ -90,7 +90,7 @@ std::shared_ptr Decoder::decodeToSectors( } if (_sector->status != Sector::MISSING) - _trackdata->sectors.push_back(_sector); + _trackdata->allSectors.push_back(_sector); } return _trackdata; diff --git a/tests/fluxmapreader.cc b/tests/fluxmapreader.cc index 78cb76a6..84e56d14 100644 --- a/tests/fluxmapreader.cc +++ b/tests/fluxmapreader.cc @@ -5,8 +5,11 @@ #include "fmt/format.h" #include "tests.h" #include +#include "snowhouse/snowhouse.h" -static Fluxmap fluxmap(Bytes{F_DESYNC, +using namespace snowhouse; + +static const Fluxmap fluxmap(Bytes{F_DESYNC, F_BIT_PULSE | 0x30, F_BIT_INDEX | 0x30, F_BIT_PULSE | F_BIT_INDEX | 0x30, @@ -59,7 +62,7 @@ void test_read_pulses() ASSERT_READ_SPECIFIC_EVENT(F_BIT_PULSE, 0x60); ASSERT_READ_SPECIFIC_EVENT(F_BIT_PULSE, 0x60); ASSERT_READ_SPECIFIC_EVENT(F_BIT_PULSE, 0x30); - ASSERT_READ_SPECIFIC_EVENT(F_BIT_PULSE, 0x90); + ASSERT_READ_SPECIFIC_EVENT(F_BIT_PULSE, 0x90); /* EOF event */ } void test_read_indices() @@ -67,7 +70,7 @@ void test_read_indices() FluxmapReader fmr(fluxmap); ASSERT_READ_SPECIFIC_EVENT(F_BIT_INDEX, 0x60); ASSERT_READ_SPECIFIC_EVENT(F_BIT_INDEX, 0x30); - ASSERT_READ_SPECIFIC_EVENT(F_BIT_INDEX, 6 * 0x30); + ASSERT_READ_SPECIFIC_EVENT(F_BIT_INDEX, 6 * 0x30); /* EOF event */ } void test_read_desyncs() @@ -76,7 +79,13 @@ void test_read_desyncs() ASSERT_READ_SPECIFIC_EVENT(F_DESYNC, 0); ASSERT_READ_SPECIFIC_EVENT(F_DESYNC, 0xf0); ASSERT_READ_SPECIFIC_EVENT(F_DESYNC, 0x60); - ASSERT_READ_SPECIFIC_EVENT(F_DESYNC, 0x60); + ASSERT_READ_SPECIFIC_EVENT(F_DESYNC, 0x60); /* EOF event */ +} + +void test_index_marks() +{ + AssertThat(fluxmap.getIndexMarks(), + Equals(std::vector{8000, 12000})); } int main(int argc, const char* argv[]) @@ -85,5 +94,6 @@ int main(int argc, const char* argv[]) test_read_pulses(); test_read_indices(); test_read_desyncs(); + test_index_marks(); return 0; }