2017-06-07 14:12:13 +00:00
|
|
|
//
|
|
|
|
// ZX8081.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 07/06/2017.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2017 Thomas Harte. All rights reserved.
|
2017-06-07 14:12:13 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#include "ZX8081.hpp"
|
2017-06-07 21:27:05 +00:00
|
|
|
|
|
|
|
using namespace Storage::Tape::ZX8081;
|
|
|
|
|
|
|
|
Parser::Parser() : pulse_was_high_(false), pulse_time_(0) {}
|
|
|
|
|
2024-12-04 03:28:57 +00:00
|
|
|
void Parser::process_pulse(const Storage::Tape::Pulse &pulse) {
|
2017-07-21 23:39:38 +00:00
|
|
|
// If this is anything other than a transition from low to high, just add it to the
|
|
|
|
// count of time.
|
2024-12-04 03:28:57 +00:00
|
|
|
const bool pulse_is_high = pulse.type == Storage::Tape::Pulse::High;
|
2021-03-07 20:56:58 +00:00
|
|
|
const bool pulse_did_change = pulse_is_high != pulse_was_high_;
|
2017-06-07 21:27:05 +00:00
|
|
|
pulse_was_high_ = pulse_is_high;
|
2017-07-21 23:39:38 +00:00
|
|
|
if(!pulse_did_change || !pulse_is_high) {
|
|
|
|
pulse_time_ += pulse.length;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise post a new pulse.
|
2017-06-09 01:33:35 +00:00
|
|
|
post_pulse();
|
2017-07-21 23:39:38 +00:00
|
|
|
pulse_time_ = pulse.length;
|
2017-06-09 01:33:35 +00:00
|
|
|
}
|
2017-06-07 21:27:05 +00:00
|
|
|
|
2017-06-09 01:33:35 +00:00
|
|
|
void Parser::post_pulse() {
|
2019-12-22 05:22:17 +00:00
|
|
|
constexpr float expected_pulse_length = 300.0f / 1000000.0f;
|
|
|
|
constexpr float expected_gap_length = 1300.0f / 1000000.0f;
|
2021-03-07 20:56:58 +00:00
|
|
|
const auto pulse_time = pulse_time_.get<float>();
|
2017-06-07 21:27:05 +00:00
|
|
|
|
2017-06-07 21:50:03 +00:00
|
|
|
if(pulse_time > expected_gap_length * 1.25f) {
|
2017-06-07 21:27:05 +00:00
|
|
|
push_wave(WaveType::LongGap);
|
2017-07-17 23:52:54 +00:00
|
|
|
} else if(pulse_time > expected_pulse_length * 1.25f) {
|
2017-06-07 21:27:05 +00:00
|
|
|
push_wave(WaveType::Gap);
|
2017-07-17 23:52:54 +00:00
|
|
|
} else if(pulse_time >= expected_pulse_length * 0.75f && pulse_time <= expected_pulse_length * 1.25f) {
|
2017-06-07 21:27:05 +00:00
|
|
|
push_wave(WaveType::Pulse);
|
2017-07-17 23:52:54 +00:00
|
|
|
} else {
|
2017-06-07 21:50:03 +00:00
|
|
|
push_wave(WaveType::Unrecognised);
|
|
|
|
}
|
2017-06-07 21:27:05 +00:00
|
|
|
}
|
|
|
|
|
2017-06-09 01:33:35 +00:00
|
|
|
void Parser::mark_end() {
|
2017-07-22 19:41:33 +00:00
|
|
|
// Post a long gap to cap any bit that's in the process of recognition.
|
|
|
|
push_wave(WaveType::LongGap);
|
2017-06-09 01:33:35 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 21:27:05 +00:00
|
|
|
void Parser::inspect_waves(const std::vector<WaveType> &waves) {
|
|
|
|
// A long gap is a file gap.
|
|
|
|
if(waves[0] == WaveType::LongGap) {
|
|
|
|
push_symbol(SymbolType::FileGap, 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:23:26 +00:00
|
|
|
if(waves[0] == WaveType::Unrecognised) {
|
|
|
|
push_symbol(SymbolType::Unrecognised, 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-21 23:39:38 +00:00
|
|
|
if(waves.size() >= 4) {
|
2017-11-11 20:28:40 +00:00
|
|
|
std::size_t wave_offset = 0;
|
2017-06-11 22:31:09 +00:00
|
|
|
// If the very first thing is a gap, swallow it.
|
|
|
|
if(waves[0] == WaveType::Gap) {
|
|
|
|
wave_offset = 1;
|
|
|
|
}
|
|
|
|
|
2017-06-07 21:27:05 +00:00
|
|
|
// Count the number of pulses at the start of this vector
|
2017-11-11 20:28:40 +00:00
|
|
|
std::size_t number_of_pulses = 0;
|
2017-06-23 02:28:50 +00:00
|
|
|
while(number_of_pulses + wave_offset < waves.size() && waves[number_of_pulses + wave_offset] == WaveType::Pulse) {
|
2017-06-07 21:27:05 +00:00
|
|
|
number_of_pulses++;
|
|
|
|
}
|
|
|
|
|
2017-07-22 19:41:33 +00:00
|
|
|
// If those pulses were followed by something not recognised as a pulse, check for a bit
|
|
|
|
if(number_of_pulses + wave_offset < waves.size()) {
|
|
|
|
// A 1 is 9 waves, a 0 is 4. Counting upward zero transitions, the first in either group will
|
|
|
|
// act simply to terminate the gap beforehand and won't be logged as a pulse. So counts to
|
|
|
|
// check are 8 and 3.
|
2017-11-11 20:28:40 +00:00
|
|
|
std::size_t gaps_to_swallow = wave_offset + ((waves[number_of_pulses + wave_offset] == WaveType::Gap) ? 1 : 0);
|
2017-06-07 21:27:05 +00:00
|
|
|
switch(number_of_pulses) {
|
2020-05-10 03:00:39 +00:00
|
|
|
case 8: push_symbol(SymbolType::One, int(number_of_pulses + gaps_to_swallow)); break;
|
|
|
|
case 3: push_symbol(SymbolType::Zero, int(number_of_pulses + gaps_to_swallow)); break;
|
|
|
|
default: push_symbol(SymbolType::Unrecognised, 1); break;
|
2017-06-07 21:27:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int Parser::get_next_byte(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
|
|
|
int c = 8;
|
|
|
|
int result = 0;
|
2017-07-22 00:23:26 +00:00
|
|
|
while(c) {
|
2017-06-09 01:33:35 +00:00
|
|
|
if(is_at_end(tape)) return -1;
|
2017-07-22 00:23:26 +00:00
|
|
|
|
2017-06-07 21:27:05 +00:00
|
|
|
SymbolType symbol = get_next_symbol(tape);
|
|
|
|
if(symbol != SymbolType::One && symbol != SymbolType::Zero) {
|
2017-07-22 00:23:26 +00:00
|
|
|
if(c == 8) continue;
|
2017-07-17 11:43:47 +00:00
|
|
|
return_symbol(symbol);
|
2017-06-07 21:27:05 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2017-07-22 00:23:26 +00:00
|
|
|
|
2017-06-07 21:27:05 +00:00
|
|
|
result = (result << 1) | (symbol == SymbolType::One ? 1 : 0);
|
2017-07-22 00:23:26 +00:00
|
|
|
c--;
|
2017-06-07 21:27:05 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-06-08 23:09:51 +00:00
|
|
|
std::shared_ptr<std::vector<uint8_t>> Parser::get_next_file_data(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
2017-06-09 01:33:35 +00:00
|
|
|
if(is_at_end(tape)) return nullptr;
|
2017-06-07 21:27:05 +00:00
|
|
|
SymbolType symbol = get_next_symbol(tape);
|
2017-07-21 23:39:38 +00:00
|
|
|
if(symbol != SymbolType::FileGap) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2017-07-17 11:43:47 +00:00
|
|
|
while((symbol == SymbolType::FileGap || symbol == SymbolType::Unrecognised) && !is_at_end(tape)) {
|
2017-06-07 21:27:05 +00:00
|
|
|
symbol = get_next_symbol(tape);
|
|
|
|
}
|
2017-06-09 01:33:35 +00:00
|
|
|
if(is_at_end(tape)) return nullptr;
|
2017-06-07 21:27:05 +00:00
|
|
|
return_symbol(symbol);
|
|
|
|
|
2019-12-22 04:52:04 +00:00
|
|
|
auto result = std::make_shared<std::vector<uint8_t>>();
|
2017-06-07 21:27:05 +00:00
|
|
|
int byte;
|
2017-06-09 01:33:35 +00:00
|
|
|
while(!is_at_end(tape)) {
|
2017-06-07 21:27:05 +00:00
|
|
|
byte = get_next_byte(tape);
|
|
|
|
if(byte == -1) return result;
|
2020-05-10 03:00:39 +00:00
|
|
|
result->push_back(uint8_t(byte));
|
2017-06-07 21:27:05 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-06-08 23:09:51 +00:00
|
|
|
std::shared_ptr<Storage::Data::ZX8081::File> Parser::get_next_file(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
|
|
|
std::shared_ptr<std::vector<uint8_t>> file_data = get_next_file_data(tape);
|
2017-07-21 23:39:38 +00:00
|
|
|
if(!file_data) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2017-06-08 23:09:51 +00:00
|
|
|
return Storage::Data::ZX8081::FileFromData(*file_data);
|
2017-06-07 21:27:05 +00:00
|
|
|
}
|