#include "lib/core/globals.h" #include "lib/data/fluxmap.h" #include "lib/data/fluxmapreader.h" #include "lib/data/fluxpattern.h" #include "lib/decoders/decoders.h" #include "lib/encoders/encoders.h" #include "arch/brother/brother.h" #include "lib/data/sector.h" #include "lib/core/bytes.h" #include "lib/core/crc.h" #include const FluxPattern SECTOR_RECORD_PATTERN(32, BROTHER_SECTOR_RECORD); const FluxPattern DATA_RECORD_PATTERN(32, BROTHER_DATA_RECORD); const FluxMatchers ANY_RECORD_PATTERN( {&SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN}); static std::vector outputbuffer; /* * Brother disks have this very very non-IBM system where sector header records * and data records use two different kinds of GCR: sector headers are 8-in-16 * (but the encodable values range from 0 to 77ish only) and data headers are * 5-in-8. In addition, there's a non-encoded 10-bit ID word at the beginning * of each record, as well as a string of 53 1s introducing them. That does at * least make them easy to find. * * Disk formats vary from machine to machine, but mine uses 78 tracks. Track 0 * is erased but not formatted. Track alignment is extremely dubious and * Brother track 0 shows up on my machine at track 2. */ static int decode_data_gcr(uint8_t gcr) { switch (gcr) { #define GCR_ENTRY(gcr, data) \ case gcr: \ return data; #include "data_gcr.h" #undef GCR_ENTRY } return -1; } static int decode_header_gcr(uint16_t word) { switch (word) { #define GCR_ENTRY(gcr, data) \ case gcr: \ return data; #include "header_gcr.h" #undef GCR_ENTRY } return -1; } class BrotherDecoder : public Decoder { public: BrotherDecoder(const DecoderProto& config): Decoder(config) {} nanoseconds_t advanceToNextRecord() override { return seekToPattern(ANY_RECORD_PATTERN); } void decodeSectorRecord() override { if (readRaw32() != BROTHER_SECTOR_RECORD) return; const auto& rawbits = readRawBits(32); const auto& bytes = toBytes(rawbits).slice(0, 4); ByteReader br(bytes); _sector->logicalCylinder = decode_header_gcr(br.read_be16()); _sector->logicalSector = decode_header_gcr(br.read_be16()); /* Sanity check the values read; there's no header checksum and * occasionally we get garbage due to bit errors. */ if (_sector->logicalSector > 11) return; if (_sector->logicalCylinder > 79) return; _sector->status = Sector::DATA_MISSING; } void decodeDataRecord() override { if (readRaw32() != BROTHER_DATA_RECORD) return; const auto& rawbits = readRawBits(BROTHER_DATA_RECORD_ENCODED_SIZE * 8); const auto& rawbytes = toBytes(rawbits).slice(0, BROTHER_DATA_RECORD_ENCODED_SIZE); Bytes bytes; ByteWriter bw(bytes); BitWriter bitw(bw); for (uint8_t b : rawbytes) { uint32_t nibble = decode_data_gcr(b); bitw.push(nibble, 5); } bitw.flush(); _sector->data = bytes.slice(0, BROTHER_DATA_RECORD_PAYLOAD); uint32_t realCrc = crcbrother(_sector->data); uint32_t wantCrc = bytes.reader().seek(BROTHER_DATA_RECORD_PAYLOAD).read_be24(); _sector->status = (realCrc == wantCrc) ? Sector::OK : Sector::BAD_CHECKSUM; } }; std::unique_ptr createBrotherDecoder(const DecoderProto& config) { return std::unique_ptr(new BrotherDecoder(config)); }