Refactor the write code to make it easier to add new encoders.

This commit is contained in:
David Given
2019-08-06 22:17:58 +02:00
parent 973f4c2c2d
commit 5748f017dd
6 changed files with 124 additions and 93 deletions

View File

@@ -9,6 +9,9 @@
#define BROTHER_DATA_RECORD_CHECKSUM 3
#define BROTHER_DATA_RECORD_ENCODED_SIZE 415
#define BROTHER_TRACKS_PER_DISK 78
#define BROTHER_SECTORS_PER_TRACK 12
class Sector;
class Fluxmap;
@@ -26,11 +29,11 @@ class BrotherEncoder : public AbstractEncoder
{
public:
virtual ~BrotherEncoder() {}
public:
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors);
};
extern void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor,
int track, int sector);
extern void writeBrotherSectorData(std::vector<bool>& bits, unsigned& cursor,
const Bytes& data);
extern FlagGroup brotherEncoderFlags;
#endif

View File

@@ -4,6 +4,35 @@
#include "encoders/encoders.h"
#include "brother.h"
#include "crc.h"
#include "sectorset.h"
#include "writer.h"
FlagGroup brotherEncoderFlags;
static DoubleFlag clockRateUs(
{ "--clock-rate" },
"Encoded data clock rate (microseconds).",
3.83);
static DoubleFlag postIndexGapMs(
{ "--post-index-gap" },
"Post-index gap before first sector header (milliseconds).",
1.0);
static DoubleFlag sectorSpacingMs(
{ "--sector-spacing" },
"Time between successive sector headers (milliseconds).",
16.2);
static DoubleFlag postHeaderSpacingMs(
{ "--post-header-spacing" },
"Time between a sector's header and data records (milliseconds).",
0.69);
static StringFlag sectorSkew(
{ "--sector-skew" },
"Order in which to write sectors.",
"05a3816b4927");
static int encode_header_gcr(uint16_t word)
{
@@ -41,7 +70,7 @@ static void write_bits(std::vector<bool>& bits, unsigned& cursor, uint32_t data,
}
}
void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor,
static void write_sector_header(std::vector<bool>& bits, unsigned& cursor,
int track, int sector)
{
write_bits(bits, cursor, 0xffffffff, 31);
@@ -51,7 +80,7 @@ void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor,
write_bits(bits, cursor, encode_header_gcr(0x2f), 16);
}
void writeBrotherSectorData(std::vector<bool>& bits, unsigned& cursor, const Bytes& data)
static void write_sector_data(std::vector<bool>& bits, unsigned& cursor, const Bytes& data)
{
write_bits(bits, cursor, 0xffffffff, 32);
write_bits(bits, cursor, BROTHER_DATA_RECORD, 32);
@@ -90,4 +119,49 @@ void writeBrotherSectorData(std::vector<bool>& bits, unsigned& cursor, const Byt
write_byte(0);
}
static int charToInt(char c)
{
if (isdigit(c))
return c - '0';
return 10 + tolower(c) - 'a';
}
std::unique_ptr<Fluxmap> BrotherEncoder::encode(
int physicalTrack, int physicalSide, const SectorSet& allSectors)
{
if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_DISK)
|| (physicalSide != 0))
return std::unique_ptr<Fluxmap>();
int bitsPerRevolution = 200000.0 / clockRateUs;
const std::string& skew = sectorSkew.get();
std::vector<bool> bits(bitsPerRevolution);
unsigned cursor = 0;
for (int sectorCount=0; sectorCount<BROTHER_SECTORS_PER_TRACK; sectorCount++)
{
int sectorId = charToInt(skew.at(sectorCount));
double headerMs = postIndexGapMs + sectorCount*sectorSpacingMs;
unsigned headerCursor = headerMs*1e3 / clockRateUs;
double dataMs = headerMs + postHeaderSpacingMs;
unsigned dataCursor = dataMs*1e3 / clockRateUs;
const auto& sectorData = allSectors.get(physicalTrack, 0, sectorId);
fillBitmapTo(bits, cursor, headerCursor, { true, false });
write_sector_header(bits, cursor, physicalTrack, sectorId);
fillBitmapTo(bits, cursor, dataCursor, { true, false });
write_sector_data(bits, cursor, sectorData->data);
}
if (cursor > bits.size())
Error() << "track data overrun";
fillBitmapTo(bits, cursor, bits.size(), { true, false });
// The pre-index gap is not normally reported.
// std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl;
std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
fluxmap->appendBits(bits, clockRateUs*1e3);
return fluxmap;
}

View File

@@ -1,7 +1,18 @@
#ifndef ENCODERS_H
#define ENCODERS_H
class AbstractEncoder {};
class Fluxmap;
class SectorSet;
class AbstractEncoder
{
public:
virtual ~AbstractEncoder() {}
public:
virtual std::unique_ptr<Fluxmap> encode(
int physicalTrack, int physicalSide, const SectorSet& allSectors) = 0;
};
#endif

View File

@@ -6,9 +6,14 @@
#include "protocol.h"
#include "usb.h"
#include "dataspec.h"
#include "encoders/encoders.h"
#include "fluxsource/fluxsource.h"
#include "fluxsink/fluxsink.h"
#include "fmt/format.h"
#include "record.h"
#include "image.h"
#include "sector.h"
#include "sectorset.h"
FlagGroup writerFlags { &hardwareFluxSourceFlags };
@@ -60,10 +65,12 @@ void writeTracks(
{
if (!outdb)
{
std::cout << "erasing" << std::endl;
std::cout << "erasing\n";
usbSeek(location.track);
usbErase(location.side);
}
else
std::cout << "skipping\n";
}
else
{
@@ -96,3 +103,16 @@ void fillBitmapTo(std::vector<bool>& bitmap,
}
}
void writeDiskCommand(
AbstractEncoder& encoder, const Geometry& geometry, const std::string& inputFilename)
{
SectorSet allSectors;
readSectorsFromFile(allSectors, geometry, inputFilename);
writeTracks(
[&](int track, int side) -> std::unique_ptr<Fluxmap>
{
return encoder.encode(track, side, allSectors);
}
);
}

View File

@@ -6,6 +6,8 @@
extern FlagGroup writerFlags;
class Fluxmap;
class AbstractEncoder;
class Geometry;
extern void setWriterDefaultDest(const std::string& dest);
@@ -15,5 +17,7 @@ extern void fillBitmapTo(std::vector<bool>& bitmap,
unsigned& cursor, unsigned terminateAt,
const std::vector<bool>& pattern);
extern void writeDiskCommand(
AbstractEncoder& encoder, const Geometry& geometry, const std::string& inputFilename);
#endif

View File

@@ -1,109 +1,28 @@
#include "globals.h"
#include "flags.h"
#include "fluxmap.h"
#include "sector.h"
#include "sectorset.h"
#include "decoders/decoders.h"
#include "encoders/encoders.h"
#include "brother/brother.h"
#include "image.h"
#include "writer.h"
#include "fmt/format.h"
#include "image.h"
#include <fstream>
#include <ctype.h>
static FlagGroup flags { &writerFlags };
static FlagGroup flags { &writerFlags, &brotherEncoderFlags };
static StringFlag inputFilename(
{ "--input", "-i" },
"The input image file to read from.",
"brother.img");
static DoubleFlag clockRateUs(
{ "--clock-rate" },
"Encoded data clock rate (microseconds).",
3.83);
static DoubleFlag postIndexGapMs(
{ "--post-index-gap" },
"Post-index gap before first sector header (milliseconds).",
1.0);
static DoubleFlag sectorSpacingMs(
{ "--sector-spacing" },
"Time between successive sector headers (milliseconds).",
16.2);
static DoubleFlag postHeaderSpacingMs(
{ "--post-header-spacing" },
"Time between a sector's header and data records (milliseconds).",
0.69);
static StringFlag sectorSkew(
{ "--sector-skew" },
"Order in which to write sectors.",
"05a3816b4927");
static int charToInt(char c)
{
if (isdigit(c))
return c - '0';
return 10 + tolower(c) - 'a';
}
int mainWriteBrother(int argc, const char* argv[])
{
setWriterDefaultDest(":d=0:t=0-77:s=0");
flags.parseFlags(argc, argv);
SectorSet allSectors;
BrotherEncoder encoder;
Geometry geometry = {78, 1, 12, 256};
readSectorsFromFile(allSectors, geometry, inputFilename);
int bitsPerRevolution = 200000.0 / clockRateUs;
std::cerr << bitsPerRevolution << " bits per 200ms revolution" << std::endl
<< fmt::format("post-index gap: {:.3f}ms\n", (double)postIndexGapMs);
const std::string& skew = sectorSkew;
writeTracks(
[&](int track, int side) -> std::unique_ptr<Fluxmap>
{
if ((track < 0) || (track > 77) || (side != 0))
return std::unique_ptr<Fluxmap>();
std::vector<bool> bits(bitsPerRevolution);
unsigned cursor = 0;
for (int sectorCount=0; sectorCount<geometry.sectors; sectorCount++)
{
int sectorId = charToInt(skew.at(sectorCount));
double headerMs = postIndexGapMs + sectorCount*sectorSpacingMs;
unsigned headerCursor = headerMs*1e3 / clockRateUs;
double dataMs = headerMs + postHeaderSpacingMs;
unsigned dataCursor = dataMs*1e3 / clockRateUs;
auto& sectorData = allSectors.get(track, 0, sectorId);
fillBitmapTo(bits, cursor, headerCursor, { true, false });
writeBrotherSectorHeader(bits, cursor, track, sectorId);
fillBitmapTo(bits, cursor, dataCursor, { true, false });
writeBrotherSectorData(bits, cursor, sectorData->data);
}
if (cursor > bits.size())
Error() << "track data overrun";
fillBitmapTo(bits, cursor, bits.size(), { true, false });
// The pre-index gap is not normally reported.
// std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl;
std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
fluxmap->appendBits(bits, clockRateUs*1e3);
return fluxmap;
}
);
writeDiskCommand(encoder, geometry, inputFilename);
return 0;
}