mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
189 lines
7.0 KiB
C++
189 lines
7.0 KiB
C++
#include "globals.h"
|
|
#include "flags.h"
|
|
#include "fluxmap.h"
|
|
#include "writer.h"
|
|
#include "protocol.h"
|
|
#include "usb/usb.h"
|
|
#include "encoders/encoders.h"
|
|
#include "decoders/decoders.h"
|
|
#include "fluxsource/fluxsource.h"
|
|
#include "fluxsink/fluxsink.h"
|
|
#include "imagereader/imagereader.h"
|
|
#include "fmt/format.h"
|
|
#include "sector.h"
|
|
#include "image.h"
|
|
#include "logger.h"
|
|
#include "lib/config.pb.h"
|
|
#include "proto.h"
|
|
|
|
void writeTracks(FluxSink& fluxSink,
|
|
const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer)
|
|
{
|
|
for (unsigned cylinder : iterate(config.cylinders()))
|
|
{
|
|
for (unsigned head : iterate(config.heads()))
|
|
{
|
|
Logger() << DiskContextLogMessage(cylinder, head)
|
|
<< fmt::format("{0:>3}.{1}: writing", cylinder, head)
|
|
<< BeginWriteOperationLogMessage();
|
|
|
|
std::unique_ptr<Fluxmap> fluxmap = producer(cylinder, head);
|
|
if (!fluxmap)
|
|
{
|
|
/* Erase this track rather than writing. */
|
|
|
|
fluxmap.reset(new Fluxmap());
|
|
fluxSink.writeFlux(cylinder, head, *fluxmap);
|
|
Logger() << "erased";
|
|
}
|
|
else
|
|
{
|
|
fluxmap->rescale(config.flux_sink().rescale());
|
|
/* Precompensation actually seems to make things worse, so let's
|
|
* leave it disabled for now. */
|
|
// fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS, 2);
|
|
fluxSink.writeFlux(cylinder, head, *fluxmap);
|
|
Logger() << fmt::format("{0} ms in {1} bytes",
|
|
int(fluxmap->duration() / 1e6),
|
|
fluxmap->bytes());
|
|
}
|
|
Logger() << EndWriteOperationLogMessage();
|
|
}
|
|
}
|
|
}
|
|
|
|
void writeTracksAndVerify(FluxSink& fluxSink,
|
|
AbstractEncoder& encoder,
|
|
FluxSource& fluxSource,
|
|
AbstractDecoder& decoder,
|
|
const Image& image)
|
|
{
|
|
std::cout << "Writing to: " << fluxSink << std::endl;
|
|
|
|
for (unsigned cylinder : iterate(config.cylinders()))
|
|
{
|
|
for (unsigned head : iterate(config.heads()))
|
|
{
|
|
Logger() << DiskContextLogMessage { cylinder, head }
|
|
<< fmt::format("{0:>3}.{1}", cylinder, head);
|
|
|
|
auto sectors = encoder.collectSectors(cylinder, head, image);
|
|
std::unique_ptr<Fluxmap> fluxmap =
|
|
encoder.encode(cylinder, head, sectors, image);
|
|
if (!fluxmap)
|
|
{
|
|
/* Erase this track rather than writing. */
|
|
|
|
Logger() << BeginWriteOperationLogMessage() << "erasing";
|
|
fluxmap.reset(new Fluxmap());
|
|
fluxSink.writeFlux(cylinder, head, *fluxmap);
|
|
Logger() << EndWriteOperationLogMessage();
|
|
}
|
|
else
|
|
{
|
|
fluxmap->rescale(config.flux_sink().rescale());
|
|
std::sort(
|
|
sectors.begin(), sectors.end(), sectorPointerSortPredicate);
|
|
|
|
for (int retry = 0;; retry++)
|
|
{
|
|
/* Precompensation actually seems to make things worse, so
|
|
* let's leave it disabled for now. */
|
|
// fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS,
|
|
// 2);
|
|
Logger() << BeginWriteOperationLogMessage() << "writing";
|
|
fluxSink.writeFlux(cylinder, head, *fluxmap);
|
|
Logger() << EndWriteOperationLogMessage()
|
|
<< fmt::format("{0} ms in {1} bytes",
|
|
int(fluxmap->duration() / 1e6),
|
|
fluxmap->bytes());
|
|
|
|
Logger() << "verifying" << BeginReadOperationLogMessage();
|
|
std::shared_ptr<Fluxmap> writtenFluxmap =
|
|
fluxSource.readFlux(cylinder, head);
|
|
Logger() << EndReadOperationLogMessage()
|
|
<< fmt::format("{0} ms in {1} bytes",
|
|
int(writtenFluxmap->duration() / 1e6),
|
|
writtenFluxmap->bytes());
|
|
|
|
const auto trackdata =
|
|
decoder.decodeToSectors(writtenFluxmap, cylinder, head);
|
|
|
|
std::vector<std::shared_ptr<Sector>> gotSectors =
|
|
trackdata->sectors;
|
|
gotSectors.erase(std::remove_if(gotSectors.begin(),
|
|
gotSectors.end(),
|
|
[](const auto& s)
|
|
{
|
|
return s->status != Sector::OK;
|
|
}),
|
|
gotSectors.end());
|
|
std::sort(gotSectors.begin(),
|
|
gotSectors.end(),
|
|
sectorPointerSortPredicate);
|
|
gotSectors.erase(std::unique(gotSectors.begin(),
|
|
gotSectors.end(),
|
|
sectorPointerEqualsPredicate),
|
|
gotSectors.end());
|
|
|
|
if (std::equal(gotSectors.begin(),
|
|
gotSectors.end(),
|
|
sectors.begin(),
|
|
sectors.end(),
|
|
sectorPointerEqualsPredicate))
|
|
break;
|
|
|
|
if (retry == config.decoder().retries())
|
|
Error() << "Write failed; uncorrectable error during "
|
|
"write.";
|
|
|
|
Logger() << "retrying";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void fillBitmapTo(std::vector<bool>& bitmap,
|
|
unsigned& cursor,
|
|
unsigned terminateAt,
|
|
const std::vector<bool>& pattern)
|
|
{
|
|
while (cursor < terminateAt)
|
|
{
|
|
for (bool b : pattern)
|
|
{
|
|
if (cursor < bitmap.size())
|
|
bitmap[cursor++] = b;
|
|
}
|
|
}
|
|
}
|
|
|
|
void writeDiskCommand(const Image& image,
|
|
AbstractEncoder& encoder,
|
|
FluxSink& fluxSink,
|
|
AbstractDecoder* decoder,
|
|
FluxSource* fluxSource)
|
|
{
|
|
if (fluxSource && decoder)
|
|
writeTracksAndVerify(fluxSink, encoder, *fluxSource, *decoder, image);
|
|
else
|
|
writeTracks(fluxSink,
|
|
[&](int physicalTrack, int physicalSide) -> std::unique_ptr<Fluxmap>
|
|
{
|
|
const auto& sectors =
|
|
encoder.collectSectors(physicalTrack, physicalSide, image);
|
|
return encoder.encode(
|
|
physicalTrack, physicalSide, sectors, image);
|
|
});
|
|
}
|
|
|
|
void writeRawDiskCommand(FluxSource& fluxSource, FluxSink& fluxSink)
|
|
{
|
|
writeTracks(fluxSink,
|
|
[&](int track, int side) -> std::unique_ptr<Fluxmap>
|
|
{
|
|
return fluxSource.readFlux(track, side);
|
|
});
|
|
}
|