mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Convert scptoflux to a proper flux source.
This commit is contained in:
		
							
								
								
									
										130
									
								
								lib/fluxsource/scpfluxsource.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								lib/fluxsource/scpfluxsource.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "kryoflux.h" | ||||
| #include "lib/fluxsource/fluxsource.pb.h" | ||||
| #include "fluxsource/fluxsource.h" | ||||
| #include "scp.h" | ||||
| #include "proto.h" | ||||
| #include "fmt/format.h" | ||||
| #include <fstream> | ||||
|  | ||||
| static int trackno(int strack) | ||||
| { | ||||
|     return strack >> 1; | ||||
| } | ||||
|  | ||||
| static int headno(int strack) | ||||
| { | ||||
|     return strack & 1; | ||||
| } | ||||
|  | ||||
| static int strackno(int track, int side) | ||||
| { | ||||
| 	return (track << 1) | side; | ||||
| } | ||||
|  | ||||
| class ScpFluxSource : public FluxSource | ||||
| { | ||||
| public: | ||||
|     ScpFluxSource(const ScpFluxSourceProto& config): | ||||
|         _config(config) | ||||
|     { | ||||
| 		_if.open(_config.filename(), std::ios::in | std::ios::binary); | ||||
| 		if (!_if.is_open()) | ||||
| 			Error() << fmt::format("cannot open input file '{}': {}", _config.filename(), strerror(errno)); | ||||
|  | ||||
| 		_if.read((char*) &_header, sizeof(_header)); | ||||
| 		check_for_error(); | ||||
|  | ||||
| 		if ((_header.file_id[0] != 'S') | ||||
| 				|| (_header.file_id[1] != 'C') | ||||
| 				|| (_header.file_id[2] != 'P')) | ||||
| 			Error() << "input not a SCP file"; | ||||
|  | ||||
| 		_resolution = 25 * (_header.resolution + 1); | ||||
| 		int startSide = (_header.heads == 2) ? 1 : 0; | ||||
| 		int endSide = (_header.heads == 1) ? 0 : 1; | ||||
|  | ||||
| 		if ((_header.cell_width != 0) && (_header.cell_width != 16)) | ||||
| 			Error() << "currently only 16-bit cells in SCP files are supported"; | ||||
|  | ||||
| 		std::cout << fmt::format("SCP tracks {}-{}, heads {}-{}\n", | ||||
| 			trackno(_header.start_track), trackno(_header.end_track), startSide, endSide); | ||||
| 		std::cout << fmt::format("SCP sample resolution: {} ns\n", _resolution); | ||||
| 	} | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> readFlux(int track, int side) | ||||
|     { | ||||
| 		int strack = strackno(track, side); | ||||
| 		uint32_t offset = Bytes(_header.track[strack], 4).reader().read_le32(); | ||||
| 		if (offset == 0) | ||||
| 			return std::unique_ptr<Fluxmap>(); | ||||
|  | ||||
| 		ScpTrack trackheader; | ||||
| 		_if.seekg(offset, std::ios::beg); | ||||
| 		_if.read((char*) &trackheader, sizeof(trackheader)); | ||||
| 		check_for_error(); | ||||
|  | ||||
| 		if ((trackheader.track_id[0] != 'T') | ||||
| 				|| (trackheader.track_id[1] != 'R') | ||||
| 				|| (trackheader.track_id[2] != 'K')) | ||||
| 			Error() << "corrupt SCP file"; | ||||
|  | ||||
| 		std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
| 		nanoseconds_t pending = 0; | ||||
| 		unsigned inputBytes = 0; | ||||
| 		for (int revolution = 0; revolution < _header.revolutions; revolution++) | ||||
| 		{ | ||||
| 			if (revolution != 0) | ||||
| 				fluxmap->appendIndex(); | ||||
|  | ||||
| 			uint32_t datalength = Bytes(trackheader.revolution[revolution].length, 4).reader().read_le32(); | ||||
| 			uint32_t dataoffset = Bytes(trackheader.revolution[revolution].offset, 4).reader().read_le32(); | ||||
|  | ||||
| 			Bytes data(datalength*2); | ||||
| 			_if.seekg(dataoffset + offset, std::ios::beg); | ||||
| 			_if.read((char*) data.begin(), data.size()); | ||||
| 			check_for_error(); | ||||
|  | ||||
| 			ByteReader br(data); | ||||
| 			for (int cell = 0; cell < datalength; cell++) | ||||
| 			{ | ||||
| 				uint16_t interval = br.read_be16(); | ||||
| 				if (interval) | ||||
| 				{ | ||||
| 					fluxmap->appendInterval((interval + pending) * _resolution / NS_PER_TICK); | ||||
| 					fluxmap->appendPulse(); | ||||
| 					pending = 0; | ||||
| 				} | ||||
| 				else | ||||
| 					pending += 0x10000; | ||||
| 			} | ||||
|  | ||||
| 			inputBytes += datalength*2; | ||||
| 		} | ||||
|  | ||||
| 		return fluxmap; | ||||
|     } | ||||
|  | ||||
|     void recalibrate() {} | ||||
|  | ||||
| private: | ||||
| 	void check_for_error() | ||||
| 	{ | ||||
| 		if (_if.fail()) | ||||
| 			Error() << fmt::format("SCP read I/O error: {}", strerror(errno)); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
|     const ScpFluxSourceProto& _config; | ||||
| 	std::ifstream _if; | ||||
| 	ScpHeader _header; | ||||
| 	nanoseconds_t _resolution; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<FluxSource> FluxSource::createScpFluxSource(const ScpFluxSourceProto& config) | ||||
| { | ||||
|     return std::unique_ptr<FluxSource>(new ScpFluxSource(config)); | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user