1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-10 16:30:07 +00:00

Makes an attempt to parse headers.

This commit is contained in:
Thomas Harte 2021-03-07 20:49:09 -05:00
parent ab5e4ca9c7
commit e9177bbb2a
2 changed files with 128 additions and 0 deletions

View File

@ -96,3 +96,55 @@ void Parser::inspect_waves(const std::vector<Storage::Tape::ZXSpectrum::WaveType
break;
}
}
std::optional<Header> Parser::find_header(const std::shared_ptr<Storage::Tape::Tape> &tape) {
// Find pilot tone.
proceed_to_symbol(tape, SymbolType::Pilot);
if(is_at_end(tape)) return std::nullopt;
// Find sync.
proceed_to_symbol(tape, SymbolType::Sync);
if(is_at_end(tape)) return std::nullopt;
// Read market byte.
const auto type = get_byte(tape);
if(!type) return std::nullopt;
if(*type != 0x00) return std::nullopt;
reset_checksum();
// Read header contents.
uint8_t header_bytes[17];
for(size_t c = 0; c < sizeof(header_bytes); c++) {
const auto next_byte = get_byte(tape);
if(!next_byte) return std::nullopt;
header_bytes[c] = *next_byte;
}
// Check checksum.
const auto post_checksum = get_byte(tape);
if(!post_checksum || *post_checksum) return std::nullopt;
// Unpack and return.
Header header;
header.type = header_bytes[0];
memcpy(&header.name, &header_bytes[1], 10);
header.data_length = uint16_t(header_bytes[11] | (header_bytes[12] << 8));
header.parameters[0] = uint16_t(header_bytes[13] | (header_bytes[14] << 8));
header.parameters[1] = uint16_t(header_bytes[15] | (header_bytes[16] << 8));
return header;
}
void Parser::reset_checksum() {
checksum_ = 0;
}
std::optional<uint8_t> Parser::get_byte(const std::shared_ptr<Storage::Tape::Tape> &tape) {
uint8_t result = 0;
for(int c = 0; c < 8; c++) {
const SymbolType symbol = get_next_symbol(tape);
if(symbol != SymbolType::One && symbol != SymbolType::Zero) return std::nullopt;
result = uint8_t((result << 1) | (symbol == SymbolType::One));
}
checksum_ ^= result;
return result;
}

View File

@ -11,6 +11,8 @@
#include "TapeParser.hpp"
#include <optional>
namespace Storage {
namespace Tape {
namespace ZXSpectrum {
@ -35,10 +37,84 @@ enum class SymbolType {
Gap,
};
struct Header {
uint8_t type = 0;
char name[11]{}; // 10 bytes on tape; always given a NULL terminator in this code.
uint16_t data_length = 0;
uint16_t parameters[2] = {0, 0};
enum class Type {
Program = 0,
NumberArray = 1,
CharacterArray = 2,
Code = 3,
Unknown
};
Type decoded_type() {
if(type > 3) return Type::Unknown;
return Type(type);
}
struct BasicParameters {
std::optional<uint16_t> autostart_line_number;
uint16_t start_of_variable_area;
};
BasicParameters basic_parameters() {
const BasicParameters params = {
.autostart_line_number = parameters[0] < 32768 ? std::make_optional(parameters[0]) : std::nullopt,
.start_of_variable_area = parameters[1]
};
return params;
}
struct CodeParameters {
uint16_t start_address;
};
CodeParameters code_parameters() {
const CodeParameters params = {
.start_address = parameters[0]
};
return params;
}
struct DataParameters {
char name;
enum class Type {
Numeric,
String
} type;
};
DataParameters data_parameters() {
#if TARGET_RT_BIG_ENDIAN
const uint8_t data_name = uint8_t(parameters[0]);
#else
const uint8_t data_name = uint8_t(parameters[0] >> 8);
#endif
using Type = DataParameters::Type;
const DataParameters params = {
.name = char((data_name & 0x1f) + 'a'),
.type = (data_name & 0x40) ? Type::String : Type::Numeric
};
return params;
}
};
class Parser: public Storage::Tape::PulseClassificationParser<WaveType, SymbolType> {
public:
/*!
Finds the next header from the tape, if any.
*/
std::optional<Header> find_header(const std::shared_ptr<Storage::Tape::Tape> &tape);
void reset_checksum();
std::optional<uint8_t> get_byte(const std::shared_ptr<Storage::Tape::Tape> &tape);
private:
void process_pulse(const Storage::Tape::Tape::Pulse &pulse) override;
void inspect_waves(const std::vector<WaveType> &waves) override;
uint8_t checksum_ = 0;
};
}