// // OricMFMDSK.cpp // Clock Signal // // Created by Thomas Harte on 21/11/2016. // Copyright © 2016 Thomas Harte. All rights reserved. // #include "OricMFMDSK.hpp" #include "../PCMTrack.hpp" #include "../Encodings/MFM.hpp" using namespace Storage::Disk; OricMFMDSK::OricMFMDSK(const char *file_name) : Storage::FileHolder(file_name) { if(!check_signature("MFM_DISK", 8)) throw ErrorNotOricMFMDSK; head_count_ = fgetc32le(); track_count_ = fgetc32le(); geometry_type_ = fgetc32le(); if(geometry_type_ < 1 || geometry_type_ > 2) throw ErrorNotOricMFMDSK; } OricMFMDSK::~OricMFMDSK() { flush_updates(); } unsigned int OricMFMDSK::get_head_position_count() { return track_count_; } unsigned int OricMFMDSK::get_head_count() { return head_count_; } bool OricMFMDSK::get_is_read_only() { return is_read_only_; } long OricMFMDSK::get_file_offset_for_position(unsigned int head, unsigned int position) { long seek_offset = 0; switch(geometry_type_) { case 1: seek_offset = (head * track_count_) + position; break; case 2: seek_offset = (position * track_count_ * head_count_) + head; break; } return (seek_offset * 6400) + 256; } std::shared_ptr OricMFMDSK::get_uncached_track_at_position(unsigned int head, unsigned int position) { fseek(file_, get_file_offset_for_position(head, position), SEEK_SET); PCMSegment segment; // The file format omits clock bits. So it's not a genuine MFM capture. // A consumer must contextually guess when an FB, FC, etc is meant to be a control mark. size_t track_offset = 0; uint8_t last_header[6]; std::unique_ptr encoder = Encodings::MFM::GetMFMEncoder(segment.data); bool did_sync = false; while(track_offset < 6250) { uint8_t next_byte = (uint8_t)fgetc(file_); track_offset++; switch(next_byte) { default: { encoder->add_byte(next_byte); if(did_sync) { switch(next_byte) { default: break; case 0xfe: for(int byte = 0; byte < 6; byte++) { last_header[byte] = (uint8_t)fgetc(file_); encoder->add_byte(last_header[byte]); track_offset++; if(track_offset == 6250) break; } break; case 0xfb: for(int byte = 0; byte < (128 << last_header[3]) + 2; byte++) { encoder->add_byte((uint8_t)fgetc(file_)); track_offset++; if(track_offset == 6250) break; } break; } } did_sync = false; } break; case 0xa1: // a synchronisation mark that implies a sector or header coming encoder->output_short(Storage::Encodings::MFM::MFMSync); did_sync = true; break; case 0xc2: // an 'ordinary' synchronisation mark encoder->output_short(Storage::Encodings::MFM::MFMIndexSync); break; } } segment.number_of_bits = (unsigned int)(segment.data.size() * 8); std::shared_ptr track(new PCMTrack(segment)); return track; } void OricMFMDSK::store_updated_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr &track, std::mutex &file_access_mutex) { Storage::Encodings::MFM::Parser parser(true, track); std::vector parsed_track = parser.get_track((uint8_t)position); std::lock_guard lock_guard(file_access_mutex); long file_offset = get_file_offset_for_position(head, position); fseek(file_, file_offset, SEEK_SET); fwrite(parsed_track.data(), 1, parsed_track.size(), file_); }