text: //
  //  Acorn.cpp
  //  Clock Signal
  //
  //  Created by Thomas Harte on 06/11/2016.
  //  Copyright 2016 Thomas Harte. All rights reserved.
  //
  
  #include "Acorn.hpp"
  
  using namespace Storage::Tape::Acorn;
  
  namespace {
  constexpr int PLLClockRate = 1920000;
  }
  
  Parser::Parser(): crc_(0x1021) {
  	shifter_.set_delegate(this);
  }
  
  int Parser::get_next_bit(const std::shared_ptr<Storage::Tape::Tape> &tape) {
  	const SymbolType symbol = get_next_symbol(tape);
  	return (symbol == SymbolType::One) ? 1 : 0;
  }
  
  int Parser::get_next_byte(const std::shared_ptr<Storage::Tape::Tape> &tape) {
  	if(get_next_bit(tape)) {
  		set_error_flag();
  		return -1;
  	}
  
  	int value = 0;
  	int c = 8;
  	while(c--) {
  		value = (value >> 1) | (get_next_bit(tape) << 7);
  	}
  	if(!get_next_bit(tape)) {
  		set_error_flag();
  		return -1;
  	}
  	crc_.add(uint8_t(value));
  	return value;
  }
  
  unsigned int Parser::get_next_short(const std::shared_ptr<Storage::Tape::Tape> &tape) {
  	unsigned int result = unsigned(get_next_byte(tape));
  	result |= unsigned(get_next_byte(tape)) << 8;
  	return result;
  }
  
  unsigned int Parser::get_next_word(const std::shared_ptr<Storage::Tape::Tape> &tape) {
  	unsigned int result = get_next_short(tape);
  	result |= get_next_short(tape) << 8;
  	return result;
  }
  
  void Parser::reset_crc()			{	crc_.reset();				}
  uint16_t Parser::get_crc() const	{	return crc_.get_value();	}
  
  void Parser::acorn_shifter_output_bit(int value) {
  	push_symbol(value ? SymbolType::One : SymbolType::Zero);
  }
  
  void Parser::process_pulse(const Storage::Tape::Tape::Pulse &pulse) {
  	shifter_.process_pulse(pulse);
  }
  
  
  Shifter::Shifter() :
  	pll_(PLLClockRate / 4800, *this),
  	was_high_(false),
  	input_pattern_(0),
  	delegate_(nullptr) {}
  
  void Shifter::process_pulse(const Storage::Tape::Tape::Pulse &pulse) {
  	pll_.run_for(Cycles(int(float(PLLClockRate) * pulse.length.get<float>())));
  
  	const bool is_high = pulse.type == Storage::Tape::Tape::Pulse::High;
  	if(is_high != was_high_) {
  		pll_.add_pulse();
  	}
  	was_high_ = is_high;
  }
  
  void Shifter::digital_phase_locked_loop_output_bit(int value) {
  	input_pattern_ = ((input_pattern_ << 1) | unsigned(value)) & 0xf;
  	switch(input_pattern_) {
  		case 0x5:	delegate_->acorn_shifter_output_bit(0); input_pattern_ = 0;	break;
  		case 0xf:	delegate_->acorn_shifter_output_bit(1); input_pattern_ = 0;	break;
  		default:	break;
  	}
  }
  