From 3a8ddf8025465efb028a92b1cf6f477e4a68c93d Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 13 May 2021 15:55:05 +0200 Subject: [PATCH] The writer now works with the new config system. --- arch/brother/brother.h | 12 ++-- arch/brother/brother.proto | 8 +++ arch/brother/encoder.cc | 9 +-- arch/ibm/encoder.cc | 57 ++++++++--------- arch/ibm/ibm.h | 25 ++------ arch/ibm/ibm.proto | 29 ++++----- lib/{range.proto => common.proto} | 0 lib/config.proto | 4 +- lib/fluxsink/fluxsink.cc | 22 ++----- lib/fluxsink/fluxsink.h | 13 +++- lib/fluxsink/hardwarefluxsink.cc | 5 ++ lib/fluxsink/sqlitefluxsink.cc | 10 ++- lib/imagereader/diskcopyimagereader.cc | 11 ++-- lib/imagereader/imagereader.cc | 47 +++----------- lib/imagereader/imagereader.h | 28 +++------ lib/imagereader/imdimagereader.cc | 11 ++-- lib/imagereader/img.proto | 6 +- lib/imagereader/imgimagereader.cc | 67 +++++++++++--------- lib/imagereader/jv3imagereader.cc | 14 ++--- lib/reader.cc | 4 +- lib/writer.cc | 87 +++++++++----------------- lib/writer.h | 6 +- mkninja.sh | 17 ++++- src/fe-erase.cc | 5 +- src/fe-write.cc | 68 ++++++++++++++++++++ src/fe-writetestpattern.cc | 4 +- src/fluxengine.cc | 35 +---------- src/readables/brother.textpb | 2 +- src/readables/ibm.textpb | 2 +- src/writables/brother240.textpb | 28 +++++++++ src/writables/ibm1440.textpb | 32 ++++++++++ 31 files changed, 363 insertions(+), 305 deletions(-) rename lib/{range.proto => common.proto} (100%) create mode 100644 src/fe-write.cc create mode 100644 src/writables/brother240.textpb create mode 100644 src/writables/ibm1440.textpb diff --git a/arch/brother/brother.h b/arch/brother/brother.h index bed85aec..da02c286 100644 --- a/arch/brother/brother.h +++ b/arch/brother/brother.h @@ -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 encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); }; -extern FlagGroup brotherEncoderFlags; - #endif diff --git a/arch/brother/brother.proto b/arch/brother/brother.proto index 9a314331..df7a9388 100644 --- a/arch/brother/brother.proto +++ b/arch/brother/brother.proto @@ -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]; } diff --git a/arch/brother/encoder.cc b/arch/brother/encoder.cc index f9cb00f5..bfb9ef20 100644 --- a/arch/brother/encoder.cc +++ b/arch/brother/encoder.cc @@ -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 BrotherEncoder::encode( int logicalTrack; if (physicalSide != 0) return std::unique_ptr(); - 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(); logicalTrack = physicalTrack/2; break; - case 240: + case BROTHER240: if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_240KB_DISK)) return std::unique_ptr(); logicalTrack = physicalTrack; diff --git a/arch/ibm/encoder.cc b/arch/ibm/encoder.cc index ccab23b4..d98c3a2c 100644 --- a/arch/ibm/encoder.cc +++ b/arch/ibm/encoder.cc @@ -6,6 +6,7 @@ #include "crc.h" #include "sectorset.h" #include "writer.h" +#include "arch/ibm/ibm.pb.h" #include "fmt/format.h" #include @@ -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 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 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 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 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)); diff --git a/arch/ibm/ibm.h b/arch/ibm/ibm.h index 4a4ed657..c8278a47 100644 --- a/arch/ibm/ibm.h +++ b/arch/ibm/ibm.h @@ -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 _bits; unsigned _cursor; bool _lastBit; diff --git a/arch/ibm/ibm.proto b/arch/ibm/ibm.proto index c0157ab0..9595712c 100644 --- a/arch/ibm/ibm.proto +++ b/arch/ibm/ibm.proto @@ -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]; } diff --git a/lib/range.proto b/lib/common.proto similarity index 100% rename from lib/range.proto rename to lib/common.proto diff --git a/lib/config.proto b/lib/config.proto index 74daee48..d8f5c175 100644 --- a/lib/config.proto +++ b/lib/config.proto @@ -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; } diff --git a/lib/fluxsink/fluxsink.cc b/lib/fluxsink/fluxsink.cc index 3d217e2d..3eac4e97 100644 --- a/lib/fluxsink/fluxsink.cc +++ b/lib/fluxsink/fluxsink.cc @@ -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::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::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(); + if (config.has_fluxfile()) + return createSqliteFluxSink(config.fluxfile()); + return createHardwareFluxSink(config.drive()); } diff --git a/lib/fluxsink/fluxsink.h b/lib/fluxsink/fluxsink.h index 43e77b8a..deb84d9b 100644 --- a/lib/fluxsink/fluxsink.h +++ b/lib/fluxsink/fluxsink.h @@ -2,12 +2,13 @@ #define FLUXSINK_H #include "flags.h" +#include extern FlagGroup hardwareFluxSinkFlags; extern FlagGroup sqliteFluxSinkFlags; class Fluxmap; -class FluxSpec; +class Config_OutputDisk; class FluxSink { @@ -17,13 +18,19 @@ public: static std::unique_ptr createSqliteFluxSink(const std::string& filename); static std::unique_ptr createHardwareFluxSink(unsigned drive); - static std::unique_ptr create(const FluxSpec& spec); + static std::unique_ptr 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 diff --git a/lib/fluxsink/hardwarefluxsink.cc b/lib/fluxsink/hardwarefluxsink.cc index 761a8681..6eb8ada3 100644 --- a/lib/fluxsink/hardwarefluxsink.cc +++ b/lib/fluxsink/hardwarefluxsink.cc @@ -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; diff --git a/lib/fluxsink/sqlitefluxsink.cc b/lib/fluxsink/sqlitefluxsink.cc index 9bb49087..e8d312ba 100644 --- a/lib/fluxsink/sqlitefluxsink.cc +++ b/lib/fluxsink/sqlitefluxsink.cc @@ -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::createSqliteFluxSink(const std::string& filename) diff --git a/lib/imagereader/diskcopyimagereader.cc b/lib/imagereader/diskcopyimagereader.cc index 9c484f34..edfc107f 100644 --- a/lib/imagereader/diskcopyimagereader.cc +++ b/lib/imagereader/diskcopyimagereader.cc @@ -4,6 +4,7 @@ #include "sector.h" #include "sectorset.h" #include "imagereader/imagereader.h" +#include "lib/config.pb.h" #include "fmt/format.h" #include #include @@ -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::createDiskCopyImageReader( - const ImageSpec& spec) + const Config_InputFile& config) { - return std::unique_ptr(new DiskCopyImageReader(spec)); + return std::unique_ptr(new DiskCopyImageReader(config)); } diff --git a/lib/imagereader/imagereader.cc b/lib/imagereader/imagereader.cc index 718cfc49..1d2416bb 100644 --- a/lib/imagereader/imagereader.cc +++ b/lib/imagereader/imagereader.cc @@ -6,49 +6,20 @@ #include "imagereader/imagereader.h" #include "utils.h" #include "fmt/format.h" +#include "lib/config.pb.h" #include #include -std::map ImageReader::formats = +std::unique_ptr 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(); } -std::unique_ptr 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) {} diff --git a/lib/imagereader/imagereader.h b/lib/imagereader/imagereader.h index 138902c4..f67947f2 100644 --- a/lib/imagereader/imagereader.h +++ b/lib/imagereader/imagereader.h @@ -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 create(const ImageSpec& spec); - static void verifyImageSpec(const ImageSpec& spec); + static std::unique_ptr create(const Config_InputFile& config); -private: - typedef - std::function< - std::unique_ptr(const ImageSpec& spec) - > - Constructor; - - static std::map formats; - - static std::unique_ptr createDiskCopyImageReader(const ImageSpec& spec); - static std::unique_ptr createImgImageReader(const ImageSpec& spec); - static std::unique_ptr createJv3ImageReader(const ImageSpec& spec); - static std::unique_ptr createIMDImageReader(const ImageSpec& spec); - - static Constructor findConstructor(const ImageSpec& spec); +public: + static std::unique_ptr createDiskCopyImageReader(const Config_InputFile& config); + static std::unique_ptr createImgImageReader(const Config_InputFile& config); + static std::unique_ptr createJv3ImageReader(const Config_InputFile& config); + static std::unique_ptr createIMDImageReader(const Config_InputFile& config); public: virtual SectorSet readImage() = 0; protected: - ImageSpec spec; + const Config_InputFile& _config; }; #endif diff --git a/lib/imagereader/imdimagereader.cc b/lib/imagereader/imdimagereader.cc index 853c8fcf..c40234cd 100644 --- a/lib/imagereader/imdimagereader.cc +++ b/lib/imagereader/imdimagereader.cc @@ -4,6 +4,7 @@ #include "sector.h" #include "sectorset.h" #include "imagereader/imagereader.h" +#include "lib/config.pb.h" #include "fmt/format.h" #include #include @@ -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::createIMDImageReader( - const ImageSpec& spec) + const Config_InputFile& config) { - return std::unique_ptr(new IMDImageReader(spec)); + return std::unique_ptr(new IMDImageReader(config)); } diff --git a/lib/imagereader/img.proto b/lib/imagereader/img.proto index d88dc858..504cc616 100644 --- a/lib/imagereader/img.proto +++ b/lib/imagereader/img.proto @@ -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]; } diff --git a/lib/imagereader/imgimagereader.cc b/lib/imagereader/imgimagereader.cc index a720dae0..06f3930a 100644 --- a/lib/imagereader/imgimagereader.cc +++ b/lib/imagereader/imgimagereader.cc @@ -4,6 +4,7 @@ #include "sector.h" #include "sectorset.h" #include "imagereader/imagereader.h" +#include "lib/config.pb.h" #include "fmt/format.h" #include #include @@ -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 = sectors.get(physicalTrack, head, sectorId); + std::unique_ptr& 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::createImgImageReader( - const ImageSpec& spec) + const Config_InputFile& config) { - return std::unique_ptr(new ImgImageReader(spec)); + return std::unique_ptr(new ImgImageReader(config)); } diff --git a/lib/imagereader/jv3imagereader.cc b/lib/imagereader/jv3imagereader.cc index 06b38dd6..d49b26ff 100644 --- a/lib/imagereader/jv3imagereader.cc +++ b/lib/imagereader/jv3imagereader.cc @@ -5,6 +5,7 @@ #include "sectorset.h" #include "imagereader/imagereader.h" #include "fmt/format.h" +#include "lib/config.pb.h" #include #include #include @@ -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::createJv3ImageReader( - const ImageSpec& spec) +std::unique_ptr ImageReader::createJv3ImageReader(const Config_InputFile& config) { - return std::unique_ptr(new Jv3ImageReader(spec)); + return std::unique_ptr(new Jv3ImageReader(config)); } diff --git a/lib/reader.cc b/lib/reader.cc index aa6602d2..2640a51d 100644 --- a/lib/reader.cc +++ b/lib/reader.cc @@ -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(cylinder, side); + auto track = std::make_unique(cylinder, head); track->fluxsource = &fluxsource; std::map> readSectors; diff --git a/lib/writer.cc b/lib/writer.cc index 33aa0a87..e426e627 100644 --- a/lib/writer.cc +++ b/lib/writer.cc @@ -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(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::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 = 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 = 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& 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 { return encoder.encode(track, side, allSectors); diff --git a/lib/writer.h b/lib/writer.h index a7d8f9df..325d70be 100644 --- a/lib/writer.h +++ b/lib/writer.h @@ -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(int track, int side)> producer); +extern void writeTracks(FluxSink& fluxSink, const std::function(int track, int side)> producer); extern void fillBitmapTo(std::vector& bitmap, unsigned& cursor, unsigned terminateAt, const std::vector& pattern); -extern void writeDiskCommand(AbstractEncoder& encoder); +extern void writeDiskCommand(ImageReader& imageReader, AbstractEncoder& encoder, FluxSink& fluxSink); #endif diff --git a/mkninja.sh b/mkninja.sh index 7fdb129d..4585f285 100644 --- a/mkninja.sh +++ b/mkninja.sh @@ -13,7 +13,7 @@ rule proto description = PROTO \$in rule protoencode - command = (echo '#include ' && 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 ' && 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 \ diff --git a/src/fe-erase.cc b/src/fe-erase.cc index 445d2be9..4d7733f3 100644 --- a/src/fe-erase.cc +++ b/src/fe-erase.cc @@ -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 { return std::unique_ptr(); } ); + #endif return 0; } diff --git a/src/fe-write.cc b/src/fe-write.cc new file mode 100644 index 00000000..f3e645bc --- /dev/null +++ b/src/fe-write.cc @@ -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 +#include + +static FlagGroup flags { &writerFlags }; + +extern std::string writables_brother240_pb(); +extern std::string writables_ibm1440_pb(); + +static std::map> writables = { + { "brother240", writables_brother240_pb }, + { "ibm1440", writables_ibm1440_pb }, +}; + +int mainWrite(int argc, const char* argv[]) +{ + std::vector 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 reader(ImageReader::create(config.input().file())); + + const auto& disk = config.output().disk(); + std::unique_ptr 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::create(config.output().disk())); + + writeDiskCommand(*reader, *encoder, *fluxSink); + + return 0; +} + diff --git a/src/fe-writetestpattern.cc b/src/fe-writetestpattern.cc index 64151d1a..c729b226 100644 --- a/src/fe-writetestpattern.cc +++ b/src/fe-writetestpattern.cc @@ -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 { @@ -41,6 +42,7 @@ int mainWriteTestPattern(int argc, const char* argv[]) return fluxmap; } ); + #endif return 0; } diff --git a/src/fluxengine.cc b/src/fluxengine.cc index ecb2104c..dd596dfb 100644 --- a/src/fluxengine.cc +++ b/src/fluxengine.cc @@ -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& 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); } diff --git a/src/readables/brother.textpb b/src/readables/brother.textpb index ec68635c..74d7096e 100644 --- a/src/readables/brother.textpb +++ b/src/readables/brother.textpb @@ -17,7 +17,7 @@ cylinders { end: 81 } -sides { +heads { start: 0 end: 0 } diff --git a/src/readables/ibm.textpb b/src/readables/ibm.textpb index a745ab93..bfff801b 100644 --- a/src/readables/ibm.textpb +++ b/src/readables/ibm.textpb @@ -16,7 +16,7 @@ cylinders { end: 81 } -sides { +heads { start: 0 end: 1 } diff --git a/src/writables/brother240.textpb b/src/writables/brother240.textpb new file mode 100644 index 00000000..d5602dca --- /dev/null +++ b/src/writables/brother240.textpb @@ -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 +} + diff --git a/src/writables/ibm1440.textpb b/src/writables/ibm1440.textpb new file mode 100644 index 00000000..b4d72e81 --- /dev/null +++ b/src/writables/ibm1440.textpb @@ -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 +} +