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:
parent
ab5e4ca9c7
commit
e9177bbb2a
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user