This commit is contained in:
David Given
2022-02-24 23:52:18 +01:00
35 changed files with 315 additions and 269 deletions

View File

@@ -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.

View File

@@ -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>();

View File

@@ -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)

View File

@@ -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)

View File

@@ -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);

View File

@@ -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>();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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`.

View File

@@ -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

View File

@@ -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`.

View File

@@ -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

View File

@@ -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:

View File

@@ -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.

View File

@@ -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

View File

@@ -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. */

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -3,6 +3,7 @@
#include <stddef.h>
#include <functional>
#include <numeric>
#include <iostream>
#include <map>
#include <memory>

View File

@@ -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()

View File

@@ -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

View File

@@ -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;
});

View File

@@ -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

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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);

View File

@@ -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

View File

@@ -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();

View File

@@ -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();
};