Added functionality for faking the necessary data in a DecodedDisk to

make the visualiser work. Blank images can now be created in memory.
This commit is contained in:
David Given
2025-10-13 00:19:59 +02:00
parent c2e7f32cba
commit f960c7efd0
20 changed files with 151 additions and 65 deletions

View File

@@ -409,6 +409,7 @@ static ReadGroupResult readGroup(const DiskLayout& diskLayout,
}
void writeTracks(const DiskLayout& diskLayout,
FluxSink& fluxSink,
std::function<std::unique_ptr<const Fluxmap>(
const std::shared_ptr<const LogicalTrackLayout>&)> producer,
@@ -666,31 +667,28 @@ TracksAndSectors readAndDecodeTrack(const DiskLayout& diskLayout,
return fas;
}
void readDiskCommand(
FluxSource& fluxSource, Decoder& decoder, DecodedDisk& decodedDisk)
void readDiskCommand(const DiskLayout& diskLayout,
FluxSource& fluxSource,
Decoder& decoder,
DecodedDisk& decodedDisk)
{
std::unique_ptr<FluxSink> outputFluxSink;
if (globalConfig()->decoder().has_copy_flux_to())
outputFluxSink =
FluxSink::create(globalConfig()->decoder().copy_flux_to());
if (!decodedDisk.layout)
decodedDisk.layout = createDiskLayout();
log(BeginOperationLogMessage{"Reading and decoding disk"});
unsigned index = 0;
for (auto& [logicalLocation, ltl] :
decodedDisk.layout->layoutByLogicalLocation)
for (auto& [logicalLocation, ltl] : diskLayout.layoutByLogicalLocation)
{
log(OperationProgressLogMessage{
index * 100 /
(unsigned)decodedDisk.layout->layoutByLogicalLocation.size()});
index * 100 / (unsigned)diskLayout.layoutByLogicalLocation.size()});
index++;
testForEmergencyStop();
auto [trackFluxes, trackSectors] =
readAndDecodeTrack(*decodedDisk.layout, fluxSource, decoder, ltl);
readAndDecodeTrack(diskLayout, fluxSource, decoder, ltl);
for (const auto& flux : trackFluxes)
decodedDisk.tracksByPhysicalLocation.emplace(
CylinderHead{
@@ -781,11 +779,13 @@ void readDiskCommand(
log(EndOperationLogMessage{"Read complete"});
}
void readDiskCommand(
FluxSource& fluxsource, Decoder& decoder, ImageWriter& writer)
void readDiskCommand(const DiskLayout& diskLayout,
FluxSource& fluxsource,
Decoder& decoder,
ImageWriter& writer)
{
DecodedDisk decodedDisk;
readDiskCommand(fluxsource, decoder, decodedDisk);
readDiskCommand(diskLayout, fluxsource, decoder, decodedDisk);
writer.printMap(*decodedDisk.image);
if (globalConfig()->decoder().has_write_csv_to())

View File

@@ -121,9 +121,13 @@ extern TracksAndSectors readAndDecodeTrack(const DiskLayout& diskLayout,
Decoder& decoder,
const std::shared_ptr<const LogicalTrackLayout>& ltl);
extern void readDiskCommand(
FluxSource& fluxsource, Decoder& decoder, DecodedDisk& diskflux);
extern void readDiskCommand(
FluxSource& source, Decoder& decoder, ImageWriter& writer);
extern void readDiskCommand(const DiskLayout& diskLayout,
FluxSource& fluxsource,
Decoder& decoder,
DecodedDisk& diskflux);
extern void readDiskCommand(const DiskLayout& diskLayout,
FluxSource& source,
Decoder& decoder,
ImageWriter& writer);
#endif

View File

@@ -3,6 +3,7 @@ from build.c import cxxlibrary
cxxlibrary(
name="data",
srcs=[
"./decoded.cc",
"./fluxmap.cc",
"./fluxmapreader.cc",
"./fluxpattern.cc",

View File

@@ -38,7 +38,8 @@ struct DecodedDisk
std::multimap<CylinderHead, std::shared_ptr<const Sector>>
sectorsByPhysicalLocation;
std::shared_ptr<const Image> image;
std::shared_ptr<const DiskLayout> layout;
void populateTrackDataFromImage(const DiskLayout& diskLayout);
};
#endif

View File

@@ -94,3 +94,25 @@ void Image::calculateSize()
}
_geometry.numSectors = maxSector - _geometry.firstSector + 1;
}
void Image::populateSectorPhysicalLocationsFromLogicalLocations(
const DiskLayout& diskLayout)
{
Image tempImage;
for (const auto& sector : *this)
{
const auto& ltl = diskLayout.layoutByLogicalLocation.at(
{sector->logicalCylinder, sector->logicalHead});
auto newSector = tempImage.put(sector->logicalCylinder,
sector->logicalHead,
sector->logicalSector);
*newSector = *sector;
newSector->physicalLocation = std::make_optional<CylinderHead>(
ltl->physicalCylinder, ltl->physicalHead);
}
for (const auto& sector : tempImage)
_sectors[{sector->logicalCylinder,
sector->logicalHead,
sector->logicalSector}] = sector;
}

View File

@@ -106,6 +106,8 @@ public:
}
void addMissingSectors(const DiskLayout& layout, bool populated = false);
void populateSectorPhysicalLocationsFromLogicalLocations(
const DiskLayout& diskLayout);
const_iterator begin() const
{

View File

@@ -20,7 +20,7 @@ std::string Sector::statusToString(Status status)
case Status::CONFLICT:
return "conflicting data";
default:
return fmt::format("unknown error {}", status);
return fmt::format("unknown error {}", (int)status);
}
}

View File

@@ -14,6 +14,7 @@ cxxlibrary(
"./fl2fluxsink.cc",
"./fluxsink.cc",
"./hardwarefluxsink.cc",
"./memoryfluxsink.cc",
"./scpfluxsink.cc",
"./vcdfluxsink.cc",
],

View File

@@ -14,6 +14,7 @@ class VcdFluxSinkProto;
class ScpFluxSinkProto;
class Fl2FluxSinkProto;
class Config;
class DecodedDisk;
class FluxSink
{
@@ -32,6 +33,8 @@ public:
const ScpFluxSinkProto& config);
static std::unique_ptr<FluxSink> createFl2FluxSink(
const Fl2FluxSinkProto& config);
static std::unique_ptr<FluxSink> createMemoryFluxSink(
DecodedDisk& decodedDisk);
static std::unique_ptr<FluxSink> createFl2FluxSink(
const std::string& filename);

View File

@@ -99,8 +99,8 @@ public:
_changedSectors,
*_encoder,
*_fluxSink,
&*_decoder,
&*_fluxSource,
_decoder.get(),
_fluxSource.get(),
locations);
discardChanges();

View File

@@ -41,7 +41,13 @@ public:
void flushChanges() override
{
// _writer->writeImage(*_image);
for (const auto& sector : *_liveImage)
{
const auto& s = _backupImage->put(sector->logicalCylinder,
sector->logicalHead,
sector->logicalSector);
*s = *sector;
}
_changed = false;
}

View File

@@ -305,11 +305,13 @@ void Filesystem::putLogicalSector(uint32_t number, const Bytes& data)
unsigned pos = 0;
while (pos < data.size())
{
auto& [cylinder, head, sectorId] =
const auto& [cylinder, head, sectorId] =
_diskLayout->logicalSectorLocationsInFilesystemOrder.at(number);
auto& ltl = _diskLayout->layoutByLogicalLocation.at({cylinder, head});
_sectors->put(cylinder, head, sectorId)->data =
data.slice(pos, ltl->sectorSize);
const auto& ltl =
_diskLayout->layoutByLogicalLocation.at({cylinder, head});
const auto& sector = _sectors->put(cylinder, head, sectorId);
sector->status = Sector::OK;
sector->data = data.slice(pos, ltl->sectorSize);
pos += ltl->sectorSize;
number++;
}

View File

@@ -225,6 +225,7 @@ public:
public:
Filesystem(const std::shared_ptr<const DiskLayout>& diskLayout,
std::shared_ptr<SectorInterface> sectors);
virtual ~Filesystem() {};
Bytes getSector(unsigned track, unsigned side, unsigned sector);
@@ -238,7 +239,7 @@ public:
void eraseEverythingOnDisk();
protected:
const std::shared_ptr<const DiskLayout>& _diskLayout;
const std::shared_ptr<const DiskLayout> _diskLayout;
unsigned _blockCount;
private:

View File

@@ -5,6 +5,7 @@
#include "lib/data/fluxmap.h"
#include "lib/decoders/decoders.h"
#include "lib/data/sector.h"
#include "lib/data/layout.h"
#include "lib/config/proto.h"
#include "lib/fluxsource/fluxsource.h"
#include "lib/fluxsink/fluxsink.h"
@@ -50,11 +51,12 @@ int mainRead(int argc, const char* argv[])
if (globalConfig()->decoder().copy_flux_to().type() == FLUXTYPE_DRIVE)
error("you cannot copy flux to a hardware device");
auto diskLayout = createDiskLayout(globalConfig());
auto fluxSource = FluxSource::create(globalConfig());
auto decoder = Arch::createDecoder(globalConfig());
auto writer = ImageWriter::create(globalConfig());
readDiskCommand(*fluxSource, *decoder, *writer);
readDiskCommand(*diskLayout, *fluxSource, *decoder, *writer);
return 0;
}

View File

@@ -70,6 +70,7 @@ static void emitOptions(DynamicSetting<std::string>& setting,
if (value)
options[it.name()] = "true";
setting = optionsToString(options);
Datastore::reset();
}
}
}
@@ -146,6 +147,7 @@ static void emitOptions(DynamicSetting<std::string>& setting,
options[it.name()] = ot.name();
}
setting = optionsToString(options);
Datastore::reset();
}
}
}
@@ -183,7 +185,10 @@ static void formatProperties()
label = name;
if (ImGui::Selectable(
fmt::format("{}##{}", label, name).c_str(), false))
{
formatSetting = name;
Datastore::reset();
}
}
}

View File

@@ -130,10 +130,11 @@ void ControlPanelView::drawContent()
"fluxengine.view.controlpanel.rereadBad"_lang,
nullptr,
busy || !diskFlux);
ImGui::TableNextColumn();
ImGui::TableNextRow();
button(ICON_VS_NEW_FILE,
"fluxengine.view.controlpanel.createBlank"_lang,
nullptr,
Datastore::createBlankImage,
busy || !Datastore::canFormat());
}

View File

@@ -12,10 +12,12 @@
#include "lib/fluxsource/fluxsource.h"
#include "lib/fluxsink/fluxsink.h"
#include "lib/decoders/decoders.h"
#include "lib/encoders/encoders.h"
#include "lib/imagewriter/imagewriter.h"
#include "lib/algorithms/readerwriter.h"
#include "lib/usb/usbfinder.h"
#include "lib/vfs/vfs.h"
#include "lib/vfs/sectorinterface.h"
#include "arch/arch.h"
#include "logview.h"
#include "globals.h"
@@ -208,34 +210,31 @@ void Datastore::init()
Events::SeekToSectorViaPhysicalLocation::subscribe(
[](CylinderHeadSector physicalLocation)
{
if (diskLayout)
if (!diskLayout)
return;
auto& ptlo = findOptionally(diskLayout->layoutByPhysicalLocation,
{physicalLocation.cylinder, physicalLocation.head});
if (ptlo.has_value())
{
auto& ptlo =
findOptionally(diskLayout->layoutByPhysicalLocation,
{physicalLocation.cylinder, physicalLocation.head});
if (ptlo.has_value())
{
auto& ptl = *ptlo;
auto offseto = findOptionally(
diskLayout->sectorOffsetByLogicalSectorLocation,
{ptl->logicalTrackLayout->logicalCylinder,
ptl->logicalTrackLayout->logicalHead,
physicalLocation.sector});
if (offseto.has_value())
hex::ImHexApi::HexEditor::setSelection(hex::Region(
*offseto, ptl->logicalTrackLayout->sectorSize));
}
auto& ptl = *ptlo;
auto offseto = findOptionally(
diskLayout->sectorOffsetByLogicalSectorLocation,
{ptl->logicalTrackLayout->logicalCylinder,
ptl->logicalTrackLayout->logicalHead,
physicalLocation.sector});
if (offseto.has_value())
hex::ImHexApi::HexEditor::setSelection(hex::Region(
*offseto, ptl->logicalTrackLayout->sectorSize));
}
});
Events::SeekToTrackViaPhysicalLocation::subscribe(
[](CylinderHead physicalLocation)
{
if (!diskFlux)
if (!diskFlux || !diskLayout)
return;
auto ptlo =
findOptionally(diskFlux->layout->layoutByPhysicalLocation,
{physicalLocation.cylinder, physicalLocation.head});
auto ptlo = findOptionally(diskLayout->layoutByPhysicalLocation,
{physicalLocation.cylinder, physicalLocation.head});
if (!ptlo.has_value())
return;
auto ptl = *ptlo;
@@ -244,10 +243,10 @@ void Datastore::init()
unsigned lastSectorId = ltl->filesystemSectorOrder.back();
unsigned startOffset =
diskFlux->layout->sectorOffsetByLogicalSectorLocation.at(
diskLayout->sectorOffsetByLogicalSectorLocation.at(
{ltl->logicalCylinder, ltl->logicalHead, firstSectorId});
unsigned endOffset =
diskFlux->layout->sectorOffsetByLogicalSectorLocation.at(
diskLayout->sectorOffsetByLogicalSectorLocation.at(
{ltl->logicalCylinder, ltl->logicalHead, lastSectorId}) +
ltl->sectorSize;
@@ -521,7 +520,20 @@ void Datastore::beginRead(void)
auto decoder = Arch::createDecoder(globalConfig());
auto diskflux = std::make_shared<DecodedDisk>();
readDiskCommand(*fluxSource, *decoder, *diskflux);
readDiskCommand(*diskLayout, *fluxSource, *decoder, *diskflux);
});
}
void Datastore::reset()
{
Datastore::runOnWorkerThread(
[]
{
busy = true;
DEFER(busy = false);
wtRebuildConfiguration();
wtWaitForUiThreadToCatchUp();
});
}
@@ -576,7 +588,28 @@ void Datastore::createBlankImage()
ON_SCOPE_EXIT
{
busy = false;
wtRebuildConfiguration();
};
wtRebuildConfiguration();
auto diskflux = std::make_shared<DecodedDisk>();
auto image = std::make_shared<Image>();
std::shared_ptr<SectorInterface> sectorInterface =
SectorInterface::createMemorySectorInterface(image);
auto filesystem = Filesystem::createFilesystem(
globalConfig()->filesystem(), diskLayout, sectorInterface);
filesystem->create(false, "FLUXENGINE");
filesystem->flushChanges();
image->calculateSize();
image->populateSectorPhysicalLocationsFromLogicalLocations(
*diskLayout);
diskflux->image = image;
diskflux->populateTrackDataFromImage(*diskLayout);
hex::TaskManager::doLater(
[=]
{
::diskFlux = diskflux;
});
});
}

View File

@@ -61,20 +61,21 @@ void DiskProvider::close() {}
void DiskProvider::readRaw(u64 offset, void* buffer, size_t size)
{
const auto& diskFlux = Datastore::getDecodedDisk();
if (diskFlux && diskFlux->image)
const auto& diskLayout = Datastore::getDiskLayout();
if (diskFlux && diskFlux->image && diskLayout)
{
while (size != 0)
{
auto it = diskFlux->layout->logicalSectorLocationBySectorOffset
.upper_bound(offset);
if (it !=
diskFlux->layout->logicalSectorLocationBySectorOffset.begin())
auto it =
diskLayout->logicalSectorLocationBySectorOffset.upper_bound(
offset);
if (it != diskLayout->logicalSectorLocationBySectorOffset.begin())
it--;
unsigned realOffset = it->first;
auto logicalLocation = it->second;
auto sector = diskFlux->image->get(logicalLocation);
auto& ltl = diskFlux->layout->layoutByLogicalLocation.at(
auto& ltl = diskLayout->layoutByLogicalLocation.at(
logicalLocation.trackLocation());
unsigned blockOffset = realOffset - offset;
unsigned bytesRemaining =

View File

@@ -25,12 +25,13 @@ DiskLayout::LayoutBounds PhysicalView::getBounds()
std::shared_ptr<const Sector> PhysicalView::getSector(
unsigned physicalCylinder, unsigned physicalHead, unsigned sectorId)
{
auto diskFlux = Datastore::getDecodedDisk();
auto& ptl = findOrDefault(diskFlux->layout->layoutByPhysicalLocation,
{physicalCylinder, physicalHead});
const auto& diskFlux = Datastore::getDecodedDisk();
const auto& diskLayout = Datastore::getDiskLayout();
const auto& ptl = findOrDefault(
diskLayout->layoutByPhysicalLocation, {physicalCylinder, physicalHead});
if (!ptl)
return nullptr;
auto& ltl = ptl->logicalTrackLayout;
const auto& ltl = ptl->logicalTrackLayout;
return diskFlux->image->get(
{ltl->logicalCylinder, ltl->logicalHead, sectorId});
}

View File

@@ -39,7 +39,7 @@
"fluxengine.view.controlpanel.readImage": "Load disk image",
"fluxengine.view.controlpanel.writeImage": "Save disk image",
"fluxengine.view.controlpanel.rereadBad": "Re-read bad tracks",
"fluxengine.view.controlpanel.createBlank": "Format disk",
"fluxengine.view.controlpanel.createBlank": "Empty filesystem",
"fluxengine.view.controlpanel.stop": "Stop",
"fluxengine.view.log.name": "FluxEngine log viewer"