2016-11-07 00:22:09 +00:00
|
|
|
//
|
|
|
|
// Oric.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 06/11/2016.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2016 Thomas Harte. All rights reserved.
|
2016-11-07 00:22:09 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#include "Oric.hpp"
|
|
|
|
|
|
|
|
using namespace Storage::Tape::Oric;
|
|
|
|
|
2019-12-22 05:00:23 +00:00
|
|
|
int Parser::get_next_byte(const std::shared_ptr<Storage::Tape::Tape> &tape, bool use_fast_encoding) {
|
2016-12-03 17:05:19 +00:00
|
|
|
detection_mode_ = use_fast_encoding ? FastZero : SlowZero;
|
|
|
|
cycle_length_ = 0.0f;
|
2016-11-07 00:22:09 +00:00
|
|
|
|
|
|
|
int result = 0;
|
|
|
|
int bit_count = 0;
|
2019-12-22 05:00:23 +00:00
|
|
|
while(bit_count < 11 && !tape->is_at_end()) {
|
2016-11-07 00:22:09 +00:00
|
|
|
SymbolType symbol = get_next_symbol(tape);
|
|
|
|
if(!bit_count && symbol != SymbolType::Zero) continue;
|
2016-12-03 17:05:19 +00:00
|
|
|
detection_mode_ = use_fast_encoding ? FastData : SlowData;
|
2016-11-07 00:22:09 +00:00
|
|
|
result |= ((symbol == SymbolType::One) ? 1 : 0) << bit_count;
|
|
|
|
bit_count++;
|
|
|
|
}
|
2016-11-07 02:31:10 +00:00
|
|
|
// TODO: check parity?
|
2016-11-08 01:17:06 +00:00
|
|
|
return tape->is_at_end() ? -1 : ((result >> 1)&0xff);
|
2016-11-07 00:22:09 +00:00
|
|
|
}
|
|
|
|
|
2019-12-22 05:00:23 +00:00
|
|
|
bool Parser::sync_and_get_encoding_speed(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
2016-12-03 17:05:19 +00:00
|
|
|
detection_mode_ = Sync;
|
2019-12-22 05:00:23 +00:00
|
|
|
while(!tape->is_at_end()) {
|
|
|
|
const SymbolType symbol = get_next_symbol(tape);
|
|
|
|
switch(symbol) {
|
2016-11-07 02:31:10 +00:00
|
|
|
case SymbolType::FoundSlow: return false;
|
|
|
|
case SymbolType::FoundFast: return true;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-12-22 05:00:23 +00:00
|
|
|
void Parser::process_pulse(const Storage::Tape::Tape::Pulse &pulse) {
|
|
|
|
constexpr float maximum_short_length = 0.000512f;
|
|
|
|
constexpr float maximum_medium_length = 0.000728f;
|
|
|
|
constexpr float maximum_long_length = 0.001456f;
|
2016-11-07 00:22:09 +00:00
|
|
|
|
2021-03-07 20:56:58 +00:00
|
|
|
const bool wave_is_high = pulse.type == Storage::Tape::Tape::Pulse::High;
|
2019-12-22 05:00:23 +00:00
|
|
|
if(!wave_was_high_ && wave_is_high != wave_was_high_) {
|
2016-12-03 17:05:19 +00:00
|
|
|
if(cycle_length_ < maximum_short_length) push_wave(WaveType::Short);
|
|
|
|
else if(cycle_length_ < maximum_medium_length) push_wave(WaveType::Medium);
|
|
|
|
else if(cycle_length_ < maximum_long_length) push_wave(WaveType::Long);
|
2016-11-09 11:37:10 +00:00
|
|
|
else push_wave(WaveType::Unrecognised);
|
2016-11-07 00:22:09 +00:00
|
|
|
|
2016-12-03 17:05:19 +00:00
|
|
|
cycle_length_ = 0.0f;
|
2016-11-07 00:22:09 +00:00
|
|
|
}
|
2016-12-03 17:05:19 +00:00
|
|
|
wave_was_high_ = wave_is_high;
|
2018-04-25 23:54:39 +00:00
|
|
|
cycle_length_ += pulse.length.get<float>();
|
2016-11-07 00:22:09 +00:00
|
|
|
}
|
|
|
|
|
2019-12-22 05:00:23 +00:00
|
|
|
void Parser::inspect_waves(const std::vector<WaveType> &waves) {
|
|
|
|
switch(detection_mode_) {
|
2016-11-08 01:17:06 +00:00
|
|
|
case FastZero:
|
2016-11-09 11:37:10 +00:00
|
|
|
if(waves.empty()) return;
|
2019-12-22 05:00:23 +00:00
|
|
|
if(waves[0] == WaveType::Medium) {
|
2016-11-09 11:37:10 +00:00
|
|
|
push_symbol(SymbolType::Zero, 1);
|
2016-11-08 01:17:06 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2016-11-07 02:31:10 +00:00
|
|
|
case FastData:
|
2016-11-09 11:37:10 +00:00
|
|
|
if(waves.empty()) return;
|
2019-12-22 05:00:23 +00:00
|
|
|
if(waves[0] == WaveType::Medium) {
|
2016-11-09 11:37:10 +00:00
|
|
|
push_symbol(SymbolType::Zero, 1);
|
|
|
|
return;
|
|
|
|
}
|
2019-12-22 05:00:23 +00:00
|
|
|
if(waves[0] == WaveType::Short) {
|
2016-11-09 11:37:10 +00:00
|
|
|
push_symbol(SymbolType::One, 1);
|
2016-11-07 02:31:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2016-11-08 01:17:06 +00:00
|
|
|
case SlowZero:
|
2016-11-09 11:37:10 +00:00
|
|
|
if(waves.size() < 4) return;
|
2019-12-22 05:00:23 +00:00
|
|
|
if(waves[0] == WaveType::Long && waves[1] == WaveType::Long && waves[2] == WaveType::Long && waves[3] == WaveType::Long) {
|
2016-11-09 11:37:10 +00:00
|
|
|
push_symbol(SymbolType::Zero, 4);
|
2016-11-08 01:17:06 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2024-01-23 02:22:56 +00:00
|
|
|
case SlowData: {
|
|
|
|
const auto check_run = [&](std::size_t length, WaveType type, SymbolType symbol) -> bool {
|
|
|
|
if(waves.size() >= length) {
|
|
|
|
std::size_t c;
|
|
|
|
for(c = 0; c < length; c++) if(waves[c] != type) break;
|
|
|
|
if(c == length) {
|
|
|
|
push_symbol(symbol, int(length));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
2016-11-07 02:31:10 +00:00
|
|
|
|
2024-01-23 02:22:56 +00:00
|
|
|
if(check_run(4, WaveType::Long, SymbolType::Zero)) return;
|
|
|
|
if(check_run(8, WaveType::Short, SymbolType::One)) return;
|
2016-11-07 02:31:10 +00:00
|
|
|
if(waves.size() < 16) return; // TODO, maybe: if there are any inconsistencies in the first 8, don't return
|
2024-01-23 02:22:56 +00:00
|
|
|
} break;
|
2016-11-07 02:31:10 +00:00
|
|
|
|
2019-12-22 05:00:23 +00:00
|
|
|
case Sync: {
|
2016-11-07 02:31:10 +00:00
|
|
|
// Sync is 0x16, either encoded fast or slow; i.e. 0 0110 1000 1
|
2019-12-22 05:00:23 +00:00
|
|
|
const Pattern slow_sync[] = {
|
2017-11-11 00:14:19 +00:00
|
|
|
{WaveType::Long, 8},
|
|
|
|
{WaveType::Short, 16},
|
|
|
|
{WaveType::Long, 4},
|
|
|
|
{WaveType::Short, 8},
|
|
|
|
{WaveType::Long, 12},
|
|
|
|
{WaveType::Short, 8},
|
|
|
|
{WaveType::Unrecognised}
|
2016-11-07 02:31:10 +00:00
|
|
|
};
|
2019-12-22 05:00:23 +00:00
|
|
|
const Pattern fast_sync[] = {
|
2017-11-11 00:14:19 +00:00
|
|
|
{WaveType::Medium, 2},
|
|
|
|
{WaveType::Short, 2},
|
|
|
|
{WaveType::Medium, 1},
|
|
|
|
{WaveType::Short, 1},
|
|
|
|
{WaveType::Medium, 3},
|
|
|
|
{WaveType::Short, 1},
|
|
|
|
{WaveType::Unrecognised}
|
2016-11-07 02:31:10 +00:00
|
|
|
};
|
|
|
|
|
2017-11-11 20:28:40 +00:00
|
|
|
std::size_t slow_sync_matching_depth = pattern_matching_depth(waves, slow_sync);
|
|
|
|
std::size_t fast_sync_matching_depth = pattern_matching_depth(waves, fast_sync);
|
2016-11-07 02:31:10 +00:00
|
|
|
|
2019-12-22 05:00:23 +00:00
|
|
|
if(slow_sync_matching_depth == 52) {
|
2016-11-09 11:37:10 +00:00
|
|
|
push_symbol(SymbolType::FoundSlow, 52);
|
2016-11-07 02:31:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-12-22 05:00:23 +00:00
|
|
|
if(fast_sync_matching_depth == 10) {
|
2016-11-09 11:37:10 +00:00
|
|
|
push_symbol(SymbolType::FoundFast, 10);
|
2016-11-07 02:31:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-12-22 05:00:23 +00:00
|
|
|
if(slow_sync_matching_depth < waves.size() && fast_sync_matching_depth < waves.size()) {
|
2020-05-10 03:00:39 +00:00
|
|
|
int least_depth = int(std::min(slow_sync_matching_depth, fast_sync_matching_depth));
|
2016-11-07 03:56:38 +00:00
|
|
|
remove_waves(least_depth ? least_depth : 1);
|
|
|
|
}
|
2016-11-07 02:31:10 +00:00
|
|
|
|
2016-11-07 00:22:09 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-11-07 02:31:10 +00:00
|
|
|
break;
|
2016-11-07 00:22:09 +00:00
|
|
|
}
|
2016-11-07 02:31:10 +00:00
|
|
|
|
|
|
|
remove_waves(1);
|
|
|
|
}
|
|
|
|
|
2019-12-22 05:00:23 +00:00
|
|
|
std::size_t Parser::pattern_matching_depth(const std::vector<WaveType> &waves, const Pattern *pattern) {
|
2017-11-11 20:28:40 +00:00
|
|
|
std::size_t depth = 0;
|
2016-11-07 02:31:10 +00:00
|
|
|
int pattern_depth = 0;
|
2019-12-22 05:00:23 +00:00
|
|
|
while(depth < waves.size() && pattern->type != WaveType::Unrecognised) {
|
2016-11-07 02:31:10 +00:00
|
|
|
if(waves[depth] != pattern->type) break;
|
2016-11-07 03:56:38 +00:00
|
|
|
depth++;
|
2016-11-07 02:31:10 +00:00
|
|
|
pattern_depth++;
|
2019-12-22 05:00:23 +00:00
|
|
|
if(pattern_depth == pattern->count) {
|
2016-11-07 02:31:10 +00:00
|
|
|
pattern_depth = 0;
|
|
|
|
pattern++;
|
2016-11-07 00:22:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-07 02:31:10 +00:00
|
|
|
return depth;
|
2016-11-07 00:22:09 +00:00
|
|
|
}
|