#include "globals.h" #include "micropolis.h" #include "sector.h" #include "decoders/decoders.h" #include "encoders/encoders.h" #include "image.h" #include "lib/encoders/encoders.pb.h" static void write_sector(std::vector& bits, unsigned& cursor, const std::shared_ptr& sector) { if ((sector->data.size() != 256) && (sector->data.size() != MICROPOLIS_ENCODED_SECTOR_SIZE)) error("unsupported sector size --- you must pick 256 or 275"); int fullSectorSize = 40 + MICROPOLIS_ENCODED_SECTOR_SIZE + 40 + 35; auto fullSector = std::make_shared>(); fullSector->reserve(fullSectorSize); /* sector preamble */ for (int i = 0; i < 40; i++) fullSector->push_back(0); Bytes sectorData; if (sector->data.size() == MICROPOLIS_ENCODED_SECTOR_SIZE) { if (sector->data[0] != 0xFF) error( "275 byte sector doesn't start with sync byte 0xFF. " "Corrupted sector"); uint8_t wantChecksum = sector->data[1 + 2 + 266]; uint8_t gotChecksum = micropolisChecksum(sector->data.slice(1, 2 + 266)); if (wantChecksum != gotChecksum) std::cerr << "Warning: checksum incorrect. Sector: " << sector->logicalSector << std::endl; sectorData = sector->data; } else { ByteWriter writer(sectorData); writer.write_8(0xff); /* Sync */ writer.write_8(sector->logicalTrack); writer.write_8(sector->logicalSector); for (int i = 0; i < 10; i++) writer.write_8(0); /* Padding */ writer += sector->data; writer.write_8(micropolisChecksum(sectorData.slice(1))); for (int i = 0; i < 5; i++) writer.write_8(0); /* 4 byte ECC and ECC not present flag */ } for (uint8_t b : sectorData) fullSector->push_back(b); /* sector postamble */ for (int i = 0; i < 40; i++) fullSector->push_back(0); /* filler */ for (int i = 0; i < 35; i++) fullSector->push_back(0); if (fullSector->size() != fullSectorSize) error("sector mismatched length"); bool lastBit = false; encodeMfm(bits, cursor, fullSector, lastBit); /* filler */ for (int i = 0; i < 5; i++) { bits[cursor++] = 1; bits[cursor++] = 0; } } class MicropolisEncoder : public Encoder { public: MicropolisEncoder(const EncoderProto& config): Encoder(config), _config(config.micropolis()) { } std::unique_ptr encode(std::shared_ptr& trackInfo, const std::vector>& sectors, const Image& image) override { int bitsPerRevolution = (_config.rotational_period_ms() * 1e3) / _config.clock_period_us(); std::vector bits(bitsPerRevolution); unsigned cursor = 0; for (const auto& sectorData : sectors) write_sector(bits, cursor, sectorData); if (cursor != bits.size()) error("track data mismatched length"); std::unique_ptr fluxmap(new Fluxmap); fluxmap->appendBits(bits, calculatePhysicalClockPeriod(_config.clock_period_us() * 1e3, _config.rotational_period_ms() * 1e6)); return fluxmap; } private: const MicropolisEncoderProto& _config; }; std::unique_ptr createMicropolisEncoder(const EncoderProto& config) { return std::unique_ptr(new MicropolisEncoder(config)); }