The writer now works with the new config system.

This commit is contained in:
David Given
2021-05-13 15:55:05 +02:00
parent c2aae7ee18
commit 3a8ddf8025
31 changed files with 363 additions and 305 deletions

View File

@@ -16,6 +16,7 @@
class Sector;
class Fluxmap;
class BrotherInput;
class BrotherOutput;
class BrotherDecoder : public AbstractDecoder
{
@@ -31,20 +32,17 @@ public:
class BrotherEncoder : public AbstractEncoder
{
public:
BrotherEncoder(int format, int bias):
_format(format),
_bias(bias)
BrotherEncoder(const BrotherOutput& config):
_config(config)
{}
virtual ~BrotherEncoder() {}
private:
int _format;
int _bias;
const BrotherOutput& _config;
public:
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors);
};
extern FlagGroup brotherEncoderFlags;
#endif

View File

@@ -2,11 +2,19 @@ syntax = "proto2";
message BrotherInput {}
enum BrotherFormat {
BROTHER240 = 0;
BROTHER120 = 1;
};
message BrotherOutput {
optional double clock_rate_us = 1 [default = 3.83];
optional double post_index_gap_ms = 2 [default = 1.0];
optional double sector_spacing_ms = 3 [default = 16.2];
optional double post_header_spacing_ms = 4 [default = 0.69];
optional string sector_skew = 5 [default = "05a3816b4927"];
optional BrotherFormat format = 6 [default = BROTHER240];
optional int32 bias = 7 [default = 0];
}

View File

@@ -6,6 +6,7 @@
#include "crc.h"
#include "sectorset.h"
#include "writer.h"
#include "arch/brother/brother.pb.h"
FlagGroup brotherEncoderFlags;
@@ -132,17 +133,17 @@ std::unique_ptr<Fluxmap> BrotherEncoder::encode(
int logicalTrack;
if (physicalSide != 0)
return std::unique_ptr<Fluxmap>();
physicalTrack -= _bias;
switch (_format)
physicalTrack -= _config.bias();
switch (_config.format())
{
case 120:
case BROTHER120:
if ((physicalTrack < 0) || (physicalTrack >= (BROTHER_TRACKS_PER_120KB_DISK*2))
|| (physicalTrack & 1))
return std::unique_ptr<Fluxmap>();
logicalTrack = physicalTrack/2;
break;
case 240:
case BROTHER240:
if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_240KB_DISK))
return std::unique_ptr<Fluxmap>();
logicalTrack = physicalTrack;

View File

@@ -6,6 +6,7 @@
#include "crc.h"
#include "sectorset.h"
#include "writer.h"
#include "arch/ibm/ibm.pb.h"
#include "fmt/format.h"
#include <ctype.h>
@@ -78,7 +79,7 @@ void IbmEncoder::writeRawBits(uint32_t data, int width)
void IbmEncoder::writeBytes(const Bytes& bytes)
{
if (_parameters.useFm)
if (_config.use_fm())
encodeFm(_bits, _cursor, bytes);
else
encodeMfm(_bits, _cursor, bytes, _lastBit);
@@ -102,21 +103,21 @@ static uint8_t decodeUint16(uint16_t raw)
std::unique_ptr<Fluxmap> IbmEncoder::encode(
int physicalTrack, int physicalSide, const SectorSet& allSectors)
{
if (_parameters.swapSides)
if (_config.swap_sides())
physicalSide = 1 - physicalSide;
double clockRateUs = 1e3 / _parameters.clockRateKhz;
if (!_parameters.useFm)
double clockRateUs = 1e3 / _config.clock_rate_khz();
if (!_config.use_fm())
clockRateUs /= 2.0;
int bitsPerRevolution = (_parameters.trackLengthMs * 1000.0) / clockRateUs;
int bitsPerRevolution = (_config.track_length_ms() * 1000.0) / clockRateUs;
_bits.resize(bitsPerRevolution);
_cursor = 0;
uint8_t idamUnencoded = decodeUint16(_parameters.idamByte);
uint8_t damUnencoded = decodeUint16(_parameters.damByte);
uint8_t idamUnencoded = decodeUint16(_config.idam_byte());
uint8_t damUnencoded = decodeUint16(_config.dam_byte());
uint8_t sectorSize = 0;
{
int s = _parameters.sectorSize >> 7;
int s = _config.sector_size() >> 7;
while (s > 1)
{
s >>= 1;
@@ -124,27 +125,27 @@ std::unique_ptr<Fluxmap> IbmEncoder::encode(
}
}
uint8_t gapFill = _parameters.useFm ? 0x00 : 0x4e;
uint8_t gapFill = _config.use_fm() ? 0x00 : 0x4e;
writeBytes(_parameters.gap0, gapFill);
if (_parameters.emitIam)
writeBytes(_config.gap0(), gapFill);
if (_config.emit_iam())
{
writeBytes(_parameters.useFm ? 6 : 12, 0x00);
if (!_parameters.useFm)
writeBytes(_config.use_fm() ? 6 : 12, 0x00);
if (!_config.use_fm())
{
for (int i=0; i<3; i++)
writeRawBits(MFM_IAM_SEPARATOR, 16);
}
writeRawBits(_parameters.useFm ? FM_IAM_RECORD : MFM_IAM_RECORD, 16);
writeBytes(_parameters.gap1, gapFill);
writeRawBits(_config.use_fm() ? FM_IAM_RECORD : MFM_IAM_RECORD, 16);
writeBytes(_config.gap1(), gapFill);
}
bool first = true;
for (char sectorChar : _parameters.sectorSkew)
for (char sectorChar : _config.sector_skew())
{
int sectorId = charToInt(sectorChar);
if (!first)
writeBytes(_parameters.gap3, gapFill);
writeBytes(_config.gap3(), gapFill);
first = false;
const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId);
@@ -166,8 +167,8 @@ std::unique_ptr<Fluxmap> IbmEncoder::encode(
Bytes header;
ByteWriter bw(header);
writeBytes(_parameters.useFm ? 6 : 12, 0x00);
if (!_parameters.useFm)
writeBytes(_config.use_fm() ? 6 : 12, 0x00);
if (!_config.use_fm())
{
for (int i=0; i<3; i++)
bw.write_8(MFM_RECORD_SEPARATOR_BYTE);
@@ -175,53 +176,53 @@ std::unique_ptr<Fluxmap> IbmEncoder::encode(
bw.write_8(idamUnencoded);
bw.write_8(sectorData->logicalTrack);
bw.write_8(sectorData->logicalSide);
bw.write_8(sectorData->logicalSector + _parameters.startSectorId);
bw.write_8(sectorData->logicalSector + _config.start_sector_id());
bw.write_8(sectorSize);
uint16_t crc = crc16(CCITT_POLY, header);
bw.write_be16(crc);
int conventionalHeaderStart = 0;
if (!_parameters.useFm)
if (!_config.use_fm())
{
for (int i=0; i<3; i++)
writeRawBits(MFM_RECORD_SEPARATOR, 16);
conventionalHeaderStart += 3;
}
writeRawBits(_parameters.idamByte, 16);
writeRawBits(_config.idam_byte(), 16);
conventionalHeaderStart += 1;
writeBytes(header.slice(conventionalHeaderStart));
}
writeBytes(_parameters.gap2, gapFill);
writeBytes(_config.gap2(), gapFill);
{
Bytes data;
ByteWriter bw(data);
writeBytes(_parameters.useFm ? 6 : 12, 0x00);
if (!_parameters.useFm)
writeBytes(_config.use_fm() ? 6 : 12, 0x00);
if (!_config.use_fm())
{
for (int i=0; i<3; i++)
bw.write_8(MFM_RECORD_SEPARATOR_BYTE);
}
bw.write_8(damUnencoded);
Bytes truncatedData = sectorData->data.slice(0, _parameters.sectorSize);
Bytes truncatedData = sectorData->data.slice(0, _config.sector_size());
bw += truncatedData;
uint16_t crc = crc16(CCITT_POLY, data);
bw.write_be16(crc);
int conventionalHeaderStart = 0;
if (!_parameters.useFm)
if (!_config.use_fm())
{
for (int i=0; i<3; i++)
writeRawBits(MFM_RECORD_SEPARATOR, 16);
conventionalHeaderStart += 3;
}
writeRawBits(_parameters.damByte, 16);
writeRawBits(_config.dam_byte(), 16);
conventionalHeaderStart += 1;
writeBytes(data.slice(conventionalHeaderStart));

View File

@@ -5,6 +5,7 @@
#include "encoders/encoders.h"
class IBMInput;
class IBMOutput;
/* IBM format (i.e. ordinary PC floppies). */
@@ -50,29 +51,11 @@ private:
unsigned _currentHeaderLength;
};
struct IbmParameters
{
int trackLengthMs;
int sectorSize;
bool emitIam;
int startSectorId;
int clockRateKhz;
bool useFm;
uint16_t idamByte;
uint16_t damByte;
int gap0;
int gap1;
int gap2;
int gap3;
std::string sectorSkew;
bool swapSides;
};
class IbmEncoder : public AbstractEncoder
{
public:
IbmEncoder(const IbmParameters& parameters):
_parameters(parameters)
IbmEncoder(const IBMOutput& config):
_config(config)
{}
virtual ~IbmEncoder() {}
@@ -87,7 +70,7 @@ private:
void writeSync();
private:
IbmParameters _parameters;
const IBMOutput& _config;
std::vector<bool> _bits;
unsigned _cursor;
bool _lastBit;

View File

@@ -1,6 +1,6 @@
syntax = "proto2";
import "lib/range.proto";
import "lib/common.proto";
message IBMInput {
optional int32 sector_base = 1 [default=0];
@@ -9,24 +9,19 @@ message IBMInput {
}
message IBMOutput {
enum FmMfm {
USE_MFM = 0;
USE_FM = 1;
}
optional double track_length_ms = 1;
optional int32 sector_size_bytes = 2;
optional bool emit_iam = 3;
optional int32 start_sector_id = 4;
optional int32 sector_size = 2 [default=512];
optional bool emit_iam = 3 [default=true];
optional int32 start_sector_id = 4 [default=1];
optional double clock_rate_khz = 5;
optional FmMfm use_fm = 6 [default = USE_MFM];
optional int32 idam_byte = 7;
optional int32 dam_byte = 8;
optional int32 gap0 = 9;
optional int32 gap1 = 10;
optional int32 gap2 = 11;
optional int32 gap3 = 12;
optional bool use_fm = 6 [default=false];
optional int32 idam_byte = 7 [default=0x5554];
optional int32 dam_byte = 8 [default=0x5545];
optional int32 gap0 = 9 [default=80];
optional int32 gap1 = 10 [default=50];
optional int32 gap2 = 11 [default=22];
optional int32 gap3 = 12 [default=80];
optional string sector_skew = 13;
optional bool swap_sizes = 14;
optional bool swap_sides = 14 [default=false];
}

View File

View File

@@ -4,7 +4,7 @@ import "arch/brother/brother.proto";
import "arch/ibm/ibm.proto";
import "lib/decoders/decoder.proto";
import "lib/imagereader/img.proto";
import "lib/range.proto";
import "lib/common.proto";
import "google/protobuf/descriptor.proto";
extend google.protobuf.FieldOptions {
@@ -67,6 +67,6 @@ message Config {
optional Decoder decoder = 3;
optional Range cylinders = 4;
optional Range sides = 5;
optional Range heads = 5;
}

View File

@@ -2,23 +2,11 @@
#include "flags.h"
#include "dataspec.h"
#include "fluxsink/fluxsink.h"
#include "lib/config.pb.h"
static bool ends_with(const std::string& value, const std::string& ending)
std::unique_ptr<FluxSink> FluxSink::create(const Config_OutputDisk& config)
{
if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
std::unique_ptr<FluxSink> FluxSink::create(const FluxSpec& spec)
{
const auto& filename = spec.filename;
if (filename.empty())
return createHardwareFluxSink(spec.drive);
else if (ends_with(filename, ".flux"))
return createSqliteFluxSink(filename);
Error() << "unrecognised flux filename extension";
return std::unique_ptr<FluxSink>();
if (config.has_fluxfile())
return createSqliteFluxSink(config.fluxfile());
return createHardwareFluxSink(config.drive());
}

View File

@@ -2,12 +2,13 @@
#define FLUXSINK_H
#include "flags.h"
#include <ostream>
extern FlagGroup hardwareFluxSinkFlags;
extern FlagGroup sqliteFluxSinkFlags;
class Fluxmap;
class FluxSpec;
class Config_OutputDisk;
class FluxSink
{
@@ -17,13 +18,19 @@ public:
static std::unique_ptr<FluxSink> createSqliteFluxSink(const std::string& filename);
static std::unique_ptr<FluxSink> createHardwareFluxSink(unsigned drive);
static std::unique_ptr<FluxSink> create(const FluxSpec& spec);
static std::unique_ptr<FluxSink> create(const Config_OutputDisk& config);
public:
virtual void writeFlux(int track, int side, Fluxmap& fluxmap) = 0;
virtual operator std::string () const = 0;
};
extern void setHardwareFluxSinkHardSectorCount(int sectorCount);
inline std::ostream& operator << (std::ostream& stream, FluxSink& flushSink)
{
stream << (std::string)flushSink;
return stream;
}
#endif

View File

@@ -64,6 +64,11 @@ public:
return usbWrite(side, fluxmap.rawBytes(), _hardSectorThreshold);
}
operator std::string () const
{
return fmt::format("drive {}", _drive);
}
private:
unsigned _drive;
nanoseconds_t _hardSectorThreshold;

View File

@@ -19,7 +19,8 @@ static SettableFlag overwriteFlag(
class SqliteFluxSink : public FluxSink
{
public:
SqliteFluxSink(const std::string& filename)
SqliteFluxSink(const std::string& filename):
_filename(filename)
{
if (mergeFlag && overwriteFlag)
Error() << "you can't specify --merge and --overwrite";
@@ -58,8 +59,15 @@ public:
return sqlWriteFlux(_outdb, track, side, fluxmap);
}
operator std::string () const
{
return fmt::format("fluxfile {}", _filename);
}
private:
sqlite3* _outdb;
std::string _filename;
};
std::unique_ptr<FluxSink> FluxSink::createSqliteFluxSink(const std::string& filename)

View File

@@ -4,6 +4,7 @@
#include "sector.h"
#include "sectorset.h"
#include "imagereader/imagereader.h"
#include "lib/config.pb.h"
#include "fmt/format.h"
#include <algorithm>
#include <iostream>
@@ -12,13 +13,13 @@
class DiskCopyImageReader : public ImageReader
{
public:
DiskCopyImageReader(const ImageSpec& spec):
ImageReader(spec)
DiskCopyImageReader(const Config_InputFile& config):
ImageReader(config)
{}
SectorSet readImage()
{
std::ifstream inputFile(spec.filename, std::ios::in | std::ios::binary);
std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary);
if (!inputFile.is_open())
Error() << "cannot open input file";
@@ -120,9 +121,9 @@ public:
};
std::unique_ptr<ImageReader> ImageReader::createDiskCopyImageReader(
const ImageSpec& spec)
const Config_InputFile& config)
{
return std::unique_ptr<ImageReader>(new DiskCopyImageReader(spec));
return std::unique_ptr<ImageReader>(new DiskCopyImageReader(config));
}

View File

@@ -6,49 +6,20 @@
#include "imagereader/imagereader.h"
#include "utils.h"
#include "fmt/format.h"
#include "lib/config.pb.h"
#include <algorithm>
#include <ctype.h>
std::map<std::string, ImageReader::Constructor> ImageReader::formats =
std::unique_ptr<ImageReader> ImageReader::create(const Config_InputFile& config)
{
{".adf", ImageReader::createImgImageReader},
{".d81", ImageReader::createImgImageReader},
{".diskcopy", ImageReader::createDiskCopyImageReader},
{".img", ImageReader::createImgImageReader},
{".ima", ImageReader::createImgImageReader},
{".jv1", ImageReader::createImgImageReader},
{".jv3", ImageReader::createJv3ImageReader},
{".st", ImageReader::createImgImageReader},
{".imd", ImageReader::createIMDImageReader},
{".IMD", ImageReader::createIMDImageReader},
};
ImageReader::Constructor ImageReader::findConstructor(const ImageSpec& spec)
{
const auto& filename = spec.filename;
for (const auto& e : formats)
{
if (endsWith(filename, e.first))
return e.second;
}
return NULL;
if (config.has_img())
return ImageReader::createImgImageReader(config);
else
Error() << "bad input file config";
return std::unique_ptr<ImageReader>();
}
std::unique_ptr<ImageReader> ImageReader::create(const ImageSpec& spec)
{
verifyImageSpec(spec);
return findConstructor(spec)(spec);
}
void ImageReader::verifyImageSpec(const ImageSpec& spec)
{
if (!findConstructor(spec))
Error() << "unrecognised input image filename extension";
}
ImageReader::ImageReader(const ImageSpec& spec):
spec(spec)
ImageReader::ImageReader(const Config_InputFile& config):
_config(config)
{}

View File

@@ -3,38 +3,28 @@
class SectorSet;
class ImageSpec;
class Config_InputFile;
class ImageReader
{
public:
ImageReader(const ImageSpec& spec);
ImageReader(const Config_InputFile& config);
virtual ~ImageReader() {};
public:
static std::unique_ptr<ImageReader> create(const ImageSpec& spec);
static void verifyImageSpec(const ImageSpec& spec);
static std::unique_ptr<ImageReader> create(const Config_InputFile& config);
private:
typedef
std::function<
std::unique_ptr<ImageReader>(const ImageSpec& spec)
>
Constructor;
static std::map<std::string, Constructor> formats;
static std::unique_ptr<ImageReader> createDiskCopyImageReader(const ImageSpec& spec);
static std::unique_ptr<ImageReader> createImgImageReader(const ImageSpec& spec);
static std::unique_ptr<ImageReader> createJv3ImageReader(const ImageSpec& spec);
static std::unique_ptr<ImageReader> createIMDImageReader(const ImageSpec& spec);
static Constructor findConstructor(const ImageSpec& spec);
public:
static std::unique_ptr<ImageReader> createDiskCopyImageReader(const Config_InputFile& config);
static std::unique_ptr<ImageReader> createImgImageReader(const Config_InputFile& config);
static std::unique_ptr<ImageReader> createJv3ImageReader(const Config_InputFile& config);
static std::unique_ptr<ImageReader> createIMDImageReader(const Config_InputFile& config);
public:
virtual SectorSet readImage() = 0;
protected:
ImageSpec spec;
const Config_InputFile& _config;
};
#endif

View File

@@ -4,6 +4,7 @@
#include "sector.h"
#include "sectorset.h"
#include "imagereader/imagereader.h"
#include "lib/config.pb.h"
#include "fmt/format.h"
#include <algorithm>
#include <iostream>
@@ -84,8 +85,8 @@ static unsigned getSectorSize(uint8_t flags)
class IMDImageReader : public ImageReader
{
public:
IMDImageReader(const ImageSpec& spec):
ImageReader(spec)
IMDImageReader(const Config_InputFile& config):
ImageReader(config)
{}
SectorSet readImage()
@@ -109,7 +110,7 @@ public:
*/
{
//Read File
std::ifstream inputFile(spec.filename, std::ios::in | std::ios::binary);
std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary);
if (!inputFile.is_open())
Error() << "cannot open input file";
//define some variables
@@ -273,9 +274,9 @@ public:
};
std::unique_ptr<ImageReader> ImageReader::createIMDImageReader(
const ImageSpec& spec)
const Config_InputFile& config)
{
return std::unique_ptr<ImageReader>(new IMDImageReader(spec));
return std::unique_ptr<ImageReader>(new IMDImageReader(config));
}

View File

@@ -5,10 +5,12 @@ message ImgInputOutput {
optional int32 track = 1;
optional int32 side = 2;
optional int64 file_offset = 3;
optional int32 sector_size = 4;
optional int32 sector_size = 3 [default=512];
optional int32 sectors = 4;
}
repeated Format format = 4;
optional int32 tracks = 5 [default=80];
optional int32 sides = 6 [default=2];
}

View File

@@ -4,6 +4,7 @@
#include "sector.h"
#include "sectorset.h"
#include "imagereader/imagereader.h"
#include "lib/config.pb.h"
#include "fmt/format.h"
#include <algorithm>
#include <iostream>
@@ -12,59 +13,69 @@
class ImgImageReader : public ImageReader
{
public:
ImgImageReader(const ImageSpec& spec):
ImageReader(spec)
ImgImageReader(const Config_InputFile& config):
ImageReader(config)
{}
SectorSet readImage()
{
std::ifstream inputFile(spec.filename, std::ios::in | std::ios::binary);
std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary);
if (!inputFile.is_open())
Error() << "cannot open input file";
size_t headSize = spec.sectors * spec.bytes;
size_t trackSize = headSize * spec.heads;
std::cout << fmt::format("reading {} tracks, {} heads, {} sectors, {} bytes per sector, {} kB total",
spec.cylinders, spec.heads,
spec.sectors, spec.bytes,
spec.cylinders * trackSize / 1024)
<< std::endl;
if ((spec.physicalOffset != 0) || (spec.physicalStep != 1))
std::cout << fmt::format("logical to physical track mapping: physical = logical*{} + {}\n",
spec.physicalStep, spec.physicalOffset);
SectorSet sectors;
for (int track = 0; track < spec.cylinders; track++)
for (int track = 0; track < _config.img().tracks(); track++)
{
for (int head = 0; head < spec.heads; head++)
for (int side = 0; side < _config.img().sides(); side++)
{
for (int sectorId = 0; sectorId < spec.sectors; sectorId++)
ImgInputOutput::Format format;
getTrackFormat(format, track, side);
for (int sectorId = 0; sectorId < format.sectors(); sectorId++)
{
inputFile.seekg(track*trackSize + head*headSize + sectorId*spec.bytes, std::ios::beg);
Bytes data(format.sector_size());
inputFile.read((char*) data.begin(), data.size());
Bytes data(spec.bytes);
inputFile.read((char*) data.begin(), spec.bytes);
int physicalTrack = track*spec.physicalStep + spec.physicalOffset;
std::unique_ptr<Sector>& sector = sectors.get(physicalTrack, head, sectorId);
std::unique_ptr<Sector>& sector = sectors.get(track, side, sectorId);
sector.reset(new Sector);
sector->status = Sector::OK;
sector->logicalTrack = track;
sector->physicalTrack = physicalTrack;
sector->logicalSide = sector->physicalSide = head;
sector->physicalTrack = track;
sector->logicalSide = sector->physicalSide = side;
sector->logicalSector = sectorId;
sector->data = data;
}
}
if (inputFile.eof())
break;
}
std::cout << fmt::format("reading {} tracks, {} sides, {} kB total\n",
_config.img().tracks(), _config.img().sides(),
inputFile.tellg() / 1024);
return sectors;
}
private:
void getTrackFormat(ImgInputOutput::Format& format, unsigned track, unsigned side)
{
format.Clear();
for (const ImgInputOutput::Format& f : _config.img().format())
{
if (f.has_track() && (f.track() != track))
continue;
if (f.has_side() && (f.side() != side))
continue;
format.MergeFrom(f);
}
}
};
std::unique_ptr<ImageReader> ImageReader::createImgImageReader(
const ImageSpec& spec)
const Config_InputFile& config)
{
return std::unique_ptr<ImageReader>(new ImgImageReader(spec));
return std::unique_ptr<ImageReader>(new ImgImageReader(config));
}

View File

@@ -5,6 +5,7 @@
#include "sectorset.h"
#include "imagereader/imagereader.h"
#include "fmt/format.h"
#include "lib/config.pb.h"
#include <algorithm>
#include <iostream>
#include <fstream>
@@ -13,7 +14,7 @@
* in any order, followed by the same again for more sectors. To find the second data block
* you need to know the size of the first data block, which requires parsing it.
*
* https://www.tim-mann.org/trs80/dskspec.html
* https://www.tim-mann.org/trs80/dskconfig.html
*
* typedef struct {
* SectorHeader headers1[2901];
@@ -77,13 +78,13 @@ static unsigned getSectorSize(uint8_t flags)
class Jv3ImageReader : public ImageReader
{
public:
Jv3ImageReader(const ImageSpec& spec):
ImageReader(spec)
Jv3ImageReader(const Config_InputFile& config):
ImageReader(config)
{}
SectorSet readImage()
{
std::ifstream inputFile(spec.filename, std::ios::in | std::ios::binary);
std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary);
if (!inputFile.is_open())
Error() << "cannot open input file";
@@ -132,10 +133,9 @@ public:
}
};
std::unique_ptr<ImageReader> ImageReader::createJv3ImageReader(
const ImageSpec& spec)
std::unique_ptr<ImageReader> ImageReader::createJv3ImageReader(const Config_InputFile& config)
{
return std::unique_ptr<ImageReader>(new Jv3ImageReader(spec));
return std::unique_ptr<ImageReader>(new Jv3ImageReader(config));
}

View File

@@ -136,9 +136,9 @@ void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWrit
SectorSet allSectors;
for (int cylinder : iterate(config.cylinders()))
{
for (int side : iterate(config.sides()))
for (int head : iterate(config.heads()))
{
auto track = std::make_unique<Track>(cylinder, side);
auto track = std::make_unique<Track>(cylinder, head);
track->fluxsource = &fluxsource;
std::map<int, std::unique_ptr<Sector>> readSectors;

View File

@@ -14,70 +14,42 @@
#include "record.h"
#include "sector.h"
#include "sectorset.h"
#include "lib/config.pb.h"
#include "proto.h"
FlagGroup writerFlags { &hardwareFluxSourceFlags, &sqliteFluxSinkFlags, &hardwareFluxSinkFlags };
static DataSpecFlag dest(
{ "--dest", "-d" },
"destination for data",
":d=0:t=0-79:s=0-1");
static DataSpecFlag input(
{ "--input", "-i" },
"input image file to read from",
"");
static sqlite3* outdb;
void setWriterDefaultDest(const std::string& dest)
{
::dest.set(dest);
}
void setWriterDefaultInput(const std::string& input)
{
::input.set(input);
}
void setWriterHardSectorCount(int sectorCount)
{
setHardwareFluxSinkHardSectorCount(sectorCount);
}
static SectorSet readSectorsFromFile(const ImageSpec& spec)
{
return ImageReader::create(spec)->readImage();
}
void writeTracks(
FluxSink& fluxSink,
const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer)
{
const FluxSpec spec(dest);
std::cout << "Writing to: " << fluxSink << std::endl;
std::cout << "Writing to: " << dest << std::endl;
std::shared_ptr<FluxSink> fluxSink = FluxSink::create(spec);
for (const auto& location : spec.locations)
{
std::cout << fmt::format("{0:>3}.{1}: ", location.track, location.side) << std::flush;
std::unique_ptr<Fluxmap> fluxmap = producer(location.track, location.side);
if (!fluxmap)
{
/* Erase this track rather than writing. */
fluxmap.reset(new Fluxmap());
fluxSink->writeFlux(location.track, location.side, *fluxmap);
std::cout << "erased\n";
}
else
for (unsigned cylinder : iterate(config.cylinders()))
{
for (unsigned head : iterate(config.heads()))
{
/* Precompensation actually seems to make things worse, so let's leave
* it disabled for now. */
//fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS, 2);
fluxSink->writeFlux(location.track, location.side, *fluxmap);
std::cout << fmt::format(
"{0} ms in {1} bytes", int(fluxmap->duration()/1e6), fluxmap->bytes()) << std::endl;
std::cout << fmt::format("{0:>3}.{1}: ", cylinder, head) << std::flush;
std::unique_ptr<Fluxmap> fluxmap = producer(cylinder, head);
if (!fluxmap)
{
/* Erase this track rather than writing. */
fluxmap.reset(new Fluxmap());
fluxSink.writeFlux(cylinder, head, *fluxmap);
std::cout << "erased\n";
}
else
{
/* Precompensation actually seems to make things worse, so let's leave
* it disabled for now. */
//fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS, 2);
fluxSink.writeFlux(cylinder, head, *fluxmap);
std::cout << fmt::format(
"{0} ms in {1} bytes", int(fluxmap->duration()/1e6), fluxmap->bytes()) << std::endl;
}
}
}
}
@@ -96,11 +68,10 @@ void fillBitmapTo(std::vector<bool>& bitmap,
}
}
void writeDiskCommand(AbstractEncoder& encoder)
void writeDiskCommand(ImageReader& imageReader, AbstractEncoder& encoder, FluxSink& fluxSink)
{
const ImageSpec spec(input);
SectorSet allSectors = readSectorsFromFile(spec);
writeTracks(
SectorSet allSectors = imageReader.readImage();
writeTracks(fluxSink,
[&](int track, int side) -> std::unique_ptr<Fluxmap>
{
return encoder.encode(track, side, allSectors);

View File

@@ -8,17 +8,19 @@ extern FlagGroup writerFlags;
class Fluxmap;
class AbstractEncoder;
class Geometry;
class ImageReader;
class FluxSink;
extern void setWriterDefaultDest(const std::string& dest);
extern void setWriterDefaultInput(const std::string& input);
extern void setWriterHardSectorCount(int sectorCount);
extern void writeTracks(const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer);
extern void writeTracks(FluxSink& fluxSink, const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer);
extern void fillBitmapTo(std::vector<bool>& bitmap,
unsigned& cursor, unsigned terminateAt,
const std::vector<bool>& pattern);
extern void writeDiskCommand(AbstractEncoder& encoder);
extern void writeDiskCommand(ImageReader& imageReader, AbstractEncoder& encoder, FluxSink& fluxSink);
#endif

View File

@@ -13,7 +13,7 @@ rule proto
description = PROTO \$in
rule protoencode
command = (echo '#include <string>' && echo 'static const char data[] = {' && ($PROTOC \$flags --encode=\$messagetype \$\$(cat \$def)< \$in | $XXD -i) && echo '}; extern std::string \$name(); std::string \$name() { return std::string(data, sizeof(data)); }') > \$out
command = (echo '#include <string>' && echo 'static const unsigned char data[] = {' && ($PROTOC \$flags --encode=\$messagetype \$\$(cat \$def)< \$in | $XXD -i) && echo '}; extern std::string \$name(); std::string \$name() { return std::string((const char*)data, sizeof(data)); }') > \$out
description = PROTOENCODE \$in
rule binencode
@@ -232,7 +232,7 @@ buildproto libproto.a \
lib/config.proto \
lib/decoders/decoder.proto \
lib/imagereader/img.proto \
lib/range.proto \
lib/common.proto \
buildlibrary libbackend.a \
-I$OBJDIR/proto \
@@ -308,6 +308,14 @@ for pb in \
readables_${pb}_pb src/readables/$pb.textpb $OBJDIR/proto/src/readables/$pb.cc
done
for pb in \
brother240 \
ibm1440 \
; do
buildencodedproto $OBJDIR/proto/libproto.def Config \
writables_${pb}_pb src/writables/$pb.textpb $OBJDIR/proto/src/writables/$pb.cc
done
buildlibrary libfrontend.a \
-I$OBJDIR/proto \
src/fe-analysedriveresponse.cc \
@@ -319,18 +327,21 @@ buildlibrary libfrontend.a \
src/fe-fluxtovcd.cc \
src/fe-image.cc \
src/fe-inspect.cc \
src/fe-read.cc \
src/fe-rpm.cc \
src/fe-scptoflux.cc \
src/fe-seek.cc \
src/fe-testbandwidth.cc \
src/fe-testvoltages.cc \
src/fe-upgradefluxfile.cc \
src/fe-write.cc \
src/fe-writeflux.cc \
src/fe-writetestpattern.cc \
src/fe-read.cc \
src/fluxengine.cc \
$OBJDIR/proto/src/readables/brother.cc \
$OBJDIR/proto/src/readables/ibm.cc \
$OBJDIR/proto/src/writables/brother240.cc \
$OBJDIR/proto/src/writables/ibm1440.cc \
# src/fe-readadfs.cc \
# src/fe-readaeslanier.cc \

View File

@@ -7,15 +7,18 @@ static FlagGroup flags { &writerFlags };
int mainErase(int argc, const char* argv[])
{
setWriterDefaultDest(":t=0-81:s=0-1");
flags.parseFlags(argc, argv);
Error() << "TODO";
#if 0
writeTracks(
[](int physicalTrack, int physicalSide) -> std::unique_ptr<Fluxmap>
{
return std::unique_ptr<Fluxmap>();
}
);
#endif
return 0;
}

68
src/fe-write.cc Normal file
View File

@@ -0,0 +1,68 @@
#include "globals.h"
#include "flags.h"
#include "writer.h"
#include "fluxmap.h"
#include "decoders/decoders.h"
#include "encoders/encoders.h"
#include "sector.h"
#include "sectorset.h"
#include "record.h"
#include "proto.h"
#include "dataspec.h"
#include "fluxsink/fluxsink.h"
#include "arch/brother/brother.h"
#include "arch/ibm/ibm.h"
#include "imagereader/imagereader.h"
#include "fmt/format.h"
#include <google/protobuf/text_format.h>
#include <fstream>
static FlagGroup flags { &writerFlags };
extern std::string writables_brother240_pb();
extern std::string writables_ibm1440_pb();
static std::map<std::string, std::function<std::string()>> writables = {
{ "brother240", writables_brother240_pb },
{ "ibm1440", writables_ibm1440_pb },
};
int mainWrite(int argc, const char* argv[])
{
std::vector<std::string> filenames = flags.parseFlagsWithFilenames(argc, argv);
for (const auto& filename : filenames)
{
if (writables.find(filename) != writables.end())
{
if (!config.ParseFromString(writables[filename]()))
Error() << "couldn't load config proto";
}
else
Error() << "configs in files not supported yet";
}
if (!config.has_input() || !config.has_output())
Error() << "incomplete config (did you remember to specify the format?)";
std::string s;
google::protobuf::TextFormat::PrintToString(config, &s);
std::cout << s << '\n';
std::unique_ptr<ImageReader> reader(ImageReader::create(config.input().file()));
const auto& disk = config.output().disk();
std::unique_ptr<AbstractEncoder> encoder;
if (disk.has_brother())
encoder.reset(new BrotherEncoder(disk.brother()));
else if (disk.has_ibm())
encoder.reset(new IbmEncoder(disk.ibm()));
else
Error() << "no output disk format specified";
std::unique_ptr<FluxSink> fluxSink(FluxSink::create(config.output().disk()));
writeDiskCommand(*reader, *encoder, *fluxSink);
return 0;
}

View File

@@ -22,11 +22,12 @@ static DoubleFlag sequenceLength(
int mainWriteTestPattern(int argc, const char* argv[])
{
setWriterDefaultDest(":t=0-81:s=0-1");
flags.parseFlags(argc, argv);
unsigned ticksPerInterval = (unsigned) (interval * TICKS_PER_US);
Error() << "TODO";
#if 0
writeTracks(
[&](int physicalTrack, int physicalSide) -> std::unique_ptr<Fluxmap>
{
@@ -41,6 +42,7 @@ int mainWriteTestPattern(int argc, const char* argv[])
return fluxmap;
}
);
#endif
return 0;
}

View File

@@ -4,42 +4,21 @@ typedef int command_cb(int agrc, const char* argv[]);
extern command_cb mainAnalyseDriveResponse;
extern command_cb mainAnalyseLayout;
extern command_cb mainErase;
extern command_cb mainConvertCwfToFlux;
extern command_cb mainConvertFluxToAu;
extern command_cb mainConvertFluxToScp;
extern command_cb mainConvertFluxToVcd;
extern command_cb mainConvertImage;
extern command_cb mainConvertScpToFlux;
extern command_cb mainErase;
extern command_cb mainInspect;
extern command_cb mainReadADFS;
extern command_cb mainReadAESLanier;
extern command_cb mainReadAmiga;
extern command_cb mainReadAmpro;
extern command_cb mainReadApple2;
extern command_cb mainReadAtariST;
extern command_cb mainReadBrother;
extern command_cb mainReadC64;
extern command_cb mainReadDFS;
extern command_cb mainReadF85;
extern command_cb mainReadFB100;
extern command_cb mainReadIBM;
extern command_cb mainReadMac;
extern command_cb mainReadMicropolis;
extern command_cb mainReadMx;
extern command_cb mainReadTiDs990;
extern command_cb mainReadVictor9K;
extern command_cb mainReadZilogMCZ;
extern command_cb mainRead;
extern command_cb mainRpm;
extern command_cb mainSeek;
extern command_cb mainTestBandwidth;
extern command_cb mainTestVoltages;
extern command_cb mainUpgradeFluxFile;
extern command_cb mainWriteAmiga;
extern command_cb mainWriteBrother;
extern command_cb mainWriteIbm;
extern command_cb mainWriteMac;
extern command_cb mainWriteTiDs990;
extern command_cb mainWrite;
extern command_cb mainWriteFlux;
extern command_cb mainWriteTestPattern;
@@ -50,8 +29,6 @@ struct Command
std::string help;
};
extern command_cb mainRead;
static command_cb mainWrite;
static command_cb mainConvert;
static command_cb mainAnalyse;
static command_cb mainTest;
@@ -156,12 +133,6 @@ static int mainExtended(std::vector<Command>& subcommands, const std::string& co
return 1;
}
//static int mainRead(int argc, const char* argv[])
//{ return mainExtended(readables, "read", argc, argv); }
static int mainWrite(int argc, const char* argv[])
{ return mainExtended(writeables, "write", argc, argv); }
static int mainConvert(int argc, const char* argv[])
{ return mainExtended(convertables, "convert", argc, argv); }

View File

@@ -17,7 +17,7 @@ cylinders {
end: 81
}
sides {
heads {
start: 0
end: 0
}

View File

@@ -16,7 +16,7 @@ cylinders {
end: 81
}
sides {
heads {
start: 0
end: 1
}

View File

@@ -0,0 +1,28 @@
input {
file {
filename: "brother240.img"
img {
format {
sectors: 12
sector_size: 256
}
}
}
}
output {
disk {
brother {}
}
}
cylinders {
start: 0
end: 77
}
heads {
start: 0
end: 0
}

View File

@@ -0,0 +1,32 @@
input {
file {
filename: "ibm1440.img"
img {
format {
sectors: 18
sector_size: 512
}
}
}
}
output {
disk {
ibm {
track_length_ms: 200
clock_rate_khz: 500
sector_skew: "0123456789abcdefgh"
}
}
}
cylinders {
start: 0
end: 79
}
heads {
start: 0
end: 1
}