mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Merge.
This commit is contained in:
@@ -57,10 +57,10 @@ std::unique_ptr<AbstractDecoder> AbstractDecoder::create(const DecoderProto& con
|
|||||||
return (decoder->second)(config);
|
return (decoder->second)(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<TrackDataFlux> AbstractDecoder::decodeToSectors(
|
std::shared_ptr<TrackDataFlux> AbstractDecoder::decodeToSectors(
|
||||||
std::shared_ptr<const Fluxmap> fluxmap, unsigned physicalCylinder, unsigned physicalHead)
|
std::shared_ptr<const Fluxmap> fluxmap, unsigned physicalCylinder, unsigned physicalHead)
|
||||||
{
|
{
|
||||||
_trackdata = std::make_unique<TrackDataFlux>();
|
_trackdata = std::make_shared<TrackDataFlux>();
|
||||||
_trackdata->fluxmap = fluxmap;
|
_trackdata->fluxmap = fluxmap;
|
||||||
_trackdata->physicalCylinder = physicalCylinder;
|
_trackdata->physicalCylinder = physicalCylinder;
|
||||||
_trackdata->physicalHead = physicalHead;
|
_trackdata->physicalHead = physicalHead;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<TrackDataFlux> decodeToSectors(std::shared_ptr<const Fluxmap> fluxmap, unsigned cylinder, unsigned head);
|
std::shared_ptr<TrackDataFlux> decodeToSectors(std::shared_ptr<const Fluxmap> fluxmap, unsigned cylinder, unsigned head);
|
||||||
void pushRecord(const Fluxmap::Position& start, const Fluxmap::Position& end);
|
void pushRecord(const Fluxmap::Position& start, const Fluxmap::Position& end);
|
||||||
|
|
||||||
void resetFluxDecoder();
|
void resetFluxDecoder();
|
||||||
@@ -82,7 +82,7 @@ protected:
|
|||||||
virtual void decodeDataRecord() {};
|
virtual void decodeDataRecord() {};
|
||||||
|
|
||||||
const DecoderProto& _config;
|
const DecoderProto& _config;
|
||||||
std::unique_ptr<TrackDataFlux> _trackdata;
|
std::shared_ptr<TrackDataFlux> _trackdata;
|
||||||
std::shared_ptr<Sector> _sector;
|
std::shared_ptr<Sector> _sector;
|
||||||
std::unique_ptr<FluxDecoder> _decoder;
|
std::unique_ptr<FluxDecoder> _decoder;
|
||||||
std::vector<bool> _recordBits;
|
std::vector<bool> _recordBits;
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ struct TrackFlux
|
|||||||
{
|
{
|
||||||
unsigned physicalCylinder;
|
unsigned physicalCylinder;
|
||||||
unsigned physicalHead;
|
unsigned physicalHead;
|
||||||
std::vector<std::unique_ptr<TrackDataFlux>> trackDatas;
|
std::vector<std::shared_ptr<TrackDataFlux>> trackDatas;
|
||||||
std::set<std::shared_ptr<Sector>> sectors;
|
std::set<std::shared_ptr<Sector>> sectors;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DiskFlux
|
struct DiskFlux
|
||||||
{
|
{
|
||||||
std::vector<std::unique_ptr<TrackFlux>> tracks;
|
std::vector<std::shared_ptr<TrackFlux>> tracks;
|
||||||
std::unique_ptr<Image> image;
|
std::unique_ptr<Image> image;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "flags.h"
|
#include "flags.h"
|
||||||
#include "fluxmap.h"
|
#include "fluxmap.h"
|
||||||
|
#include "logger.h"
|
||||||
#include "usb/usb.h"
|
#include "usb/usb.h"
|
||||||
#include "fluxsink/fluxsink.h"
|
#include "fluxsink/fluxsink.h"
|
||||||
#include "lib/fluxsink/fluxsink.pb.h"
|
#include "lib/fluxsink/fluxsink.pb.h"
|
||||||
@@ -14,22 +15,22 @@ public:
|
|||||||
{
|
{
|
||||||
if (config.has_hard_sector_count())
|
if (config.has_hard_sector_count())
|
||||||
{
|
{
|
||||||
int rotationalSpeedMs;
|
nanoseconds_t oneRevolution;
|
||||||
int retries = 5;
|
int retries = 5;
|
||||||
usbSetDrive(_config.drive(), _config.high_density(), _config.index_mode());
|
usbSetDrive(_config.drive(), _config.high_density(), _config.index_mode());
|
||||||
std::cout << "Measuring rotational speed... " << std::flush;
|
Logger() << BeginSpeedOperationLogMessage();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
nanoseconds_t oneRevolution = usbGetRotationalPeriod(_config.hard_sector_count());
|
oneRevolution = usbGetRotationalPeriod(_config.hard_sector_count());
|
||||||
_hardSectorThreshold = oneRevolution * 3 / (4 * _config.hard_sector_count());
|
_hardSectorThreshold = oneRevolution * 3 / (4 * _config.hard_sector_count());
|
||||||
rotationalSpeedMs = oneRevolution / 1e6;
|
|
||||||
retries--;
|
retries--;
|
||||||
} while ((rotationalSpeedMs == 0) && (retries > 0));
|
} while ((oneRevolution == 0) && (retries > 0));
|
||||||
|
|
||||||
if (rotationalSpeedMs == 0) {
|
if (oneRevolution == 0) {
|
||||||
Error() << "Failed\nIs a disk in the drive?";
|
Error() << "Failed\nIs a disk in the drive?";
|
||||||
}
|
}
|
||||||
std::cout << fmt::format("{}ms\n", rotationalSpeedMs);
|
|
||||||
|
Logger() << EndSpeedOperationLogMessage(oneRevolution);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_hardSectorThreshold = 0;
|
_hardSectorThreshold = 0;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "flags.h"
|
#include "flags.h"
|
||||||
#include "fluxmap.h"
|
#include "fluxmap.h"
|
||||||
|
#include "logger.h"
|
||||||
#include "usb/usb.h"
|
#include "usb/usb.h"
|
||||||
#include "fluxsource/fluxsource.h"
|
#include "fluxsource/fluxsource.h"
|
||||||
#include "lib/fluxsource/fluxsource.pb.h"
|
#include "lib/fluxsource/fluxsource.pb.h"
|
||||||
@@ -12,10 +13,9 @@ public:
|
|||||||
HardwareFluxSource(const HardwareFluxSourceProto& config):
|
HardwareFluxSource(const HardwareFluxSourceProto& config):
|
||||||
_config(config)
|
_config(config)
|
||||||
{
|
{
|
||||||
int rotationalSpeedMs;
|
|
||||||
int retries = 5;
|
int retries = 5;
|
||||||
usbSetDrive(_config.drive(), _config.high_density(), _config.index_mode());
|
usbSetDrive(_config.drive(), _config.high_density(), _config.index_mode());
|
||||||
std::cout << "Measuring rotational speed... " << std::flush;
|
Logger() << BeginSpeedOperationLogMessage();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
_oneRevolution = usbGetRotationalPeriod(_config.hard_sector_count());
|
_oneRevolution = usbGetRotationalPeriod(_config.hard_sector_count());
|
||||||
@@ -24,15 +24,14 @@ public:
|
|||||||
else
|
else
|
||||||
_hardSectorThreshold = 0;
|
_hardSectorThreshold = 0;
|
||||||
|
|
||||||
rotationalSpeedMs = _oneRevolution / 1e6;
|
|
||||||
retries--;
|
retries--;
|
||||||
} while ((rotationalSpeedMs == 0) && (retries > 0));
|
} while ((_oneRevolution == 0) && (retries > 0));
|
||||||
|
|
||||||
if (rotationalSpeedMs == 0) {
|
if (_oneRevolution == 0) {
|
||||||
Error() << "Failed\nIs a disk in the drive?";
|
Error() << "Failed\nIs a disk in the drive?";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << fmt::format("{}ms\n", rotationalSpeedMs);
|
Logger() << EndSpeedOperationLogMessage(_oneRevolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
~HardwareFluxSource()
|
~HardwareFluxSource()
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__WIN32__)
|
#if defined(_WIN32) || defined(__WIN32__)
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
|
|||||||
129
lib/logger.cc
Normal file
129
lib/logger.cc
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
#include "globals.h"
|
||||||
|
#include "bytes.h"
|
||||||
|
#include "fluxmap.h"
|
||||||
|
#include "sector.h"
|
||||||
|
#include "flux.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
template <class... Ts>
|
||||||
|
struct overloaded : Ts...
|
||||||
|
{
|
||||||
|
using Ts::operator()...;
|
||||||
|
};
|
||||||
|
template <class... Ts>
|
||||||
|
overloaded(Ts...) -> overloaded<Ts...>;
|
||||||
|
|
||||||
|
static bool indented = false;
|
||||||
|
|
||||||
|
static void indent()
|
||||||
|
{
|
||||||
|
if (!indented)
|
||||||
|
std::cout << " ";
|
||||||
|
indented = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger& Logger::operator<<(std::shared_ptr<AnyLogMessage> message)
|
||||||
|
{
|
||||||
|
std::visit(
|
||||||
|
overloaded{
|
||||||
|
/* Fallback --- do nothing */
|
||||||
|
[](const auto& m)
|
||||||
|
{
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Start measuring the rotational speed */
|
||||||
|
[](const BeginSpeedOperationLogMessage& m)
|
||||||
|
{
|
||||||
|
std::cout << "Measuring rotational speed... " << std::flush;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Finish measuring the rotational speed */
|
||||||
|
[](const EndSpeedOperationLogMessage& m)
|
||||||
|
{
|
||||||
|
std::cout << fmt::format("{:.1f}ms ({:.1f}rpm)\n",
|
||||||
|
m.rotationalPeriod / 1e6,
|
||||||
|
60e9 / m.rotationalPeriod);
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Indicates that we're working on a given cylinder and head */
|
||||||
|
[](const DiskContextLogMessage& m)
|
||||||
|
{
|
||||||
|
std::cout << fmt::format("{:2}.{}: ", m.cylinder, m.head)
|
||||||
|
<< std::flush;
|
||||||
|
indented = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
/* A single read has happened */
|
||||||
|
[](const SingleReadLogMessage& m)
|
||||||
|
{
|
||||||
|
const auto& trackdataflux = m.trackDataFlux;
|
||||||
|
|
||||||
|
indent();
|
||||||
|
std::cout << fmt::format("{} records, {} sectors",
|
||||||
|
trackdataflux->records.size(),
|
||||||
|
trackdataflux->sectors.size());
|
||||||
|
if (trackdataflux->sectors.size() > 0)
|
||||||
|
{
|
||||||
|
nanoseconds_t clock =
|
||||||
|
(*trackdataflux->sectors.begin())->clock;
|
||||||
|
std::cout << fmt::format("; {:.2f}us clock ({:.0f}kHz)",
|
||||||
|
clock / 1000.0,
|
||||||
|
1000000.0 / clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << '\n';
|
||||||
|
|
||||||
|
indent();
|
||||||
|
std::cout << "sectors:";
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Sector>> sectors(m.sectors.begin(), m.sectors.end());
|
||||||
|
std::sort(sectors.begin(), sectors.end(),
|
||||||
|
[](const std::shared_ptr<Sector>& s1, const std::shared_ptr<Sector>&s2)
|
||||||
|
{
|
||||||
|
return s1->logicalSector < s2->logicalSector;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const auto& sector : sectors)
|
||||||
|
std::cout << fmt::format(" {}{}", sector->logicalSector, Sector::statusToChar(sector->status));
|
||||||
|
|
||||||
|
std::cout << '\n';
|
||||||
|
},
|
||||||
|
|
||||||
|
/* We've finished reading a track */
|
||||||
|
[](const TrackReadLogMessage& m)
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
std::set<std::pair<int, int>> track_ids;
|
||||||
|
for (const auto& sector : m.track->sectors)
|
||||||
|
{
|
||||||
|
track_ids.insert(std::make_pair(sector->logicalTrack, sector->logicalSide));
|
||||||
|
size += sector->data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!track_ids.empty())
|
||||||
|
{
|
||||||
|
std::vector<std::string> ids;
|
||||||
|
|
||||||
|
for (const auto& i : track_ids)
|
||||||
|
ids.push_back(fmt::format("{}.{}", i.first, i.second));
|
||||||
|
|
||||||
|
indent();
|
||||||
|
std::cout << fmt::format("logical track {}\n", fmt::join(ids, "; "));
|
||||||
|
}
|
||||||
|
|
||||||
|
indent();
|
||||||
|
std::cout << fmt::format("{} bytes decoded\n", size);
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Generic text message */
|
||||||
|
[](const std::string& s)
|
||||||
|
{
|
||||||
|
indent();
|
||||||
|
std::cout << s << '\n';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
*message);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
64
lib/logger.h
Normal file
64
lib/logger.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#ifndef LOGGER_H
|
||||||
|
#define LOGGER_H
|
||||||
|
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
|
class TrackDataFlux;
|
||||||
|
class TrackFlux;
|
||||||
|
class Sector;
|
||||||
|
|
||||||
|
struct BeginSpeedOperationLogMessage {};
|
||||||
|
struct EndSpeedOperationLogMessage
|
||||||
|
{
|
||||||
|
nanoseconds_t rotationalPeriod;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DiskContextLogMessage
|
||||||
|
{
|
||||||
|
unsigned cylinder;
|
||||||
|
unsigned head;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SingleReadLogMessage
|
||||||
|
{
|
||||||
|
std::shared_ptr<TrackDataFlux> trackDataFlux;
|
||||||
|
std::set<std::shared_ptr<Sector>> sectors;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TrackReadLogMessage
|
||||||
|
{
|
||||||
|
std::shared_ptr<TrackFlux> track;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BeginReadOperationLogMessage { };
|
||||||
|
struct EndReadOperationLogMessage { };
|
||||||
|
struct BeginWriteOperationLogMessage { };
|
||||||
|
struct EndWriteOperationLogMessage { };
|
||||||
|
|
||||||
|
class TrackFlux;
|
||||||
|
|
||||||
|
typedef std::variant<std::string,
|
||||||
|
SingleReadLogMessage,
|
||||||
|
TrackReadLogMessage,
|
||||||
|
DiskContextLogMessage,
|
||||||
|
BeginSpeedOperationLogMessage,
|
||||||
|
EndSpeedOperationLogMessage,
|
||||||
|
BeginReadOperationLogMessage,
|
||||||
|
EndReadOperationLogMessage,
|
||||||
|
BeginWriteOperationLogMessage,
|
||||||
|
EndWriteOperationLogMessage>
|
||||||
|
AnyLogMessage;
|
||||||
|
|
||||||
|
class Logger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Logger& operator<<(std::shared_ptr<AnyLogMessage> message);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Logger& operator<<(const T& message)
|
||||||
|
{
|
||||||
|
return *this << std::make_shared<AnyLogMessage>(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "flux.h"
|
#include "flux.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "imagewriter/imagewriter.h"
|
#include "imagewriter/imagewriter.h"
|
||||||
|
#include "logger.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "lib/decoders/decoders.pb.h"
|
#include "lib/decoders/decoders.pb.h"
|
||||||
@@ -22,13 +23,12 @@ static std::unique_ptr<FluxSink> outputFluxSink;
|
|||||||
|
|
||||||
static std::shared_ptr<Fluxmap> readFluxmap(FluxSource& fluxsource, unsigned cylinder, unsigned head)
|
static std::shared_ptr<Fluxmap> readFluxmap(FluxSource& fluxsource, unsigned cylinder, unsigned head)
|
||||||
{
|
{
|
||||||
std::cout << fmt::format("{0:>3}.{1}: ", cylinder, head) << std::flush;
|
Logger() << DiskContextLogMessage { cylinder, head }
|
||||||
|
<< BeginReadOperationLogMessage();
|
||||||
std::shared_ptr<Fluxmap> fluxmap = fluxsource.readFlux(cylinder, head);
|
std::shared_ptr<Fluxmap> fluxmap = fluxsource.readFlux(cylinder, head);
|
||||||
fluxmap->rescale(1.0/config.flux_source().rescale());
|
fluxmap->rescale(1.0/config.flux_source().rescale());
|
||||||
std::cout << fmt::format(
|
Logger() << EndReadOperationLogMessage()
|
||||||
"{0:.0} ms in {1} bytes\n",
|
<< fmt::format("{0:.0} ms in {1} bytes", fluxmap->duration()/1e6, fluxmap->bytes());
|
||||||
fluxmap->duration()/1e6,
|
|
||||||
fluxmap->bytes());
|
|
||||||
return fluxmap;
|
return fluxmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,8 +50,7 @@ static std::set<std::shared_ptr<Sector>> collect_sectors(std::set<std::shared_pt
|
|||||||
{
|
{
|
||||||
if (replacement->data != replacing->data)
|
if (replacement->data != replacing->data)
|
||||||
{
|
{
|
||||||
std::cout << fmt::format(
|
Logger() << fmt::format("multiple conflicting copies of sector {} seen",
|
||||||
"\n multiple conflicting copies of sector {} seen; ",
|
|
||||||
std::get<2>(sectorid));
|
std::get<2>(sectorid));
|
||||||
replacing->status = replacement->status = Sector::CONFLICT;
|
replacing->status = replacement->status = Sector::CONFLICT;
|
||||||
}
|
}
|
||||||
@@ -77,7 +76,7 @@ void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWrit
|
|||||||
{
|
{
|
||||||
for (int head : iterate(config.heads()))
|
for (int head : iterate(config.heads()))
|
||||||
{
|
{
|
||||||
auto track = std::make_unique<TrackFlux>();
|
auto track = std::make_shared<TrackFlux>();
|
||||||
std::set<std::shared_ptr<Sector>> track_sectors;
|
std::set<std::shared_ptr<Sector>> track_sectors;
|
||||||
std::set<std::shared_ptr<Record>> track_records;
|
std::set<std::shared_ptr<Record>> track_records;
|
||||||
Fluxmap totalFlux;
|
Fluxmap totalFlux;
|
||||||
@@ -87,65 +86,49 @@ void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWrit
|
|||||||
auto fluxmap = readFluxmap(fluxsource, cylinder, head);
|
auto fluxmap = readFluxmap(fluxsource, cylinder, head);
|
||||||
totalFlux.appendDesync().appendBytes(fluxmap->rawBytes());
|
totalFlux.appendDesync().appendBytes(fluxmap->rawBytes());
|
||||||
|
|
||||||
{
|
auto trackdataflux = decoder.decodeToSectors(fluxmap, cylinder, head);
|
||||||
auto trackdata = decoder.decodeToSectors(fluxmap, cylinder, head);
|
track->trackDatas.push_back(trackdataflux);
|
||||||
|
|
||||||
std::cout << " ";
|
track_sectors.insert(trackdataflux->sectors.begin(), trackdataflux->sectors.end());
|
||||||
std::cout << fmt::format("{} records, {} sectors; ",
|
track_records.insert(trackdataflux->records.begin(), trackdataflux->records.end());
|
||||||
trackdata->records.size(),
|
|
||||||
trackdata->sectors.size());
|
|
||||||
if (trackdata->sectors.size() > 0)
|
|
||||||
{
|
|
||||||
nanoseconds_t clock = (*trackdata->sectors.begin())->clock;
|
|
||||||
std::cout << fmt::format("{:.2f}us clock ({:.0f}kHz); ",
|
|
||||||
clock / 1000.0, 1000000.0 / clock);
|
|
||||||
}
|
|
||||||
|
|
||||||
track_sectors.insert(trackdata->sectors.begin(), trackdata->sectors.end());
|
|
||||||
track_records.insert(trackdata->records.begin(), trackdata->records.end());
|
|
||||||
track->trackDatas.push_back(std::move(trackdata));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto collected_sectors = collect_sectors(track_sectors);
|
auto collected_sectors = collect_sectors(track_sectors);
|
||||||
std::cout << fmt::format("{} distinct sectors; ", collected_sectors.size());
|
|
||||||
|
|
||||||
bool hasBadSectors = false;
|
bool hasBadSectors = false;
|
||||||
std::set<unsigned> required_sectors = decoder.requiredSectors(cylinder, head);
|
std::set<unsigned> required_sectors = decoder.requiredSectors(cylinder, head);
|
||||||
|
std::set<std::shared_ptr<Sector>> result_sectors;
|
||||||
for (const auto& sector : collected_sectors)
|
for (const auto& sector : collected_sectors)
|
||||||
{
|
{
|
||||||
|
result_sectors.insert(sector);
|
||||||
required_sectors.erase(sector->logicalSector);
|
required_sectors.erase(sector->logicalSector);
|
||||||
|
|
||||||
if (sector->status != Sector::OK)
|
if (sector->status != Sector::OK)
|
||||||
{
|
|
||||||
std::cout << std::endl
|
|
||||||
<< " Failed to read sector " << sector->logicalSector
|
|
||||||
<< " (" << Sector::statusToString(sector->status) << "); ";
|
|
||||||
hasBadSectors = true;
|
hasBadSectors = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (unsigned logical_sector : required_sectors)
|
for (unsigned logical_sector : required_sectors)
|
||||||
{
|
{
|
||||||
std::cout << "\n"
|
auto sector = std::make_shared<Sector>();
|
||||||
<< " Required sector " << logical_sector << " missing; ";
|
sector->logicalSector = logical_sector;
|
||||||
|
sector->status = Sector::MISSING;
|
||||||
|
result_sectors.insert(sector);
|
||||||
|
|
||||||
hasBadSectors = true;
|
hasBadSectors = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger() << SingleReadLogMessage { trackdataflux, result_sectors };
|
||||||
|
|
||||||
if (hasBadSectors)
|
if (hasBadSectors)
|
||||||
failures = false;
|
failures = false;
|
||||||
|
|
||||||
std::cout << std::endl
|
|
||||||
<< " ";
|
|
||||||
|
|
||||||
if (!hasBadSectors)
|
if (!hasBadSectors)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!fluxsource.retryable())
|
if (!fluxsource.retryable())
|
||||||
break;
|
break;
|
||||||
if (retry == 0)
|
if (retry == 0)
|
||||||
std::cout << "giving up" << std::endl
|
Logger() << fmt::format("giving up");
|
||||||
<< " ";
|
|
||||||
else
|
else
|
||||||
std::cout << retry << " retries remaining" << std::endl;
|
Logger() << fmt::format("retrying; {} retries remaining", retry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outputFluxSink)
|
if (outputFluxSink)
|
||||||
@@ -181,24 +164,9 @@ void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWrit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int size = 0;
|
|
||||||
std::set<std::pair<int, int>> track_ids;
|
|
||||||
for (const auto& sector : track_sectors)
|
|
||||||
{
|
|
||||||
track_ids.insert(std::make_pair(sector->logicalTrack, sector->logicalSide));
|
|
||||||
size += sector->data.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!track_ids.empty())
|
|
||||||
{
|
|
||||||
std::cout << "logical track ";
|
|
||||||
for (const auto& i : track_ids)
|
|
||||||
std::cout << fmt::format("{}.{}; ", i.first, i.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << size << " bytes decoded." << std::endl;
|
|
||||||
track->sectors = collect_sectors(track_sectors);
|
track->sectors = collect_sectors(track_sectors);
|
||||||
diskflux->tracks.push_back(std::move(track));
|
Logger() << TrackReadLogMessage { track };
|
||||||
|
diskflux->tracks.push_back(track);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include "sector.h"
|
#include "sector.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
|
||||||
const std::string Sector::statusToString(Status status)
|
std::string Sector::statusToString(Status status)
|
||||||
{
|
{
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
@@ -15,6 +15,19 @@ const std::string Sector::statusToString(Status status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Sector::Status Sector::stringToStatus(const std::string& value)
|
Sector::Status Sector::stringToStatus(const std::string& value)
|
||||||
{
|
{
|
||||||
if (value == "OK")
|
if (value == "OK")
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ public:
|
|||||||
INTERNAL_ERROR
|
INTERNAL_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::string statusToString(Status status);
|
static std::string statusToString(Status status);
|
||||||
|
static std::string statusToChar(Status status);
|
||||||
static Status stringToStatus(const std::string& value);
|
static Status stringToStatus(const std::string& value);
|
||||||
|
|
||||||
Status status = Status::INTERNAL_ERROR;
|
Status status = Status::INTERNAL_ERROR;
|
||||||
|
|||||||
251
lib/writer.cc
251
lib/writer.cc
@@ -12,144 +12,177 @@
|
|||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "sector.h"
|
#include "sector.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
|
#include "logger.h"
|
||||||
#include "lib/config.pb.h"
|
#include "lib/config.pb.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
|
|
||||||
void writeTracks(
|
void writeTracks(FluxSink& fluxSink,
|
||||||
FluxSink& fluxSink,
|
const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer)
|
||||||
const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer)
|
|
||||||
{
|
{
|
||||||
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}: writing", cylinder, head)
|
||||||
|
<< BeginWriteOperationLogMessage();
|
||||||
|
|
||||||
for (unsigned cylinder : iterate(config.cylinders()))
|
std::unique_ptr<Fluxmap> fluxmap = producer(cylinder, head);
|
||||||
{
|
if (!fluxmap)
|
||||||
for (unsigned head : iterate(config.heads()))
|
{
|
||||||
{
|
/* Erase this track rather than writing. */
|
||||||
std::cout << fmt::format("{0:>3}.{1}: ", cylinder, head) << std::flush;
|
|
||||||
std::unique_ptr<Fluxmap> fluxmap = producer(cylinder, head);
|
|
||||||
if (!fluxmap)
|
|
||||||
{
|
|
||||||
/* Erase this track rather than writing. */
|
|
||||||
|
|
||||||
fluxmap.reset(new Fluxmap());
|
fluxmap.reset(new Fluxmap());
|
||||||
fluxSink.writeFlux(cylinder, head, *fluxmap);
|
fluxSink.writeFlux(cylinder, head, *fluxmap);
|
||||||
std::cout << "erased\n";
|
Logger() << "erased";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fluxmap->rescale(config.flux_sink().rescale());
|
fluxmap->rescale(config.flux_sink().rescale());
|
||||||
/* Precompensation actually seems to make things worse, so let's leave
|
/* Precompensation actually seems to make things worse, so let's
|
||||||
* it disabled for now. */
|
* leave it disabled for now. */
|
||||||
//fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS, 2);
|
// fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS, 2);
|
||||||
fluxSink.writeFlux(cylinder, head, *fluxmap);
|
fluxSink.writeFlux(cylinder, head, *fluxmap);
|
||||||
std::cout << fmt::format(
|
Logger() << fmt::format("{0} ms in {1} bytes",
|
||||||
"{0} ms in {1} bytes", int(fluxmap->duration()/1e6), fluxmap->bytes()) << std::endl;
|
int(fluxmap->duration() / 1e6),
|
||||||
}
|
fluxmap->bytes());
|
||||||
}
|
}
|
||||||
|
Logger() << EndWriteOperationLogMessage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeTracksAndVerify(
|
void writeTracksAndVerify(FluxSink& fluxSink,
|
||||||
FluxSink& fluxSink,
|
AbstractEncoder& encoder,
|
||||||
AbstractEncoder& encoder,
|
FluxSource& fluxSource,
|
||||||
FluxSource& fluxSource,
|
AbstractDecoder& decoder,
|
||||||
AbstractDecoder& decoder,
|
const Image& image)
|
||||||
const Image& image)
|
|
||||||
{
|
{
|
||||||
std::cout << "Writing to: " << fluxSink << std::endl;
|
std::cout << "Writing to: " << fluxSink << std::endl;
|
||||||
|
|
||||||
for (unsigned cylinder : iterate(config.cylinders()))
|
for (unsigned cylinder : iterate(config.cylinders()))
|
||||||
{
|
{
|
||||||
for (unsigned head : iterate(config.heads()))
|
for (unsigned head : iterate(config.heads()))
|
||||||
{
|
{
|
||||||
std::cout << fmt::format("{0:>3}.{1}: Write: ", cylinder, head) << std::flush;
|
Logger() << DiskContextLogMessage { cylinder, head }
|
||||||
auto sectors = encoder.collectSectors(cylinder, head, image);
|
<< fmt::format("{0:>3}.{1}", cylinder, head);
|
||||||
std::unique_ptr<Fluxmap> fluxmap = encoder.encode(cylinder, head, sectors, image);
|
|
||||||
if (!fluxmap)
|
|
||||||
{
|
|
||||||
/* Erase this track rather than writing. */
|
|
||||||
|
|
||||||
fluxmap.reset(new Fluxmap());
|
auto sectors = encoder.collectSectors(cylinder, head, image);
|
||||||
fluxSink.writeFlux(cylinder, head, *fluxmap);
|
std::unique_ptr<Fluxmap> fluxmap =
|
||||||
std::cout << "erased\n";
|
encoder.encode(cylinder, head, sectors, image);
|
||||||
}
|
if (!fluxmap)
|
||||||
else
|
{
|
||||||
{
|
/* Erase this track rather than writing. */
|
||||||
fluxmap->rescale(config.flux_sink().rescale());
|
|
||||||
std::sort(sectors.begin(), sectors.end(), sectorPointerSortPredicate);
|
|
||||||
|
|
||||||
for (int retry = 0;; retry++)
|
Logger() << BeginWriteOperationLogMessage() << "erasing";
|
||||||
{
|
fluxmap.reset(new Fluxmap());
|
||||||
/* Precompensation actually seems to make things worse, so let's leave
|
fluxSink.writeFlux(cylinder, head, *fluxmap);
|
||||||
* it disabled for now. */
|
Logger() << EndWriteOperationLogMessage();
|
||||||
//fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS, 2);
|
}
|
||||||
fluxSink.writeFlux(cylinder, head, *fluxmap);
|
else
|
||||||
std::cout << fmt::format(
|
{
|
||||||
"{0} ms in {1} bytes\n", int(fluxmap->duration()/1e6), fluxmap->bytes());
|
fluxmap->rescale(config.flux_sink().rescale());
|
||||||
|
std::sort(
|
||||||
|
sectors.begin(), sectors.end(), sectorPointerSortPredicate);
|
||||||
|
|
||||||
std::cout << fmt::format(" Verify: ", cylinder, head) << std::flush;
|
for (int retry = 0;; retry++)
|
||||||
std::shared_ptr<Fluxmap> writtenFluxmap = fluxSource.readFlux(cylinder, head);
|
{
|
||||||
std::cout << fmt::format(
|
/* Precompensation actually seems to make things worse, so
|
||||||
"{0} ms in {1} bytes\n", int(writtenFluxmap->duration()/1e6), writtenFluxmap->bytes());
|
* let's leave it disabled for now. */
|
||||||
const auto trackdata = decoder.decodeToSectors(writtenFluxmap, cylinder, head);
|
// 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());
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Sector>> gotSectors = trackdata->sectors;
|
Logger() << "verifying" << BeginReadOperationLogMessage();
|
||||||
gotSectors.erase(std::remove_if(gotSectors.begin(), gotSectors.end(),
|
std::shared_ptr<Fluxmap> writtenFluxmap =
|
||||||
[](const auto& s) { return s->status != Sector::OK; }), gotSectors.end());
|
fluxSource.readFlux(cylinder, head);
|
||||||
std::sort(gotSectors.begin(), gotSectors.end(), sectorPointerSortPredicate);
|
Logger() << EndReadOperationLogMessage()
|
||||||
gotSectors.erase(std::unique(gotSectors.begin(), gotSectors.end(),
|
<< fmt::format("{0} ms in {1} bytes",
|
||||||
sectorPointerEqualsPredicate), gotSectors.end());
|
int(writtenFluxmap->duration() / 1e6),
|
||||||
|
writtenFluxmap->bytes());
|
||||||
|
|
||||||
if (std::equal(gotSectors.begin(), gotSectors.end(), sectors.begin(), sectors.end(),
|
const auto trackdata =
|
||||||
sectorPointerEqualsPredicate))
|
decoder.decodeToSectors(writtenFluxmap, cylinder, head);
|
||||||
break;
|
|
||||||
|
|
||||||
if (retry == config.decoder().retries())
|
std::vector<std::shared_ptr<Sector>> gotSectors =
|
||||||
Error() << "Write failed; uncorrectable error during write.";
|
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());
|
||||||
|
|
||||||
std::cout << fmt::format(" Rewrite: ", cylinder, head) << std::flush;
|
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,
|
void fillBitmapTo(std::vector<bool>& bitmap,
|
||||||
unsigned& cursor, unsigned terminateAt,
|
unsigned& cursor,
|
||||||
const std::vector<bool>& pattern)
|
unsigned terminateAt,
|
||||||
|
const std::vector<bool>& pattern)
|
||||||
{
|
{
|
||||||
while (cursor < terminateAt)
|
while (cursor < terminateAt)
|
||||||
{
|
{
|
||||||
for (bool b : pattern)
|
for (bool b : pattern)
|
||||||
{
|
{
|
||||||
if (cursor < bitmap.size())
|
if (cursor < bitmap.size())
|
||||||
bitmap[cursor++] = b;
|
bitmap[cursor++] = b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeDiskCommand(const Image& image, AbstractEncoder& encoder, FluxSink& fluxSink,
|
void writeDiskCommand(const Image& image,
|
||||||
AbstractDecoder* decoder, FluxSource* fluxSource)
|
AbstractEncoder& encoder,
|
||||||
|
FluxSink& fluxSink,
|
||||||
|
AbstractDecoder* decoder,
|
||||||
|
FluxSource* fluxSource)
|
||||||
{
|
{
|
||||||
if (fluxSource && decoder)
|
if (fluxSource && decoder)
|
||||||
writeTracksAndVerify(fluxSink, encoder, *fluxSource, *decoder, image);
|
writeTracksAndVerify(fluxSink, encoder, *fluxSource, *decoder, image);
|
||||||
else
|
else
|
||||||
writeTracks(fluxSink,
|
writeTracks(fluxSink,
|
||||||
[&](int physicalTrack, int physicalSide) -> std::unique_ptr<Fluxmap>
|
[&](int physicalTrack, int physicalSide) -> std::unique_ptr<Fluxmap>
|
||||||
{
|
{
|
||||||
const auto& sectors = encoder.collectSectors(physicalTrack, physicalSide, image);
|
const auto& sectors =
|
||||||
return encoder.encode(physicalTrack, physicalSide, sectors, image);
|
encoder.collectSectors(physicalTrack, physicalSide, image);
|
||||||
}
|
return encoder.encode(
|
||||||
);
|
physicalTrack, physicalSide, sectors, image);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeRawDiskCommand(FluxSource& fluxSource, FluxSink& fluxSink)
|
void writeRawDiskCommand(FluxSource& fluxSource, FluxSink& fluxSink)
|
||||||
{
|
{
|
||||||
writeTracks(fluxSink,
|
writeTracks(fluxSink,
|
||||||
[&](int track, int side) -> std::unique_ptr<Fluxmap>
|
[&](int track, int side) -> std::unique_ptr<Fluxmap>
|
||||||
{
|
{
|
||||||
return fluxSource.readFlux(track, side);
|
return fluxSource.readFlux(track, side);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -472,6 +472,7 @@ buildlibrary libbackend.a \
|
|||||||
lib/imagewriter/rawimagewriter.cc \
|
lib/imagewriter/rawimagewriter.cc \
|
||||||
lib/imginputoutpututils.cc \
|
lib/imginputoutpututils.cc \
|
||||||
lib/ldbs.cc \
|
lib/ldbs.cc \
|
||||||
|
lib/logger.cc \
|
||||||
lib/proto.cc \
|
lib/proto.cc \
|
||||||
lib/reader.cc \
|
lib/reader.cc \
|
||||||
lib/sector.cc \
|
lib/sector.cc \
|
||||||
|
|||||||
Reference in New Issue
Block a user