From 7994148f558acbdaccd8e1c50ad41ad6727fa1e1 Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Mon, 15 Aug 2016 22:10:53 -0400
Subject: [PATCH] I'm starting to make a little headway, I think: this performs
 lead-ins and countdowns, though with no actual data or anything as helpful as
 that.

---
 Storage/Tape/Formats/TapePRG.cpp | 54 ++++++++++++++++++++++++++++++--
 Storage/Tape/Formats/TapePRG.hpp |  7 +++--
 2 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/Storage/Tape/Formats/TapePRG.cpp b/Storage/Tape/Formats/TapePRG.cpp
index 6c1370cdf..cb648e3c6 100644
--- a/Storage/Tape/Formats/TapePRG.cpp
+++ b/Storage/Tape/Formats/TapePRG.cpp
@@ -12,7 +12,7 @@
 
 using namespace Storage;
 
-TapePRG::TapePRG(const char *file_name) : _file(nullptr), _bitPhase(3)
+TapePRG::TapePRG(const char *file_name) : _file(nullptr), _bitPhase(3), _filePhase(FilePhaseLeadIn), _phaseOffset(0)
 {
 	struct stat file_stats;
 	stat(file_name, &file_stats);
@@ -64,9 +64,59 @@ void TapePRG::reset()
 {
 	_bitPhase = 3;
 	fseek(_file, 2, SEEK_SET);
+	_filePhase = FilePhaseLeadIn;
+	_phaseOffset = 0;
 }
 
 void TapePRG::get_next_output_token()
 {
-	_outputToken = Leader;
+	// the lead-in is 20,000 instances of the lead-in pair; every other phase begins with 5000
+	// before doing whatever it should be doing
+	if(_filePhase == FilePhaseLeadIn || _phaseOffset < 5000)
+	{
+		_outputToken = Leader;
+		_phaseOffset++;
+		if(_filePhase == FilePhaseLeadIn && _phaseOffset == 20000)
+		{
+			_phaseOffset = 0;
+			_filePhase = FilePhaseHeader;
+		}
+		return;
+	}
+
+	// determine whether a new byte needs to be queued up
+	int block_offset = _phaseOffset - 5000;
+	int bit_offset = block_offset % 10;
+	int byte_offset = block_offset / 10;
+
+	if(bit_offset == 0)
+	{
+		// the first nine bytes are countdown; the high bit is set if this is a header
+		if(byte_offset < 9)
+		{
+			_output_byte = (uint8_t)(9 - block_offset) | 0x80;
+		}
+		else
+		{
+		}
+	}
+
+	switch(bit_offset)
+	{
+		case 0:
+			_outputToken = WordMarker;
+		break;
+		default:
+			_outputToken = (_output_byte & (1 << (bit_offset - 1))) ? One : Zero;
+		break;
+		case 1:
+		{
+			uint8_t parity = _outputToken;
+			parity ^= (parity >> 4);
+			parity ^= (parity >> 2);
+			parity ^= (parity >> 1);
+			_outputToken = (parity&1) ? One : Zero;
+		}
+		break;
+	}
 }
diff --git a/Storage/Tape/Formats/TapePRG.hpp b/Storage/Tape/Formats/TapePRG.hpp
index 44493437f..100982f82 100644
--- a/Storage/Tape/Formats/TapePRG.hpp
+++ b/Storage/Tape/Formats/TapePRG.hpp
@@ -42,17 +42,20 @@ class TapePRG: public Tape {
 
 		enum FilePhase {
 			FilePhaseLeadIn,
-			FilePhaseHeader
+			FilePhaseHeader,
+			FilePhaseData,
 		} _filePhase;
+		int _phaseOffset;
 
 		int _bitPhase;
 		enum OutputToken {
 			Leader,
 			Zero,
 			One,
-			WordMarker
+			WordMarker,
 		} _outputToken;
 		void get_next_output_token();
+		uint8_t _output_byte;
 };
 
 }