mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-31 11:17:01 -07:00 
			
		
		
		
	Compare commits
	
		
			9 Commits
		
	
	
		
			FluxEngine
			...
			FluxEngine
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e0256adf77 | ||
|  | 5748f017dd | ||
|  | 973f4c2c2d | ||
|  | 8e1774c69f | ||
|  | 56a36072f7 | ||
|  | 8755d108ed | ||
|  | ea40cd73d1 | ||
|  | 0e28899b72 | ||
|  | eee30db981 | 
| @@ -2310,13 +2310,13 @@ | ||||
| <CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3"> | ||||
| <CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DEBUG_PINS" persistent=""> | ||||
| <Hidden v="True" /> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2"> | ||||
| <dependencies> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DEBUG_PINS_aliases.h" persistent="Generated_Source\PSoC5\DEBUG_PINS_aliases.h"> | ||||
| <Hidden v="True" /> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| @@ -3249,6 +3249,39 @@ | ||||
| </CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8> | ||||
| <filters /> | ||||
| </CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0> | ||||
| <CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3"> | ||||
| <CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="CAPTURE_CONTROL" persistent=""> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2"> | ||||
| <dependencies> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="CAPTURE_CONTROL.h" persistent="Generated_Source\PSoC5\CAPTURE_CONTROL.h"> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="HEADER;;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="CAPTURE_CONTROL.c" persistent="Generated_Source\PSoC5\CAPTURE_CONTROL.c"> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="SOURCE_C;CortexM3;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| <CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1"> | ||||
| <CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="CAPTURE_CONTROL_PM.c" persistent="Generated_Source\PSoC5\CAPTURE_CONTROL_PM.c"> | ||||
| <Hidden v="False" /> | ||||
| </CyGuid_31768f72-0253-412b-af77-e7dba74d1330> | ||||
| <build_action v="SOURCE_C;CortexM3;;;" /> | ||||
| <PropertyDeltas /> | ||||
| </CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b> | ||||
| </dependencies> | ||||
| </CyGuid_0820c2e7-528d-4137-9a08-97257b946089> | ||||
| </CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8> | ||||
| <filters /> | ||||
| </CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0> | ||||
| </dependencies> | ||||
| </CyGuid_0820c2e7-528d-4137-9a08-97257b946089> | ||||
| </CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8> | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -306,6 +306,7 @@ static void cmd_read(struct read_frame* f) | ||||
|     dma_underrun = false; | ||||
|     int count = 0; | ||||
|     SAMPLER_CONTROL_Write(0); /* !reset */ | ||||
|     CAPTURE_CONTROL_Write(1); | ||||
|     CyDmaChSetInitialTd(dma_channel, td[dma_writing_to_td]); | ||||
|     CyDmaClearPendingDrq(dma_channel); | ||||
|     CyDmaChEnable(dma_channel, 1); | ||||
| @@ -364,7 +365,8 @@ static void cmd_read(struct read_frame* f) | ||||
|         } | ||||
|         dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td); | ||||
|     } | ||||
| abort: | ||||
| abort:; | ||||
|     CAPTURE_CONTROL_Write(0); | ||||
|     CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN); | ||||
|     while (CyDmaChGetRequest(dma_channel)) | ||||
|         ; | ||||
|   | ||||
| @@ -89,7 +89,7 @@ people who've had it work). | ||||
| | [Brother 120kB](doc/disk-brother.md)     |  🦄   |        |                                     | | ||||
| | [Brother 240kB](doc/disk-brother.md)     |  🦄   |   🦄   |                                     | | ||||
| | [Brother FB-100](doc/disk-fb100.md)      |  🦖   |        | Tandy Model 100, Husky Hunter, knitting machines | | ||||
| | [Macintosh 800kB](doc/disk-macintosh.md) |  🦖   |        | and probably the 400kB too          | | ||||
| | [Macintosh 800kB](doc/disk-macintosh.md) |  🦄   |        | and probably the 400kB too          | | ||||
| | [TRS-80](doc/disk-trs80.md)              |  🦖   |        | a minor variation of the IBM scheme | | ||||
| {: .datatable } | ||||
|  | ||||
| @@ -105,6 +105,7 @@ at least, check the CRC so what data's there is probably good. | ||||
| |:-----------------------------------------|:-----:|:------:|-------| | ||||
| | [AES Superplus / No Problem](doc/disk-aeslanier.md) |  🦖   | | hard sectors! | | ||||
| | [Durango F85](doc/disk-durangof85.md)    |  🦖   |        | 5.25" | | ||||
| | [DVK MX](doc/disk-mx.md)                 |  🦖   |        | Soviet PDP-11 clone | | ||||
| | [Victor 9000](doc/disk-victor9k.md)      |  🦖   |        | 8-inch        | | ||||
| | [Zilog MCZ](doc/disk-zilogmcz.md)        |  🦖   |        | 8-inch _and_ hard sectors | | ||||
| {: .datatable } | ||||
| @@ -189,7 +190,7 @@ Jonathan Müller (`foonathan <https://github.com/foonathan>`) with | ||||
| contributions from many other people. It is licensed under the terms of the | ||||
| BSD license. Please see the contents of the directory for the full text. | ||||
|  | ||||
| As an exception, `dep/fnmatchemu` contains parts of the OpenBSD C library | ||||
| As an exception, `dep/emu` contains parts of the OpenBSD C library | ||||
| code, Todd Miller and William A. Rowe (and probably others). It is licensed | ||||
| under the terms of the 3-clause BSD license. Please see the contents of the | ||||
| directory for the full text. It's been lightly modified by me. | ||||
|   | ||||
							
								
								
									
										65
									
								
								doc/disk-mx.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								doc/disk-mx.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| Disk: DVK MX | ||||
| ============ | ||||
|  | ||||
| The DVK (in Russian, ДВК, Диалоговый вычислительный комплекс or Dialogue | ||||
| Computing Complex) was a late 1970s Soviet personal computer, a cut-down | ||||
| version of the professional SM EVM (СМ ЭВМ, abbreviation of Система Малых ЭВМ | ||||
| --- literally System of Mini Computers), which _itself_ was an unlicensed | ||||
| clone of the PDP-11. The MX board was an early floppy drive controller board | ||||
| for it. | ||||
|  | ||||
| <div style="text-align: center"> | ||||
| <a href="http://www.leningrad.su/museum/show_big.php?n=1006"><img src="dvk3m.jpg" style="max-width: 60%" alt="A Durango F85, held precariously"></a> | ||||
| </div> | ||||
|  | ||||
| The MX format is interesting in that it has to be read a track at a time. The | ||||
| format contains the usual ID prologue at the beginning of the track, then | ||||
| eleven data blocks and checksums, then the epilogue, then it stops. The | ||||
| actual encoding is normal FM. There were four different disk variants, in all | ||||
| combinations of single- and double-sided and 40- and 80-tracked; but every | ||||
| track contained eleven 256-byte sectors. | ||||
|  | ||||
| The format varies subtly depending on whether you're using the 'new' driver | ||||
| or the 'old' driver. FluxEngine should read both. | ||||
|  | ||||
| A track is: | ||||
|  | ||||
|   * 8 x 0x0000 words (FM encoded as 01010101...) | ||||
|   * 1 x 0x00F3 --- start of track | ||||
|   * 1 x 0xnnnn --- track number | ||||
|   * 11 of: | ||||
|     * 128 words (256 bytes) of data | ||||
|     * 16 bit checksum | ||||
|   * **if 'new' format:** | ||||
|     * 3 x 0x83nn --- `n = (track_number<<1) + side_number` | ||||
|   * **if 'old' format:** | ||||
|     * 3 x 0x8301 | ||||
|  | ||||
| The checksum is just the unsigned integer sum of all the words in the sector. | ||||
| Words are all stored little-endian. | ||||
|  | ||||
| Reading discs | ||||
| ------------- | ||||
|  | ||||
| ``` | ||||
| fluxengine read mx | ||||
| ``` | ||||
|  | ||||
| You should end up with an `mx.img` which will vary in length depending on the format. The default is double-sided 80-track. For the other formats, use: | ||||
|  | ||||
|   * single-sided 40-track: `-s :s=0:t=0-79x2` | ||||
|   * double-sided 40-track: `-s :s=0-1:t=0-79x2` | ||||
|   * single-sided 40-track: `-s :s=0:t=0-79` | ||||
|   * double-sided 40-track: `-s :s=0-1:t=0-79` | ||||
|  | ||||
|  | ||||
| Useful references | ||||
| ----------------- | ||||
|  | ||||
|   - [The Soviet Digital Electronics | ||||
|     Museum](http://www.leningrad.su/museum/main.php) (source of the image | ||||
|     above) | ||||
|  | ||||
|   - [a random post on the HxC2001 support | ||||
|     forum](http://torlus.com/floppy/forum/viewtopic.php?t=1384) with lots of | ||||
|     information on the format | ||||
							
								
								
									
										
											BIN
										
									
								
								doc/dvk3m.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								doc/dvk3m.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 159 KiB | 
| @@ -9,6 +9,9 @@ | ||||
| #define BROTHER_DATA_RECORD_CHECKSUM     3 | ||||
| #define BROTHER_DATA_RECORD_ENCODED_SIZE 415 | ||||
|  | ||||
| #define BROTHER_TRACKS_PER_DISK          78 | ||||
| #define BROTHER_SECTORS_PER_TRACK        12 | ||||
|  | ||||
| class Sector; | ||||
| class Fluxmap; | ||||
|  | ||||
| @@ -22,9 +25,15 @@ public: | ||||
|     void decodeDataRecord(); | ||||
| }; | ||||
|  | ||||
| extern void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor, | ||||
| 		int track, int sector); | ||||
| extern void writeBrotherSectorData(std::vector<bool>& bits, unsigned& cursor, | ||||
| 		const Bytes& data); | ||||
| class BrotherEncoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
| 	virtual ~BrotherEncoder() {} | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); | ||||
| }; | ||||
|  | ||||
| extern FlagGroup brotherEncoderFlags; | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "record.h" | ||||
| #include "brother.h" | ||||
| #include "sector.h" | ||||
|   | ||||
| @@ -1,8 +1,38 @@ | ||||
| #include "globals.h" | ||||
| #include "record.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "brother.h" | ||||
| #include "crc.h" | ||||
| #include "sectorset.h" | ||||
| #include "writer.h" | ||||
|  | ||||
| FlagGroup brotherEncoderFlags; | ||||
|  | ||||
| static DoubleFlag clockRateUs( | ||||
| 	{ "--clock-rate" }, | ||||
| 	"Encoded data clock rate (microseconds).", | ||||
| 	3.83); | ||||
|  | ||||
| static DoubleFlag postIndexGapMs( | ||||
| 	{ "--post-index-gap" }, | ||||
| 	"Post-index gap before first sector header (milliseconds).", | ||||
| 	1.0); | ||||
|  | ||||
| static DoubleFlag sectorSpacingMs( | ||||
| 	{ "--sector-spacing" }, | ||||
| 	"Time between successive sector headers (milliseconds).", | ||||
| 	16.2); | ||||
|  | ||||
| static DoubleFlag postHeaderSpacingMs( | ||||
| 	{ "--post-header-spacing" }, | ||||
| 	"Time between a sector's header and data records (milliseconds).", | ||||
| 	0.69); | ||||
|  | ||||
| static StringFlag sectorSkew( | ||||
| 	{ "--sector-skew" }, | ||||
| 	"Order in which to write sectors.", | ||||
| 	"05a3816b4927"); | ||||
|  | ||||
| static int encode_header_gcr(uint16_t word) | ||||
| { | ||||
| @@ -40,7 +70,7 @@ static void write_bits(std::vector<bool>& bits, unsigned& cursor, uint32_t data, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor, | ||||
| static void write_sector_header(std::vector<bool>& bits, unsigned& cursor, | ||||
| 		int track, int sector) | ||||
| { | ||||
| 	write_bits(bits, cursor, 0xffffffff, 31); | ||||
| @@ -50,7 +80,7 @@ void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor, | ||||
| 	write_bits(bits, cursor, encode_header_gcr(0x2f), 16); | ||||
| } | ||||
|  | ||||
| void writeBrotherSectorData(std::vector<bool>& bits, unsigned& cursor, const Bytes& data) | ||||
| static void write_sector_data(std::vector<bool>& bits, unsigned& cursor, const Bytes& data) | ||||
| { | ||||
| 	write_bits(bits, cursor, 0xffffffff, 32); | ||||
| 	write_bits(bits, cursor, BROTHER_DATA_RECORD, 32); | ||||
| @@ -89,4 +119,49 @@ void writeBrotherSectorData(std::vector<bool>& bits, unsigned& cursor, const Byt | ||||
|         write_byte(0); | ||||
| } | ||||
|  | ||||
| static int charToInt(char c) | ||||
| { | ||||
| 	if (isdigit(c)) | ||||
| 		return c - '0'; | ||||
| 	return 10 + tolower(c) - 'a'; | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Fluxmap> BrotherEncoder::encode( | ||||
| 	int physicalTrack, int physicalSide, const SectorSet& allSectors) | ||||
| { | ||||
| 	if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_DISK) | ||||
|         || (physicalSide != 0)) | ||||
| 		return std::unique_ptr<Fluxmap>(); | ||||
|  | ||||
| 	int bitsPerRevolution = 200000.0 / clockRateUs; | ||||
| 	const std::string& skew = sectorSkew.get(); | ||||
| 	std::vector<bool> bits(bitsPerRevolution); | ||||
| 	unsigned cursor = 0; | ||||
|  | ||||
| 	for (int sectorCount=0; sectorCount<BROTHER_SECTORS_PER_TRACK; sectorCount++) | ||||
| 	{ | ||||
| 		int sectorId = charToInt(skew.at(sectorCount)); | ||||
| 		double headerMs = postIndexGapMs + sectorCount*sectorSpacingMs; | ||||
| 		unsigned headerCursor = headerMs*1e3 / clockRateUs; | ||||
| 		double dataMs = headerMs + postHeaderSpacingMs; | ||||
| 		unsigned dataCursor = dataMs*1e3 / clockRateUs; | ||||
|  | ||||
| 		const auto& sectorData = allSectors.get(physicalTrack, 0, sectorId); | ||||
|  | ||||
| 		fillBitmapTo(bits, cursor, headerCursor, { true, false }); | ||||
| 		write_sector_header(bits, cursor, physicalTrack, sectorId); | ||||
| 		fillBitmapTo(bits, cursor, dataCursor, { true, false }); | ||||
| 		write_sector_data(bits, cursor, sectorData->data); | ||||
| 	} | ||||
|  | ||||
| 	if (cursor > bits.size()) | ||||
| 		Error() << "track data overrun"; | ||||
| 	fillBitmapTo(bits, cursor, bits.size(), { true, false }); | ||||
|  | ||||
| 	// The pre-index gap is not normally reported. | ||||
| 	// std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl; | ||||
| 	 | ||||
| 	std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
| 	fluxmap->appendBits(bits, clockRateUs*1e3); | ||||
| 	return fluxmap; | ||||
| } | ||||
|   | ||||
							
								
								
									
										18
									
								
								lib/encoders/encoders.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								lib/encoders/encoders.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| #ifndef ENCODERS_H | ||||
| #define ENCODERS_H | ||||
|  | ||||
| class Fluxmap; | ||||
| class SectorSet; | ||||
|  | ||||
| class AbstractEncoder | ||||
| { | ||||
| public: | ||||
|     virtual ~AbstractEncoder() {} | ||||
|  | ||||
| public: | ||||
|     virtual std::unique_ptr<Fluxmap> encode( | ||||
|         int physicalTrack, int physicalSide, const SectorSet& allSectors) = 0; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|  | ||||
| @@ -153,6 +153,9 @@ void MacintoshDecoder::decodeSectorRecord() | ||||
|     uint8_t formatByte = decode_data_gcr(header[3]); | ||||
|     uint8_t wantedsum = decode_data_gcr(header[4]); | ||||
|  | ||||
|     if (encodedSector > 11) | ||||
|         return; | ||||
|  | ||||
|     _sector->logicalTrack = _track->physicalTrack; | ||||
|     _sector->logicalSide = decode_side(encodedSide); | ||||
|     _sector->logicalSector = encodedSector; | ||||
|   | ||||
| @@ -37,7 +37,7 @@ AbstractDecoder::RecordType MxDecoder::advanceToNextRecord() | ||||
|         const FluxMatcher* matcher = nullptr; | ||||
|         _sector->clock = _clock = _fmr->seekToPattern(ID_PATTERN, matcher); | ||||
|         readRawBits(32); /* skip the ID mark */ | ||||
|         readRawBits(32); /* skip the track number */ | ||||
|         _logicalTrack = decodeFmMfm(readRawBits(32)).reader().read_be16(); | ||||
|     } | ||||
|     else if (_currentSector == 10) | ||||
|     { | ||||
| @@ -67,7 +67,7 @@ void MxDecoder::decodeSectorRecord() | ||||
|         gotChecksum += br.read_le16(); | ||||
|     uint16_t wantChecksum = br.read_le16(); | ||||
|  | ||||
|     _sector->logicalTrack = _track->physicalTrack; | ||||
|     _sector->logicalTrack = _logicalTrack; | ||||
|     _sector->logicalSide = _track->physicalSide; | ||||
|     _sector->logicalSector = _currentSector; | ||||
|     _sector->data = bytes.slice(0, SECTOR_SIZE); | ||||
|   | ||||
| @@ -15,6 +15,7 @@ public: | ||||
| private: | ||||
|     nanoseconds_t _clock; | ||||
|     int _currentSector; | ||||
|     int _logicalTrack; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -160,8 +160,9 @@ void readDiskCommand(AbstractDecoder& decoder, const std::string& outputFilename | ||||
| 					track->rawrecords.size(), | ||||
| 					track->sectors.size()); | ||||
| 				if (track->sectors.size() > 0) | ||||
| 					std::cout << fmt::format("{:.2f}us clock; ", | ||||
| 						track->sectors.begin()->clock / 1000.0); | ||||
| 					std::cout << fmt::format("{:.2f}us clock ({:.0f}kHz); ", | ||||
| 						track->sectors.begin()->clock / 1000.0, | ||||
|                         1000000.0 / track->sectors.begin()->clock); | ||||
|  | ||||
| 				for (auto& sector : track->sectors) | ||||
| 				{ | ||||
|   | ||||
| @@ -6,9 +6,14 @@ | ||||
| #include "protocol.h" | ||||
| #include "usb.h" | ||||
| #include "dataspec.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "fluxsource/fluxsource.h" | ||||
| #include "fluxsink/fluxsink.h" | ||||
| #include "fmt/format.h" | ||||
| #include "record.h" | ||||
| #include "image.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
|  | ||||
| FlagGroup writerFlags { &hardwareFluxSourceFlags }; | ||||
|  | ||||
| @@ -60,10 +65,12 @@ void writeTracks( | ||||
|         { | ||||
|             if (!outdb) | ||||
|             { | ||||
|                 std::cout << "erasing" << std::endl; | ||||
|                 std::cout << "erasing\n"; | ||||
|                 usbSeek(location.track); | ||||
|                 usbErase(location.side); | ||||
|             } | ||||
|             else | ||||
|                 std::cout << "skipping\n"; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
| @@ -96,3 +103,16 @@ void fillBitmapTo(std::vector<bool>& bitmap, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void writeDiskCommand( | ||||
|     AbstractEncoder& encoder, const Geometry& geometry, const std::string& inputFilename) | ||||
| { | ||||
|     SectorSet allSectors; | ||||
|  | ||||
| 	readSectorsFromFile(allSectors, geometry, inputFilename); | ||||
| 	writeTracks( | ||||
| 		[&](int track, int side) -> std::unique_ptr<Fluxmap> | ||||
| 		{ | ||||
| 			return encoder.encode(track, side, allSectors); | ||||
| 		} | ||||
| 	); | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,8 @@ | ||||
| extern FlagGroup writerFlags; | ||||
|  | ||||
| class Fluxmap; | ||||
| class AbstractEncoder; | ||||
| class Geometry; | ||||
|  | ||||
| extern void setWriterDefaultDest(const std::string& dest); | ||||
|  | ||||
| @@ -15,5 +17,7 @@ extern void fillBitmapTo(std::vector<bool>& bitmap, | ||||
| 		unsigned& cursor, unsigned terminateAt, | ||||
| 		const std::vector<bool>& pattern); | ||||
| 	 | ||||
| extern void writeDiskCommand( | ||||
|     AbstractEncoder& encoder, const Geometry& geometry, const std::string& inputFilename); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -150,7 +150,7 @@ buildlibrary libbackend.a \ | ||||
|     lib/decoders/decoders.cc \ | ||||
|     lib/decoders/fluxmapreader.cc \ | ||||
|     lib/decoders/fmmfm.cc \ | ||||
|     lib/encoder.cc \ | ||||
|     lib/encoders/encoders.cc \ | ||||
|     lib/f85/decoder.cc \ | ||||
|     lib/fb100/decoder.cc \ | ||||
|     lib/flags.cc \ | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #include "reader.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "brother/brother.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
|   | ||||
| @@ -1,108 +1,28 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "fluxmap.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "brother/brother.h" | ||||
| #include "image.h" | ||||
| #include "writer.h" | ||||
| #include "fmt/format.h" | ||||
| #include "image.h" | ||||
| #include <fstream> | ||||
| #include <ctype.h> | ||||
|  | ||||
| static FlagGroup flags { &writerFlags }; | ||||
| static FlagGroup flags { &writerFlags, &brotherEncoderFlags }; | ||||
|  | ||||
| static StringFlag inputFilename( | ||||
|     { "--input", "-i" }, | ||||
|     "The input image file to read from.", | ||||
|     "brother.img"); | ||||
|  | ||||
| static DoubleFlag clockRateUs( | ||||
| 	{ "--clock-rate" }, | ||||
| 	"Encoded data clock rate (microseconds).", | ||||
| 	3.83); | ||||
|  | ||||
| static DoubleFlag postIndexGapMs( | ||||
| 	{ "--post-index-gap" }, | ||||
| 	"Post-index gap before first sector header (milliseconds).", | ||||
| 	1.0); | ||||
|  | ||||
| static DoubleFlag sectorSpacingMs( | ||||
| 	{ "--sector-spacing" }, | ||||
| 	"Time between successive sector headers (milliseconds).", | ||||
| 	16.2); | ||||
|  | ||||
| static DoubleFlag postHeaderSpacingMs( | ||||
| 	{ "--post-header-spacing" }, | ||||
| 	"Time between a sector's header and data records (milliseconds).", | ||||
| 	0.69); | ||||
|  | ||||
|  | ||||
| static StringFlag sectorSkew( | ||||
| 	{ "--sector-skew" }, | ||||
| 	"Order in which to write sectors.", | ||||
| 	"05a3816b4927"); | ||||
|  | ||||
| static int charToInt(char c) | ||||
| { | ||||
| 	if (isdigit(c)) | ||||
| 		return c - '0'; | ||||
| 	return 10 + tolower(c) - 'a'; | ||||
| } | ||||
|  | ||||
| int mainWriteBrother(int argc, const char* argv[]) | ||||
| { | ||||
| 	setWriterDefaultDest(":d=0:t=0-77:s=0"); | ||||
|     flags.parseFlags(argc, argv); | ||||
|  | ||||
| 	SectorSet allSectors; | ||||
| 	BrotherEncoder encoder; | ||||
| 	Geometry geometry = {78, 1, 12, 256}; | ||||
| 	readSectorsFromFile(allSectors, geometry, inputFilename); | ||||
|  | ||||
| 	int bitsPerRevolution = 200000.0 / clockRateUs; | ||||
| 	std::cerr << bitsPerRevolution << " bits per 200ms revolution" << std::endl | ||||
| 	          << fmt::format("post-index gap: {:.3f}ms\n", (double)postIndexGapMs); | ||||
|  | ||||
| 	const std::string& skew = sectorSkew; | ||||
|  | ||||
| 	writeTracks( | ||||
| 		[&](int track, int side) -> std::unique_ptr<Fluxmap> | ||||
| 		{ | ||||
| 			if ((track < 0) || (track > 77) || (side != 0)) | ||||
| 				return std::unique_ptr<Fluxmap>(); | ||||
|  | ||||
| 			std::vector<bool> bits(bitsPerRevolution); | ||||
| 			unsigned cursor = 0; | ||||
|  | ||||
| 			for (int sectorCount=0; sectorCount<geometry.sectors; sectorCount++) | ||||
| 			{ | ||||
| 				int sectorId = charToInt(skew.at(sectorCount)); | ||||
| 				double headerMs = postIndexGapMs + sectorCount*sectorSpacingMs; | ||||
| 				unsigned headerCursor = headerMs*1e3 / clockRateUs; | ||||
| 				double dataMs = headerMs + postHeaderSpacingMs; | ||||
| 				unsigned dataCursor = dataMs*1e3 / clockRateUs; | ||||
|  | ||||
| 				auto& sectorData = allSectors.get(track, 0, sectorId); | ||||
|  | ||||
| 				fillBitmapTo(bits, cursor, headerCursor, { true, false }); | ||||
| 				writeBrotherSectorHeader(bits, cursor, track, sectorId); | ||||
| 				fillBitmapTo(bits, cursor, dataCursor, { true, false }); | ||||
| 				writeBrotherSectorData(bits, cursor, sectorData->data); | ||||
| 			} | ||||
|  | ||||
| 			if (cursor > bits.size()) | ||||
| 				Error() << "track data overrun"; | ||||
|             fillBitmapTo(bits, cursor, bits.size(), { true, false }); | ||||
|  | ||||
| 			// The pre-index gap is not normally reported. | ||||
| 			// std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl; | ||||
| 			 | ||||
| 			std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
| 			fluxmap->appendBits(bits, clockRateUs*1e3); | ||||
| 			return fluxmap; | ||||
| 		} | ||||
| 	); | ||||
| 	writeDiskCommand(encoder, geometry, inputFilename); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user