mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Merge.
This commit is contained in:
@@ -2,7 +2,7 @@ FluxEngine
|
||||
==========
|
||||
|
||||
(If you're reading this on GitHub, the formatting's a bit messed up. [Try the
|
||||
version on cowlark.com instead.](http://cowlark.com/fluxengine/)
|
||||
version on cowlark.com instead.](http://cowlark.com/fluxengine/))
|
||||
|
||||
**Breaking news!** As of 2021-05-21, the command line environment has changed
|
||||
_substantially_ (to make it more consistent and flexible, and allow some new
|
||||
@@ -149,7 +149,7 @@ at least, check the CRC so what data's there is probably good.
|
||||
There hasn't been a lot of demand for this yet; if you have a pressing
|
||||
need to write weird disks, [please
|
||||
ask](https://github.com/davidgiven/fluxengine/issues/new). I haven't
|
||||
implement write support for PC disks because they're boring and I'm lazy,
|
||||
implemented write support for PC disks because they're boring and I'm lazy,
|
||||
and also because they vary so much that figuring out how to specify them
|
||||
is hard.
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ static void write_bits(std::vector<bool>& bits, unsigned& cursor, const Bytes& b
|
||||
}
|
||||
}
|
||||
|
||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<Sector>& sector)
|
||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<const Sector>& 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<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
std::vector<std::shared_ptr<const Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
{
|
||||
std::vector<std::shared_ptr<Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
|
||||
if ((physicalTrack >= 0) && (physicalTrack < AMIGA_TRACKS_PER_DISK))
|
||||
{
|
||||
@@ -123,7 +123,7 @@ public:
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
|
||||
const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
|
||||
const std::vector<std::shared_ptr<const Sector>>& sectors, const Image& image) override
|
||||
{
|
||||
if ((physicalTrack < 0) || (physicalTrack >= AMIGA_TRACKS_PER_DISK))
|
||||
return std::unique_ptr<Fluxmap>();
|
||||
|
||||
@@ -109,9 +109,9 @@ public:
|
||||
{}
|
||||
|
||||
public:
|
||||
std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
std::vector<std::shared_ptr<const Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
{
|
||||
std::vector<std::shared_ptr<Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
|
||||
int logicalTrack;
|
||||
if (physicalSide != 0)
|
||||
@@ -144,7 +144,7 @@ public:
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
|
||||
const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
|
||||
const std::vector<std::shared_ptr<const Sector>>& sectors, const Image& image) override
|
||||
{
|
||||
int logicalTrack;
|
||||
if (physicalSide != 0)
|
||||
|
||||
@@ -211,9 +211,9 @@ public:
|
||||
{}
|
||||
|
||||
public:
|
||||
std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
std::vector<std::shared_ptr<const Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
{
|
||||
std::vector<std::shared_ptr<Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
|
||||
if (physicalSide == 0)
|
||||
{
|
||||
@@ -231,7 +231,7 @@ public:
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
|
||||
const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
|
||||
const std::vector<std::shared_ptr<const Sector>>& 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<bool>& bits, unsigned& cursor, const std::shared_ptr<Sector>& sector) const
|
||||
void writeSector(std::vector<bool>& bits, unsigned& cursor, std::shared_ptr<const Sector> 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)
|
||||
|
||||
@@ -123,9 +123,9 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
std::vector<std::shared_ptr<const Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
{
|
||||
std::vector<std::shared_ptr<Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
IbmEncoderProto::TrackdataProto trackdata;
|
||||
getTrackFormat(trackdata, physicalTrack, physicalSide);
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
|
||||
const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
|
||||
const std::vector<std::shared_ptr<const Sector>>& sectors, const Image& image) override
|
||||
{
|
||||
IbmEncoderProto::TrackdataProto trackdata;
|
||||
getTrackFormat(trackdata, physicalTrack, physicalSide);
|
||||
|
||||
@@ -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<bool>& bits, unsigned& cursor, const std::shared_ptr<Sector>& sector)
|
||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<const Sector>& 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<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
std::vector<std::shared_ptr<const Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
{
|
||||
std::vector<std::shared_ptr<Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
|
||||
if ((physicalTrack >= 0) && (physicalTrack < MAC_TRACKS_PER_DISK))
|
||||
{
|
||||
@@ -227,7 +227,7 @@ public:
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
|
||||
const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
|
||||
const std::vector<std::shared_ptr<const Sector>>& sectors, const Image& image) override
|
||||
{
|
||||
if ((physicalTrack < 0) || (physicalTrack >= MAC_TRACKS_PER_DISK))
|
||||
return std::unique_ptr<Fluxmap>();
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "image.h"
|
||||
#include "lib/encoders/encoders.pb.h"
|
||||
|
||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<Sector>& sector)
|
||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<const Sector>& 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<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
std::vector<std::shared_ptr<const Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
{
|
||||
std::vector<std::shared_ptr<Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
|
||||
if ((physicalTrack >= 0) && (physicalTrack < 77))
|
||||
{
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
|
||||
const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
|
||||
const std::vector<std::shared_ptr<const Sector>>& sectors, const Image& image) override
|
||||
{
|
||||
int bitsPerRevolution = 100000;
|
||||
double clockRateUs = 2.00;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#define TOTAL_SECTOR_BYTES ()
|
||||
|
||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<Sector>& sector)
|
||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<const Sector>& sector)
|
||||
{
|
||||
int preambleSize = 0;
|
||||
int encodedSectorSize = 0;
|
||||
@@ -108,9 +108,9 @@ public:
|
||||
_config(config.northstar())
|
||||
{}
|
||||
|
||||
std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
std::vector<std::shared_ptr<const Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
{
|
||||
std::vector<std::shared_ptr<Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
|
||||
if ((physicalTrack >= 0) && (physicalTrack < 35))
|
||||
{
|
||||
@@ -126,7 +126,7 @@ public:
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
|
||||
const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
|
||||
const std::vector<std::shared_ptr<const Sector>>& sectors, const Image& image) override
|
||||
{
|
||||
int bitsPerRevolution = 100000;
|
||||
double clockRateUs = 4.00;
|
||||
|
||||
@@ -59,9 +59,9 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
std::vector<std::shared_ptr<const Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
{
|
||||
std::vector<std::shared_ptr<Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
|
||||
for (char sectorChar : _config.sector_skew())
|
||||
{
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
|
||||
const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
|
||||
const std::vector<std::shared_ptr<const Sector>>& sectors, const Image& image) override
|
||||
{
|
||||
double clockRateUs = 1e3 / _config.clock_rate_khz() / 2.0;
|
||||
int bitsPerRevolution = (_config.track_length_ms() * 1000.0) / clockRateUs;
|
||||
|
||||
@@ -143,9 +143,9 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<std::shared_ptr<Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
std::vector<std::shared_ptr<const Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
{
|
||||
std::vector<std::shared_ptr<Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
|
||||
Victor9kEncoderProto::TrackdataProto trackdata;
|
||||
getTrackFormat(trackdata, physicalTrack, physicalSide);
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
|
||||
const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) override
|
||||
const std::vector<std::shared_ptr<const Sector>>& sectors, const Image& image) override
|
||||
{
|
||||
Victor9kEncoderProto::TrackdataProto trackdata;
|
||||
getTrackFormat(trackdata, physicalTrack, physicalSide);
|
||||
|
||||
@@ -231,7 +231,7 @@ You should now have a working board, so it's time to test it.
|
||||
have a single 3.5" connector, after the twist.)
|
||||
|
||||
If you have **two** drives, plug them into both connectors. FluxEngine,
|
||||
sadly, non-standard disk numbering (there are reasons). Drive 0 is the
|
||||
sadly, uses non-standard disk numbering (there are reasons). Drive 0 is the
|
||||
one nearest the motherboard; that is, before the twist. Drive 1 is the
|
||||
one at the end of the cable; that is, after the twist. Drive 0 is the
|
||||
default. You can tell the client to select drive 1 by using `-s :d=1`.
|
||||
|
||||
@@ -16,8 +16,8 @@ Tested ones are:
|
||||
|
||||
I expect the others to work, but haven't tried them; [get in
|
||||
touch](https://github.com/davidgiven/fluxengine/issues/new) if you have any
|
||||
news. For ADFS S (single sided 40 track) you'll want `--heads 0 --cylinders
|
||||
0-79x2`. For ADFS M (single sided 80 track) you'll want `--heads 0`.
|
||||
news. For ADFS S (single-sided 40 track) you'll want `--heads 0 --cylinders
|
||||
0-79x2`. For ADFS M (single-sided 80 track) you'll want `--heads 0`.
|
||||
|
||||
Be aware that Acorn logical block numbering goes all the way up side 0 and
|
||||
then all the way up side 1. However, FluxEngine uses traditional disk images
|
||||
|
||||
@@ -5,7 +5,7 @@ Acorn DFS disks are pretty standard FM encoded IBM scheme disks, with
|
||||
256-sectors and 0-based sector identifiers. There's nothing particularly
|
||||
special here.
|
||||
|
||||
DFS disks are all single sided, but allow the other side of the disk to be
|
||||
DFS disks are all single-sided, but allow the other side of the disk to be
|
||||
used as another drive. FluxEngine supports these; read one side at a time
|
||||
with `--heads 0` or `--heads 1`.
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ of nearly £50,000 in 2018!).
|
||||
processing software off twin 5.25" drive units, but apparently other software
|
||||
was available.
|
||||
|
||||
The disk format is exceptionally weird. They used 77 track, 32 sector, single
|
||||
sided _hard_ sectored disks, where there were multiple index holes,
|
||||
The disk format is exceptionally weird. They used 77 track, 32 sector, single-sided
|
||||
_hard_ sectored disks, where there were multiple index holes,
|
||||
indicating to the hardware where the sectors start. The encoding scheme
|
||||
itself is [MMFM (aka
|
||||
M2FM)](http://www.retrotechnology.com/herbs_stuff/m2fm.html), an early
|
||||
|
||||
@@ -3,8 +3,8 @@ Disk: Generic IBM
|
||||
|
||||
IBM scheme disks are _the_ most common disk format, ever. They're used by a
|
||||
huge variety of different systems, and they come in a huge variety of different
|
||||
forms, but they're all fundamentally the same: either FM or MFM, either single
|
||||
or double sided, with distinct sector header and data records and no sector
|
||||
forms, but they're all fundamentally the same: either FM or MFM, either single-
|
||||
or double-sided, with distinct sector header and data records and no sector
|
||||
metadata. Systems which use IBM scheme disks include but are not limited to:
|
||||
|
||||
- IBM PCs (naturally)
|
||||
@@ -133,7 +133,7 @@ Neither the FluxEngine or Greaseweazle hardware can currently command a
|
||||
tri-mode drive to spin at 360rpm, however an older 360rpm-only drive will work
|
||||
to read these formats.
|
||||
|
||||
Alternately, the FluxEngine software can resale the flux pulses to enable
|
||||
Alternately, the FluxEngine software can rescale the flux pulses to enable
|
||||
reading and writing these formats with a plain 300rpm drive. To do this,
|
||||
specify the following two additional options:
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ the Vector Graphic Dual-Mode Disk Controller which was paired with a Tandon
|
||||
drive.
|
||||
|
||||
**Important note:** You _cannot_ read these disks with a normal PC drive, as
|
||||
these drives are 96tpi.The track spacing is determined by the physical geometry
|
||||
these drives are 96tpi. The track spacing is determined by the physical geometry
|
||||
of the drive and can't be changed in software. You'll need to get hold of a
|
||||
100tpi Micropolis drive. Luckily these seem to use the same connector and
|
||||
pinout as a 96tpi PC 5.25" drive. In use they should be identical.
|
||||
|
||||
14
doc/using.md
14
doc/using.md
@@ -43,7 +43,7 @@ file while changing the decoder options, to save disk wear. It's also much faste
|
||||
|
||||
### Connecting it up
|
||||
|
||||
To use, simply plug your FluxEngine (or [GreaseWeazle](greaseweazle.doc) into
|
||||
To use, simply plug your FluxEngine (or [GreaseWeazle](greaseweazle.md)) into
|
||||
your computer and run the client. If a single device is plugged in, it will be
|
||||
automatically detected and used.
|
||||
|
||||
@@ -82,7 +82,7 @@ $ fluxengine read eco1 -s copy.flux -o eco1.ldbs --cylinders=1
|
||||
|
||||
### Configuration
|
||||
|
||||
Configuration options are reperesented as a hierarchical structure. You can
|
||||
Configuration options are represented as a hierarchical structure. You can
|
||||
either put them in a text file and load them from the command line:
|
||||
|
||||
```
|
||||
@@ -262,18 +262,18 @@ FluxEngine also supports a number of file system image formats. When using the
|
||||
|
||||
Read from a [DIM image file](https://www.pc98.org/project/doc/dim.html),
|
||||
commonly used by X68000 emulators. Supports automatically configuring
|
||||
the encoder. **Read Only.**
|
||||
the encoder. **Read only.**
|
||||
|
||||
- `<filename.fdi>`
|
||||
|
||||
Read from a [FDI image file](https://www.pc98.org/project/doc/hdi.html),
|
||||
commonly used by PC-98 emulators. Supports automatically configuring
|
||||
the encoder. **Read Only.**
|
||||
the encoder. **Read only.**
|
||||
|
||||
- `<filename.d88>`
|
||||
|
||||
Read from a [D88 image file](https://www.pc98.org/project/doc/d88.html),
|
||||
commonly used by various Japanese PC emulators, including the NEC PC-88. **Read Only.**
|
||||
commonly used by various Japanese PC emulators, including the NEC PC-88. **Read only.**
|
||||
|
||||
FluxEngine is currently limited to reading only the first floppy image in a
|
||||
D88 file.
|
||||
@@ -284,7 +284,7 @@ FluxEngine also supports a number of file system image formats. When using the
|
||||
- `<filename.nfd>`
|
||||
|
||||
Read from a [NFD r0 image file](https://www.pc98.org/project/doc/nfdr0.html),
|
||||
commonly used by various Japanese PC emulators, including the NEC PC-98. **Read Only.**
|
||||
commonly used by various Japanese PC emulators, including the NEC PC-98. **Read only.**
|
||||
|
||||
Only r0 version files are currently supported.
|
||||
|
||||
@@ -308,7 +308,7 @@ FluxEngine also supports a number of file system image formats. When using the
|
||||
underlying MFM, FM or GCR stream, without actually doing the decode into
|
||||
user-visible bytes. However, the decode is still done in order to check for
|
||||
correctness. Individual records are separated by three `\\0` bytes and tracks
|
||||
are seperated by four `\\0` bytes; tracks are emitted in CHS order.
|
||||
are separated by four `\\0` bytes; tracks are emitted in CHS order.
|
||||
|
||||
### High density disks
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ std::unique_ptr<AbstractDecoder> AbstractDecoder::create(const DecoderProto& con
|
||||
return (decoder->second)(config);
|
||||
}
|
||||
|
||||
std::shared_ptr<TrackDataFlux> AbstractDecoder::decodeToSectors(
|
||||
std::shared_ptr<const TrackDataFlux> AbstractDecoder::decodeToSectors(
|
||||
std::shared_ptr<const Fluxmap> fluxmap, unsigned physicalCylinder, unsigned physicalHead)
|
||||
{
|
||||
_trackdata = std::make_shared<TrackDataFlux>();
|
||||
@@ -84,7 +84,7 @@ std::shared_ptr<TrackDataFlux> 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. */
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
std::shared_ptr<TrackDataFlux> decodeToSectors(std::shared_ptr<const Fluxmap> fluxmap, unsigned cylinder, unsigned head);
|
||||
std::shared_ptr<const TrackDataFlux> decodeToSectors(std::shared_ptr<const Fluxmap> fluxmap, unsigned cylinder, unsigned head);
|
||||
void pushRecord(const Fluxmap::Position& start, const Fluxmap::Position& end);
|
||||
|
||||
void resetFluxDecoder();
|
||||
|
||||
@@ -10,17 +10,18 @@ class AbstractEncoder
|
||||
{
|
||||
public:
|
||||
AbstractEncoder(const EncoderProto& config) {}
|
||||
virtual ~AbstractEncoder() {}
|
||||
virtual ~AbstractEncoder() {}
|
||||
|
||||
static std::unique_ptr<AbstractEncoder> create(const EncoderProto& config);
|
||||
static std::unique_ptr<AbstractEncoder> create(const EncoderProto& config);
|
||||
|
||||
public:
|
||||
virtual std::vector<std::shared_ptr<Sector>> collectSectors(
|
||||
int physicalCylinder, int physicalHead, const Image& image) = 0;
|
||||
virtual std::vector<std::shared_ptr<const Sector>> collectSectors(
|
||||
int physicalCylinder, int physicalHead, const Image& image) = 0;
|
||||
|
||||
virtual std::unique_ptr<Fluxmap> encode(
|
||||
int physicalCylinder, int physicalHead, const std::vector<std::shared_ptr<Sector>>& sectors, const Image& image) = 0;
|
||||
virtual std::unique_ptr<Fluxmap> encode(int physicalCylinder,
|
||||
int physicalHead,
|
||||
const std::vector<std::shared_ptr<const Sector>>& sectors,
|
||||
const Image& image) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
12
lib/flux.h
12
lib/flux.h
@@ -17,22 +17,22 @@ struct TrackDataFlux
|
||||
unsigned physicalCylinder;
|
||||
unsigned physicalHead;
|
||||
std::shared_ptr<const Fluxmap> fluxmap;
|
||||
std::vector<std::shared_ptr<Record>> records;
|
||||
std::vector<std::shared_ptr<Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const Record>> records;
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
};
|
||||
|
||||
struct TrackFlux
|
||||
{
|
||||
unsigned physicalCylinder;
|
||||
unsigned physicalHead;
|
||||
std::vector<std::shared_ptr<TrackDataFlux>> trackDatas;
|
||||
std::set<std::shared_ptr<Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const TrackDataFlux>> trackDatas;
|
||||
std::set<std::shared_ptr<const Sector>> sectors;
|
||||
};
|
||||
|
||||
struct DiskFlux
|
||||
{
|
||||
std::vector<std::shared_ptr<TrackFlux>> tracks;
|
||||
std::shared_ptr<Image> image;
|
||||
std::vector<std::shared_ptr<const TrackFlux>> tracks;
|
||||
std::unique_ptr<const Image> image;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <functional>
|
||||
#include <numeric>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
13
lib/image.cc
13
lib/image.cc
@@ -5,9 +5,9 @@
|
||||
Image::Image()
|
||||
{}
|
||||
|
||||
Image::Image(std::set<std::shared_ptr<Sector>>& sectors)
|
||||
Image::Image(std::set<std::shared_ptr<const Sector>>& sectors)
|
||||
{
|
||||
for (std::shared_ptr<Sector> 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<std::shared_ptr<Sector>>& sectors)
|
||||
calculateSize();
|
||||
}
|
||||
|
||||
const std::shared_ptr<Sector>& Image::get(unsigned track, unsigned side, unsigned sectorid) const
|
||||
std::shared_ptr<const Sector> Image::get(unsigned track, unsigned side, unsigned sectorid) const
|
||||
{
|
||||
const static std::shared_ptr<Sector> NONE;
|
||||
static std::shared_ptr<const Sector> NONE;
|
||||
|
||||
key_t key = std::make_tuple(track, side, sectorid);
|
||||
auto i = _sectors.find(key);
|
||||
@@ -26,14 +26,15 @@ const std::shared_ptr<Sector>& Image::get(unsigned track, unsigned side, unsigne
|
||||
return i->second;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Sector>& Image::put(unsigned track, unsigned side, unsigned sectorid)
|
||||
std::shared_ptr<Sector> Image::put(unsigned track, unsigned side, unsigned sectorid)
|
||||
{
|
||||
key_t key = std::make_tuple(track, side, sectorid);
|
||||
std::shared_ptr<Sector> sector = std::make_shared<Sector>();
|
||||
sector->logicalTrack = track;
|
||||
sector->logicalSide = side;
|
||||
sector->logicalSector = sectorid;
|
||||
return _sectors[key] = sector;
|
||||
_sectors[key] = sector;
|
||||
return sector;
|
||||
}
|
||||
|
||||
void Image::calculateSize()
|
||||
|
||||
12
lib/image.h
12
lib/image.h
@@ -18,16 +18,16 @@ private:
|
||||
|
||||
public:
|
||||
Image();
|
||||
Image(std::set<std::shared_ptr<Sector>>& sectors);
|
||||
Image(std::set<std::shared_ptr<const Sector>>& sectors);
|
||||
|
||||
public:
|
||||
class const_iterator
|
||||
{
|
||||
typedef std::map<key_t, std::shared_ptr<Sector>>::const_iterator wrapped_iterator_t;
|
||||
typedef std::map<key_t, std::shared_ptr<const Sector>>::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<Sector>& get(unsigned track, unsigned side, unsigned sectorId) const;
|
||||
const std::shared_ptr<Sector>& put(unsigned track, unsigned side, unsigned sectorId);
|
||||
std::shared_ptr<const Sector> get(unsigned track, unsigned side, unsigned sectorId) const;
|
||||
std::shared_ptr<Sector> 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<key_t, std::shared_ptr<Sector>> _sectors;
|
||||
std::map<key_t, std::shared_ptr<const Sector>> _sectors;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -96,12 +96,12 @@ std::string Logger::toString(const AnyLogMessage& message)
|
||||
indent();
|
||||
stream << "sectors:";
|
||||
|
||||
std::vector<std::shared_ptr<Sector>> sectors(
|
||||
std::vector<std::shared_ptr<const Sector>> sectors(
|
||||
track.sectors.begin(), track.sectors.end());
|
||||
std::sort(sectors.begin(),
|
||||
sectors.end(),
|
||||
[](const std::shared_ptr<Sector>& s1,
|
||||
const std::shared_ptr<Sector>& s2)
|
||||
[](const std::shared_ptr<const Sector>& s1,
|
||||
const std::shared_ptr<const Sector>& s2)
|
||||
{
|
||||
return s1->logicalSector < s2->logicalSector;
|
||||
});
|
||||
|
||||
@@ -18,12 +18,12 @@ struct EndSpeedOperationLogMessage
|
||||
|
||||
struct TrackReadLogMessage
|
||||
{
|
||||
std::shared_ptr<TrackFlux> track;
|
||||
std::shared_ptr<const TrackFlux> track;
|
||||
};
|
||||
|
||||
struct DiskReadLogMessage
|
||||
{
|
||||
std::shared_ptr<DiskFlux> disk;
|
||||
std::shared_ptr<const DiskFlux> disk;
|
||||
};
|
||||
|
||||
struct BeginReadOperationLogMessage
|
||||
@@ -34,6 +34,8 @@ struct BeginReadOperationLogMessage
|
||||
|
||||
struct EndReadOperationLogMessage
|
||||
{
|
||||
std::shared_ptr<const TrackDataFlux> trackDataFlux;
|
||||
std::set<std::shared_ptr<const Sector>> sectors;
|
||||
};
|
||||
|
||||
struct BeginWriteOperationLogMessage
|
||||
|
||||
266
lib/reader.cc
266
lib/reader.cc
@@ -34,152 +34,172 @@ static std::shared_ptr<Fluxmap> readFluxmap(FluxSource& fluxsource, unsigned cyl
|
||||
|
||||
static bool conflictable(Sector::Status status)
|
||||
{
|
||||
return (status == Sector::OK) || (status == Sector::CONFLICT);
|
||||
return (status == Sector::OK) || (status == Sector::CONFLICT);
|
||||
}
|
||||
|
||||
static std::set<std::shared_ptr<Sector>> collect_sectors(std::set<std::shared_ptr<Sector>>& track_sectors)
|
||||
static std::set<std::shared_ptr<const Sector>> collect_sectors(
|
||||
std::set<std::shared_ptr<const Sector>>& track_sectors)
|
||||
{
|
||||
typedef std::tuple<unsigned, unsigned, unsigned> key_t;
|
||||
std::map<key_t, std::shared_ptr<Sector>> sectors;
|
||||
typedef std::tuple<unsigned, unsigned, unsigned> key_t;
|
||||
std::multimap<key_t, std::shared_ptr<const Sector>> 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;
|
||||
}
|
||||
for (const auto& sector : track_sectors)
|
||||
{
|
||||
key_t sectorid = {
|
||||
sector->logicalTrack, sector->logicalSide, sector->logicalSector};
|
||||
sectors.insert({sectorid, sector});
|
||||
}
|
||||
|
||||
std::set<std::shared_ptr<Sector>> sector_set;
|
||||
for (auto& i : sectors)
|
||||
sector_set.insert(i.second);
|
||||
return sector_set;
|
||||
std::set<std::shared_ptr<const Sector>> 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<const Sector>
|
||||
{
|
||||
auto& right = rightit.second;
|
||||
if ((left->status == Sector::OK) &&
|
||||
(right->status == Sector::OK) &&
|
||||
(left->data != right->data))
|
||||
{
|
||||
auto s = std::make_shared<Sector>(*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;
|
||||
}
|
||||
|
||||
std::shared_ptr<DiskFlux> readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder)
|
||||
std::shared_ptr<const DiskFlux> readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder)
|
||||
{
|
||||
if (config.decoder().has_copy_flux_to())
|
||||
outputFluxSink = FluxSink::create(config.decoder().copy_flux_to());
|
||||
if (config.decoder().has_copy_flux_to())
|
||||
outputFluxSink = FluxSink::create(config.decoder().copy_flux_to());
|
||||
|
||||
auto diskflux = std::make_shared<DiskFlux>();
|
||||
bool failures = false;
|
||||
for (int cylinder : iterate(config.cylinders()))
|
||||
{
|
||||
for (int head : iterate(config.heads()))
|
||||
{
|
||||
auto track = std::make_shared<TrackFlux>();
|
||||
track->physicalCylinder = cylinder;
|
||||
track->physicalHead = head;
|
||||
auto diskflux = std::make_shared<DiskFlux>();
|
||||
bool failures = false;
|
||||
for (int cylinder : iterate(config.cylinders()))
|
||||
{
|
||||
for (int head : iterate(config.heads()))
|
||||
{
|
||||
auto track = std::make_shared<TrackFlux>();
|
||||
std::set<std::shared_ptr<const Sector>> track_sectors;
|
||||
std::set<std::shared_ptr<const Record>> track_records;
|
||||
Fluxmap totalFlux;
|
||||
|
||||
std::set<std::shared_ptr<Sector>> track_sectors;
|
||||
std::set<std::shared_ptr<Record>> track_records;
|
||||
Fluxmap totalFlux;
|
||||
for (int retry = config.decoder().retries(); retry >= 0; retry--)
|
||||
{
|
||||
auto fluxmap = readFluxmap(fluxsource, cylinder, head);
|
||||
totalFlux.appendDesync().appendBytes(fluxmap->rawBytes());
|
||||
|
||||
for (int retry = config.decoder().retries(); retry >= 0; retry--)
|
||||
{
|
||||
testForEmergencyStop();
|
||||
auto trackdataflux =
|
||||
decoder.decodeToSectors(fluxmap, cylinder, head);
|
||||
track->trackDatas.push_back(trackdataflux);
|
||||
|
||||
auto fluxmap = readFluxmap(fluxsource, cylinder, head);
|
||||
totalFlux.appendDesync().appendBytes(fluxmap->rawBytes());
|
||||
track_sectors.insert(trackdataflux->sectors.begin(),
|
||||
trackdataflux->sectors.end());
|
||||
track_records.insert(trackdataflux->records.begin(),
|
||||
trackdataflux->records.end());
|
||||
|
||||
auto trackdataflux = decoder.decodeToSectors(fluxmap, cylinder, head);
|
||||
track->trackDatas.push_back(trackdataflux);
|
||||
bool hasBadSectors = false;
|
||||
std::set<unsigned> required_sectors =
|
||||
decoder.requiredSectors(cylinder, head);
|
||||
std::set<std::shared_ptr<const Sector>> result_sectors;
|
||||
for (const auto& sector : collect_sectors(track_sectors))
|
||||
{
|
||||
result_sectors.insert(sector);
|
||||
required_sectors.erase(sector->logicalSector);
|
||||
|
||||
track_sectors.insert(trackdataflux->sectors.begin(), trackdataflux->sectors.end());
|
||||
track_records.insert(trackdataflux->records.begin(), trackdataflux->records.end());
|
||||
if (sector->status != Sector::OK)
|
||||
hasBadSectors = true;
|
||||
}
|
||||
for (unsigned logical_sector : required_sectors)
|
||||
{
|
||||
auto sector = std::make_shared<Sector>();
|
||||
sector->logicalSector = logical_sector;
|
||||
sector->status = Sector::MISSING;
|
||||
result_sectors.insert(sector);
|
||||
|
||||
auto collected_sectors = collect_sectors(track_sectors);
|
||||
hasBadSectors = true;
|
||||
}
|
||||
|
||||
bool hasBadSectors = false;
|
||||
std::set<unsigned> required_sectors = decoder.requiredSectors(cylinder, head);
|
||||
std::set<std::shared_ptr<Sector>> result_sectors;
|
||||
for (const auto& sector : collected_sectors)
|
||||
{
|
||||
result_sectors.insert(sector);
|
||||
required_sectors.erase(sector->logicalSector);
|
||||
track->sectors = collect_sectors(result_sectors);
|
||||
Logger() << TrackReadLogMessage { track };
|
||||
|
||||
if (sector->status != Sector::OK)
|
||||
hasBadSectors = true;
|
||||
}
|
||||
for (unsigned logical_sector : required_sectors)
|
||||
{
|
||||
auto sector = std::make_shared<Sector>();
|
||||
sector->logicalSector = logical_sector;
|
||||
sector->status = Sector::MISSING;
|
||||
result_sectors.insert(sector);
|
||||
if (hasBadSectors)
|
||||
failures = false;
|
||||
|
||||
hasBadSectors = true;
|
||||
}
|
||||
if (!hasBadSectors)
|
||||
break;
|
||||
|
||||
track->sectors = collect_sectors(track_sectors);
|
||||
Logger() << TrackReadLogMessage { track };
|
||||
if (!fluxsource.retryable())
|
||||
break;
|
||||
if (retry == 0)
|
||||
Logger() << fmt::format("giving up");
|
||||
else
|
||||
Logger()
|
||||
<< fmt::format("retrying; {} retries remaining", retry);
|
||||
}
|
||||
|
||||
if (hasBadSectors)
|
||||
failures = false;
|
||||
if (outputFluxSink)
|
||||
outputFluxSink->writeFlux(cylinder, head, totalFlux);
|
||||
|
||||
if (!hasBadSectors)
|
||||
break;
|
||||
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 (!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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
diskflux->tracks.push_back(track);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<std::shared_ptr<Sector>> 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<std::shared_ptr<const Sector>> 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));
|
||||
|
||||
if (failures)
|
||||
Logger() << "Warning: some sectors could not be decoded.";
|
||||
@@ -192,10 +212,10 @@ void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWrit
|
||||
{
|
||||
auto diskflux = readDiskCommand(fluxsource, decoder);
|
||||
|
||||
writer.printMap(*diskflux->image);
|
||||
if (config.decoder().has_write_csv_to())
|
||||
writer.writeCsv(*diskflux->image, config.decoder().write_csv_to());
|
||||
writer.writeImage(*diskflux->image);
|
||||
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 rawReadDiskCommand(FluxSource& fluxsource, FluxSink& fluxsink)
|
||||
|
||||
@@ -12,7 +12,7 @@ class TrackDataFlux;
|
||||
extern std::unique_ptr<TrackDataFlux> readAndDecodeTrack(
|
||||
FluxSource& source, AbstractDecoder& decoder, unsigned cylinder, unsigned head);
|
||||
|
||||
extern std::shared_ptr<DiskFlux> readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder);
|
||||
extern std::shared_ptr<const DiskFlux> readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder);
|
||||
extern void readDiskCommand(FluxSource& source, AbstractDecoder& decoder, ImageWriter& writer);
|
||||
extern void rawReadDiskCommand(FluxSource& source, FluxSink& sink);
|
||||
|
||||
|
||||
@@ -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<Sector>& lhs, std::shared_ptr<Sector>& rhs)
|
||||
bool sectorPointerSortPredicate(
|
||||
std::shared_ptr<const Sector>& lhs, std::shared_ptr<const Sector>& rhs)
|
||||
{
|
||||
return *lhs < *rhs;
|
||||
return *lhs < *rhs;
|
||||
}
|
||||
|
||||
bool sectorPointerEqualsPredicate(std::shared_ptr<Sector>& lhs, std::shared_ptr<Sector>& rhs)
|
||||
bool sectorPointerEqualsPredicate(
|
||||
std::shared_ptr<const Sector>& lhs, std::shared_ptr<const Sector>& 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
49
lib/sector.h
49
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<std::shared_ptr<Record>> records;
|
||||
std::vector<std::shared_ptr<Record>> records;
|
||||
|
||||
std::tuple<int, int, int, Status> key() const
|
||||
{ return std::make_tuple(logicalTrack, logicalSide, logicalSector, status); }
|
||||
std::tuple<int, int, int, Status> 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<Sector>& lhs, std::shared_ptr<Sector>& rhs);
|
||||
extern bool sectorPointerEqualsPredicate(std::shared_ptr<Sector>& lhs, std::shared_ptr<Sector>& rhs);
|
||||
extern bool sectorPointerSortPredicate(
|
||||
std::shared_ptr<const Sector>& lhs, std::shared_ptr<const Sector>& rhs);
|
||||
extern bool sectorPointerEqualsPredicate(
|
||||
std::shared_ptr<const Sector>& lhs, std::shared_ptr<const Sector>& rhs);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -108,8 +108,8 @@ void writeTracksAndVerify(FluxSink& fluxSink,
|
||||
const auto trackdata =
|
||||
decoder.decodeToSectors(writtenFluxmap, cylinder, head);
|
||||
|
||||
std::vector<std::shared_ptr<Sector>> gotSectors =
|
||||
trackdata->sectors;
|
||||
std::vector<std::shared_ptr<const Sector>> gotSectors(
|
||||
trackdata->sectors.begin(), trackdata->sectors.end());
|
||||
gotSectors.erase(std::remove_if(gotSectors.begin(),
|
||||
gotSectors.end(),
|
||||
[](const auto& s)
|
||||
|
||||
@@ -126,7 +126,7 @@ void MainWindow::OnLogMessage(std::shared_ptr<const AnyLogMessage> message)
|
||||
*message);
|
||||
}
|
||||
|
||||
void MainWindow::UpdateVisualisedFlux(std::shared_ptr<DiskFlux>& flux)
|
||||
void MainWindow::UpdateVisualisedFlux(std::shared_ptr<const DiskFlux>& flux)
|
||||
{
|
||||
_currentDisk = flux;
|
||||
visualiser->SetDiskFlux(flux);
|
||||
|
||||
@@ -19,13 +19,13 @@ private:
|
||||
void OnReadFluxButton(wxCommandEvent&);
|
||||
void OnLogMessage(std::shared_ptr<const AnyLogMessage> message);
|
||||
|
||||
void UpdateVisualisedFlux(std::shared_ptr<DiskFlux>& flux);
|
||||
void UpdateVisualisedFlux(std::shared_ptr<const DiskFlux>& flux);
|
||||
void UpdateDevices();
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<ConfigProto>> _formats;
|
||||
std::vector<std::unique_ptr<CandidateDevice>> _devices;
|
||||
std::shared_ptr<DiskFlux> _currentDisk;
|
||||
std::shared_ptr<const DiskFlux> _currentDisk;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -87,7 +87,7 @@ void VisualisationControl::SetMode(int cylinder, int head, int mode)
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void VisualisationControl::SetDiskFlux(std::shared_ptr<DiskFlux>& disk)
|
||||
void VisualisationControl::SetDiskFlux(std::shared_ptr<const DiskFlux>& disk)
|
||||
{
|
||||
_disk = disk;
|
||||
Refresh();
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
|
||||
public:
|
||||
void SetMode(int head, int cylinder, int mode);
|
||||
void SetDiskFlux(std::shared_ptr<DiskFlux>& disk);
|
||||
void SetDiskFlux(std::shared_ptr<const DiskFlux>& disk);
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent & evt);
|
||||
@@ -32,7 +32,7 @@ private:
|
||||
int _head;
|
||||
int _cylinder;
|
||||
int _mode = VISMODE_NOTHING;
|
||||
std::shared_ptr<DiskFlux> _disk;
|
||||
std::shared_ptr<const DiskFlux> _disk;
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user