2018-04-28 03:18:45 +00:00
|
|
|
//
|
|
|
|
// AppleDSK.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 27/04/2018.
|
|
|
|
// Copyright © 2018 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "AppleDSK.hpp"
|
|
|
|
|
2018-04-28 19:18:48 +00:00
|
|
|
#include "../../Track/PCMTrack.hpp"
|
|
|
|
#include "../../Encodings/AppleGCR.hpp"
|
|
|
|
|
2018-04-28 03:18:45 +00:00
|
|
|
using namespace Storage::Disk;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
const int number_of_tracks = 35;
|
|
|
|
const int bytes_per_sector = 256;
|
|
|
|
}
|
|
|
|
|
|
|
|
AppleDSK::AppleDSK(const std::string &file_name) :
|
|
|
|
file_(file_name) {
|
|
|
|
if(file_.stats().st_size % number_of_tracks*bytes_per_sector) throw Error::InvalidFormat;
|
|
|
|
|
|
|
|
sectors_per_track_ = static_cast<int>(file_.stats().st_size / (number_of_tracks*bytes_per_sector));
|
|
|
|
if(sectors_per_track_ != 13 && sectors_per_track_ != 16) throw Error::InvalidFormat;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AppleDSK::get_head_position_count() {
|
|
|
|
return number_of_tracks * 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<Track> AppleDSK::get_track_at_position(Track::Address address) {
|
|
|
|
const long file_offset = (address.position >> 2) * bytes_per_sector * sectors_per_track_;
|
|
|
|
file_.seek(file_offset, SEEK_SET);
|
2018-04-28 19:18:48 +00:00
|
|
|
const std::vector<uint8_t> track_data = file_.read(static_cast<size_t>(bytes_per_sector * sectors_per_track_));
|
|
|
|
|
|
|
|
std::vector<Storage::Disk::PCMSegment> segments;
|
|
|
|
const uint8_t track = static_cast<uint8_t>(address.position >> 2);
|
|
|
|
|
|
|
|
// In either case below, the code aims for exactly 50,000 bits per track.
|
|
|
|
if(sectors_per_track_ == 16) {
|
|
|
|
// Write the sectors.
|
2018-04-29 20:18:14 +00:00
|
|
|
uint8_t sector_number_ = 0;
|
|
|
|
for(std::size_t c = 0; c < 16; ++c) {
|
2018-04-28 19:18:48 +00:00
|
|
|
segments.push_back(Encodings::AppleGCR::six_and_two_sync(10));
|
2018-04-29 20:18:14 +00:00
|
|
|
segments.push_back(Encodings::AppleGCR::header(0, track, sector_number_));
|
2018-04-28 19:18:48 +00:00
|
|
|
segments.push_back(Encodings::AppleGCR::six_and_two_sync(10));
|
|
|
|
segments.push_back(Encodings::AppleGCR::six_and_two_data(&track_data[c * 256]));
|
|
|
|
segments.push_back(Encodings::AppleGCR::six_and_two_sync(10));
|
2018-04-29 20:18:14 +00:00
|
|
|
|
|
|
|
// DOS and Pro DOS interleave sectors on disk, and they're represented in a disk
|
|
|
|
// image in physical order rather than logical. So that skew needs to be applied here.
|
|
|
|
sector_number_ = (sector_number_ + (is_prodos_ ? 8 : 7)) % 15;
|
2018-04-28 19:18:48 +00:00
|
|
|
}
|
|
|
|
|
2018-04-28 19:47:50 +00:00
|
|
|
// Pad if necessary.
|
2018-04-28 19:18:48 +00:00
|
|
|
int encoded_length = (80 + 112 + 80 + 2848 + 80) * sectors_per_track_;
|
2018-04-28 19:47:50 +00:00
|
|
|
if(encoded_length < 50000) {
|
|
|
|
segments.push_back(Encodings::AppleGCR::six_and_two_sync((50000 - encoded_length) >> 3));
|
|
|
|
}
|
2018-04-28 19:18:48 +00:00
|
|
|
} else {
|
2018-04-28 03:18:45 +00:00
|
|
|
|
2018-04-28 19:18:48 +00:00
|
|
|
}
|
2018-04-28 03:18:45 +00:00
|
|
|
|
2018-04-28 19:18:48 +00:00
|
|
|
return std::shared_ptr<PCMTrack>(new PCMTrack(segments));
|
2018-04-28 03:18:45 +00:00
|
|
|
}
|