mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	
		
			
				
	
	
		
			123 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #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 "brother.h"
 | |
| #include "lib/data/sector.h"
 | |
| #include "lib/core/bytes.h"
 | |
| #include "lib/core/crc.h"
 | |
| #include <ctype.h>
 | |
| 
 | |
| 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<uint8_t> 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->logicalTrack = 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->logicalTrack > 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<Decoder> createBrotherDecoder(const DecoderProto& config)
 | |
| {
 | |
|     return std::unique_ptr<Decoder>(new BrotherDecoder(config));
 | |
| }
 |