mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			config
			...
			hardsector
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | f634988356 | 
| @@ -88,16 +88,6 @@ public: | ||||
| 			now = tell().ns(); | ||||
| 		} | ||||
|  | ||||
| 		/* Discard a possible partial sector at the end of the track. | ||||
| 		 * This partial sector could be mistaken for a conflicted sector, if | ||||
| 		 * whatever data read happens to match the checksum of 0, which is | ||||
| 		 * rare, but has been observed on some disks. | ||||
| 		 */ | ||||
| 		if (now > (getFluxmapDuration() - 21e6)) { | ||||
| 			seekToIndexMark(); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		int msSinceIndex = std::round(now / 1e6); | ||||
|  | ||||
| 		/* Note that the seekToPattern ignores the sector pulses, so if | ||||
| @@ -108,11 +98,6 @@ public: | ||||
| 		nanoseconds_t clock = seekToPattern(ANY_SECTOR_PATTERN); | ||||
| 		_sector->headerStartTime = tell().ns(); | ||||
|  | ||||
| 		/* Discard a possible partial sector. */ | ||||
| 		if (_sector->headerStartTime > (getFluxmapDuration() - 21e6)) { | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		int sectorFoundTimeRaw = std::round(_sector->headerStartTime / 1e6); | ||||
| 		int sectorFoundTime; | ||||
|  | ||||
| @@ -132,7 +117,16 @@ public: | ||||
|  | ||||
| 	void decodeSectorRecord() override | ||||
| 	{ | ||||
| 		nanoseconds_t before = tell().ns(); | ||||
| 		uint64_t id = toBytes(readRawBits(64)).reader().read_be64(); | ||||
| 		nanoseconds_t after = tell().ns(); | ||||
|  | ||||
| 		/* Discard any sectors which span the end of a revolution. This can sometimes | ||||
| 		 * cause spurious bad sectors which can trigger conflicts. */ | ||||
|  | ||||
| 		if (int(before / 200e9) != int(after / 200e9)) | ||||
| 			return; | ||||
|  | ||||
| 		unsigned recordSize, payloadSize, headerSize; | ||||
|  | ||||
| 		if (id == MFM_ID) { | ||||
|   | ||||
| @@ -12,155 +12,165 @@ | ||||
| #define GAP_FILL_SIZE_DD 62 | ||||
| #define PRE_HEADER_GAP_FILL_SIZE_DD 16 | ||||
|  | ||||
| #define GAP1_FILL_BYTE	(0x4F) | ||||
| #define GAP2_FILL_BYTE	(0x4F) | ||||
| #define GAP1_FILL_BYTE (0x4F) | ||||
| #define GAP2_FILL_BYTE (0x4F) | ||||
|  | ||||
| #define TOTAL_SECTOR_BYTES () | ||||
|  | ||||
| static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<const Sector>& sector) | ||||
| static void write_sector(std::vector<bool>& bits, | ||||
|     unsigned& cursor, | ||||
|     const std::shared_ptr<const Sector>& sector) | ||||
| { | ||||
| 	int preambleSize = 0; | ||||
| 	int encodedSectorSize = 0; | ||||
| 	int gapFillSize = 0; | ||||
| 	int preHeaderGapFillSize = 0; | ||||
|     int preambleSize = 0; | ||||
|     int encodedSectorSize = 0; | ||||
|     int preHeaderGapFillSize = 0; | ||||
|  | ||||
| 	bool doubleDensity; | ||||
|     bool doubleDensity; | ||||
|  | ||||
| 	switch (sector->data.size()) { | ||||
| 	case NORTHSTAR_PAYLOAD_SIZE_SD: | ||||
| 		preambleSize = NORTHSTAR_PREAMBLE_SIZE_SD; | ||||
| 		encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_SD + NORTHSTAR_ENCODED_SECTOR_SIZE_SD + GAP_FILL_SIZE_SD; | ||||
| 		gapFillSize = GAP_FILL_SIZE_SD; | ||||
| 		preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_SD; | ||||
| 		doubleDensity = false; | ||||
| 		break; | ||||
| 	case NORTHSTAR_PAYLOAD_SIZE_DD: | ||||
| 		preambleSize = NORTHSTAR_PREAMBLE_SIZE_DD; | ||||
| 		encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_DD + NORTHSTAR_ENCODED_SECTOR_SIZE_DD + GAP_FILL_SIZE_DD; | ||||
| 		gapFillSize = GAP_FILL_SIZE_DD; | ||||
| 		preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_DD; | ||||
| 		doubleDensity = true; | ||||
| 		break; | ||||
| 	default: | ||||
| 		Error() << "unsupported sector size --- you must pick 256 or 512"; | ||||
| 		break; | ||||
| 	} | ||||
|     switch (sector->data.size()) | ||||
|     { | ||||
|         case NORTHSTAR_PAYLOAD_SIZE_SD: | ||||
|             preambleSize = NORTHSTAR_PREAMBLE_SIZE_SD; | ||||
|             encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_SD + | ||||
|                                 NORTHSTAR_ENCODED_SECTOR_SIZE_SD; | ||||
|             preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_SD; | ||||
|             doubleDensity = false; | ||||
|             break; | ||||
|  | ||||
| 	int fullSectorSize = preambleSize + encodedSectorSize; | ||||
| 	auto fullSector = std::make_shared<std::vector<uint8_t>>(); | ||||
| 	fullSector->reserve(fullSectorSize); | ||||
|         case NORTHSTAR_PAYLOAD_SIZE_DD: | ||||
|             preambleSize = NORTHSTAR_PREAMBLE_SIZE_DD; | ||||
|             encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_DD + | ||||
|                                 NORTHSTAR_ENCODED_SECTOR_SIZE_DD; | ||||
|             preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_DD; | ||||
|             doubleDensity = true; | ||||
|             break; | ||||
|  | ||||
| 	/* sector gap after index pulse */ | ||||
| 	for (int i = 0; i < preHeaderGapFillSize; i++) | ||||
| 		fullSector->push_back(GAP1_FILL_BYTE); | ||||
|         default: | ||||
|             Error() << "unsupported sector size --- you must pick 256 or 512"; | ||||
|             break; | ||||
|     } | ||||
|  | ||||
| 	/* sector preamble */ | ||||
| 	for (int i = 0; i < preambleSize; i++) | ||||
| 		fullSector->push_back(0); | ||||
|     int fullSectorSize = preambleSize + encodedSectorSize; | ||||
|     auto fullSector = std::make_shared<std::vector<uint8_t>>(); | ||||
|     fullSector->reserve(fullSectorSize); | ||||
|  | ||||
| 	Bytes sectorData; | ||||
| 	if (sector->data.size() == encodedSectorSize) | ||||
| 		sectorData = sector->data; | ||||
| 	else { | ||||
| 		ByteWriter writer(sectorData); | ||||
| 		writer.write_8(0xFB);     /* sync character */ | ||||
| 		if (doubleDensity == true) { | ||||
| 			writer.write_8(0xFB); /* Double-density has two sync characters */ | ||||
| 		} | ||||
| 		writer += sector->data; | ||||
| 		if (doubleDensity == true) { | ||||
| 			writer.write_8(northstarChecksum(sectorData.slice(2))); | ||||
| 		} else { | ||||
| 			writer.write_8(northstarChecksum(sectorData.slice(1))); | ||||
| 		} | ||||
| 	} | ||||
| 	for (uint8_t b : sectorData) | ||||
| 		fullSector->push_back(b); | ||||
|     /* sector gap after index pulse */ | ||||
|     for (int i = 0; i < preHeaderGapFillSize; i++) | ||||
|         fullSector->push_back(GAP1_FILL_BYTE); | ||||
|  | ||||
| 	if (sector->logicalSector != 9) { | ||||
| 		/* sector postamble */ | ||||
| 		for (int i = 0; i < gapFillSize; i++) | ||||
| 			fullSector->push_back(GAP2_FILL_BYTE); | ||||
|     /* sector preamble */ | ||||
|     for (int i = 0; i < preambleSize; i++) | ||||
|         fullSector->push_back(0); | ||||
|  | ||||
| 		if (fullSector->size() != fullSectorSize) | ||||
| 			Error() << "sector mismatched length (" << sector->data.size() << ") expected: " << fullSector->size() << " got " << fullSectorSize; | ||||
| 	} else { | ||||
| 		/* sector postamble */ | ||||
| 		for (int i = 0; i < gapFillSize; i++) | ||||
| 			fullSector->push_back(GAP2_FILL_BYTE); | ||||
| 	} | ||||
|     Bytes sectorData; | ||||
|     if (sector->data.size() == encodedSectorSize) | ||||
|         sectorData = sector->data; | ||||
|     else | ||||
|     { | ||||
|         ByteWriter writer(sectorData); | ||||
|         writer.write_8(0xFB); /* sync character */ | ||||
|         if (doubleDensity == true) | ||||
|             writer.write_8(0xFB); /* Double-density has two sync characters */ | ||||
|  | ||||
| 	bool lastBit = false; | ||||
|         writer += sector->data; | ||||
|         if (doubleDensity == true) | ||||
|             writer.write_8(northstarChecksum(sectorData.slice(2))); | ||||
|         else | ||||
|             writer.write_8(northstarChecksum(sectorData.slice(1))); | ||||
|     } | ||||
|     for (uint8_t b : sectorData) | ||||
|         fullSector->push_back(b); | ||||
|  | ||||
| 	if (doubleDensity == true) { | ||||
| 		encodeMfm(bits, cursor, fullSector, lastBit); | ||||
| 	} | ||||
| 	else { | ||||
| 		encodeFm(bits, cursor, fullSector); | ||||
| 	} | ||||
|     if (fullSector->size() != fullSectorSize) | ||||
|         Error() << "sector mismatched length (" << sector->data.size() | ||||
|                 << ") expected: " << fullSector->size() << " got " | ||||
|                 << fullSectorSize; | ||||
|  | ||||
|     /* A few bytes of sector postamble just so the blank skip area doesn't start | ||||
|      * immediately after the data. */ | ||||
|  | ||||
|     for (int i = 0; i < 10; i++) | ||||
|         fullSector->push_back(GAP2_FILL_BYTE); | ||||
|  | ||||
|     bool lastBit = false; | ||||
|  | ||||
|     if (doubleDensity == true) | ||||
|         encodeMfm(bits, cursor, fullSector, lastBit); | ||||
|     else | ||||
|         encodeFm(bits, cursor, fullSector); | ||||
| } | ||||
|  | ||||
| class NorthstarEncoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
| 	NorthstarEncoder(const EncoderProto& config): | ||||
| 		AbstractEncoder(config), | ||||
| 		_config(config.northstar()) | ||||
| 	{} | ||||
|     NorthstarEncoder(const EncoderProto& config): | ||||
|         AbstractEncoder(config), | ||||
|         _config(config.northstar()) | ||||
|     { | ||||
|     } | ||||
|  | ||||
| 	std::vector<std::shared_ptr<const Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override | ||||
| 	{ | ||||
| 		std::vector<std::shared_ptr<const Sector>> sectors; | ||||
|     std::vector<std::shared_ptr<const Sector>> collectSectors( | ||||
|         int physicalTrack, int physicalSide, const Image& image) override | ||||
|     { | ||||
|         std::vector<std::shared_ptr<const Sector>> sectors; | ||||
|  | ||||
| 		if ((physicalTrack >= 0) && (physicalTrack < 35)) | ||||
| 		{ | ||||
| 			for (int sectorId = 0; sectorId < 10; sectorId++) | ||||
| 			{ | ||||
| 				const auto& sector = image.get(physicalTrack, physicalSide, sectorId); | ||||
| 				if (sector) | ||||
| 					sectors.push_back(sector); | ||||
| 			} | ||||
| 		} | ||||
|         if ((physicalTrack >= 0) && (physicalTrack < 35)) | ||||
|         { | ||||
|             for (int sectorId = 0; sectorId < 10; sectorId++) | ||||
|             { | ||||
|                 const auto& sector = | ||||
|                     image.get(physicalTrack, physicalSide, sectorId); | ||||
|                 if (sector) | ||||
|                     sectors.push_back(sector); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| 		return sectors; | ||||
| 	} | ||||
|         return sectors; | ||||
|     } | ||||
|  | ||||
| 	std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, | ||||
| 			const std::vector<std::shared_ptr<const Sector>>& sectors, const Image& image) override | ||||
| 	{ | ||||
| 		int bitsPerRevolution = 100000; | ||||
| 		double clockRateUs = 4.00; | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, | ||||
|         int physicalSide, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
|         int bitsPerRevolution = 100000; | ||||
|         double clockRateUs = 4.00; | ||||
|  | ||||
| 		if ((physicalTrack < 0) || (physicalTrack >= 35) || sectors.empty()) | ||||
| 			return std::unique_ptr<Fluxmap>(); | ||||
|         if ((physicalTrack < 0) || (physicalTrack >= 35) || sectors.empty()) | ||||
|             return std::unique_ptr<Fluxmap>(); | ||||
|  | ||||
| 		const auto& sector = *sectors.begin(); | ||||
| 		if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD) { | ||||
| 			bitsPerRevolution /= 2;		// FM | ||||
| 		} else { | ||||
| 			clockRateUs /= 2.00; | ||||
| 		} | ||||
|         const auto& sector = *sectors.begin(); | ||||
|         if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD) | ||||
|             bitsPerRevolution /= 2; // FM | ||||
|         else | ||||
|             clockRateUs /= 2.00; | ||||
|  | ||||
| 		std::vector<bool> bits(bitsPerRevolution); | ||||
| 		unsigned cursor = 0; | ||||
|         auto fluxmap = std::make_unique<Fluxmap>(); | ||||
| 		bool first = true; | ||||
|         for (const auto& sectorData : sectors) | ||||
|         { | ||||
| 			if (!first) | ||||
| 				fluxmap->appendIndex(); | ||||
| 			first = false; | ||||
|  | ||||
| 		for (const auto& sectorData : sectors) | ||||
| 			write_sector(bits, cursor, sectorData); | ||||
|             std::vector<bool> bits(bitsPerRevolution); | ||||
|             unsigned cursor = 0; | ||||
|             write_sector(bits, cursor, sectorData); | ||||
|             fluxmap->appendBits(bits, clockRateUs * 1e3); | ||||
|         } | ||||
|  | ||||
| 		if (cursor > bits.size()) | ||||
| 			Error() << "track data overrun"; | ||||
| //        if (fluxmap->duration() > 200e6) | ||||
| //            Error() << "track data overrun"; | ||||
|  | ||||
| 		std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
| 		fluxmap->appendBits(bits, clockRateUs * 1e3); | ||||
| 		return fluxmap; | ||||
| 	} | ||||
|         return fluxmap; | ||||
|     } | ||||
|  | ||||
| private: | ||||
| 	const NorthstarEncoderProto& _config; | ||||
|     const NorthstarEncoderProto& _config; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<AbstractEncoder> createNorthstarEncoder(const EncoderProto& config) | ||||
| std::unique_ptr<AbstractEncoder> createNorthstarEncoder( | ||||
|     const EncoderProto& config) | ||||
| { | ||||
| 	return std::unique_ptr<AbstractEncoder>(new NorthstarEncoder(config)); | ||||
|     return std::unique_ptr<AbstractEncoder>(new NorthstarEncoder(config)); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -56,4 +56,3 @@ Fluxmap& Fluxmap::appendBits(const std::vector<bool>& bits, nanoseconds_t clock) | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -17,41 +17,60 @@ public: | ||||
|         unsigned zeroes = 0; | ||||
|  | ||||
|         nanoseconds_t ns() const | ||||
|         { return ticks * NS_PER_TICK; } | ||||
|         { | ||||
|             return ticks * NS_PER_TICK; | ||||
|         } | ||||
|  | ||||
|         operator std::string () { | ||||
|         operator std::string() | ||||
|         { | ||||
|             return fmt::format("[b:{}, t:{}, z:{}]", bytes, ticks, zeroes); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| public: | ||||
| 	Fluxmap() {} | ||||
|     Fluxmap() {} | ||||
|  | ||||
| 	Fluxmap(const std::string& s) | ||||
| 	{ | ||||
| 		appendBytes((const uint8_t*) s.c_str(), s.size()); | ||||
| 	} | ||||
|     Fluxmap(const std::string& s) | ||||
|     { | ||||
|         appendBytes((const uint8_t*)s.c_str(), s.size()); | ||||
|     } | ||||
|  | ||||
| 	Fluxmap(const Bytes bytes): | ||||
| 		_bytes(bytes) | ||||
| 	{} | ||||
|     Fluxmap(const Bytes& bytes) | ||||
|     { | ||||
|         appendBytes(bytes); | ||||
|     } | ||||
|  | ||||
|     nanoseconds_t duration() const { return _duration; } | ||||
|     unsigned ticks() const { return _ticks; } | ||||
|     size_t bytes() const { return _bytes.size(); } | ||||
|     const Bytes& rawBytes() const { return _bytes; } | ||||
|     nanoseconds_t duration() const | ||||
|     { | ||||
|         return _duration; | ||||
|     } | ||||
|  | ||||
|     unsigned ticks() const | ||||
|     { | ||||
|         return _ticks; | ||||
|     } | ||||
|  | ||||
|     size_t bytes() const | ||||
|     { | ||||
|         return _bytes.size(); | ||||
|     } | ||||
|  | ||||
|     const Bytes& rawBytes() const | ||||
|     { | ||||
|         return _bytes; | ||||
|     } | ||||
|  | ||||
|     const uint8_t* ptr() const | ||||
| 	{ | ||||
| 		if (!_bytes.empty()) | ||||
| 			return &_bytes[0]; | ||||
| 		return NULL; | ||||
| 	} | ||||
|     { | ||||
|         if (!_bytes.empty()) | ||||
|             return &_bytes[0]; | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     Fluxmap& appendInterval(uint32_t ticks); | ||||
|     Fluxmap& appendPulse(); | ||||
|     Fluxmap& appendIndex(); | ||||
| 	Fluxmap& appendDesync(); | ||||
|     Fluxmap& appendDesync(); | ||||
|  | ||||
|     Fluxmap& appendBytes(const Bytes& bytes); | ||||
|     Fluxmap& appendBytes(const uint8_t* ptr, size_t len); | ||||
| @@ -61,14 +80,14 @@ public: | ||||
|         return appendBytes(&byte, 1); | ||||
|     } | ||||
|  | ||||
| 	Fluxmap& appendBits(const std::vector<bool>& bits, nanoseconds_t clock); | ||||
|     Fluxmap& appendBits(const std::vector<bool>& bits, nanoseconds_t clock); | ||||
|  | ||||
|     void precompensate(int threshold_ticks, int amount_ticks); | ||||
|     std::vector<std::unique_ptr<const Fluxmap>> split() const; | ||||
|     std::unique_ptr<const Fluxmap> rescale(double scale) const; | ||||
|  | ||||
| private: | ||||
| 	uint8_t& findLastByte(); | ||||
|     uint8_t& findLastByte(); | ||||
|  | ||||
| private: | ||||
|     nanoseconds_t _duration = 0; | ||||
|   | ||||
| @@ -322,10 +322,10 @@ encodedecodetest() { | ||||
|     echo "    format=$format" | ||||
|     echo "    configs=$*" | ||||
|     echo "    fluxx=flux" | ||||
|     echo "build $OBJDIR/$format.encodedecode.scp.stamp : encodedecode | fluxengine$EXTENSION scripts/encodedecodetest.sh $*" | ||||
|     echo "    format=$format" | ||||
|     echo "    configs=$*" | ||||
|     echo "    fluxx=scp" | ||||
|     #echo "build $OBJDIR/$format.encodedecode.scp.stamp : encodedecode | fluxengine$EXTENSION scripts/encodedecodetest.sh $*" | ||||
|     #echo "    format=$format" | ||||
|     #echo "    configs=$*" | ||||
|     #echo "    fluxx=scp" | ||||
| } | ||||
|  | ||||
| buildlibrary libagg.a \ | ||||
| @@ -677,6 +677,7 @@ encodedecodetest rx50 | ||||
| encodedecodetest tids990 | ||||
| encodedecodetest victor9k_ss | ||||
| encodedecodetest victor9k_ds | ||||
| encodedecodetest northstar87 scripts/northstar87_test.textpb | ||||
|  | ||||
| # vim: sw=4 ts=4 et | ||||
|  | ||||
|   | ||||
							
								
								
									
										29
									
								
								scripts/northstar87_test.textpb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								scripts/northstar87_test.textpb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| image_reader { | ||||
| 	img { | ||||
| 		tracks: 35 | ||||
| 		sides: 1 | ||||
| 		trackdata { | ||||
| 			sector_size: 256 | ||||
| 			sector_range { | ||||
| 				start_sector: 0 | ||||
| 				sector_count: 10 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| image_writer { | ||||
| 	img { | ||||
| 		tracks: 35 | ||||
| 		sides: 1 | ||||
| 		trackdata { | ||||
| 			sector_size: 256 | ||||
| 			sector_range { | ||||
| 				start_sector: 0 | ||||
| 				sector_count: 10 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user