//
//  DriveSpeedAccumulator.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 01/06/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#include "DriveSpeedAccumulator.hpp"

using namespace Apple::Macintosh;

void DriveSpeedAccumulator::post_sample(uint8_t sample) {
	if(!delegate_) return;

	// An Euler-esque approximation is used here: just collect all
	// the samples until there is a certain small quantity of them,
	// then produce a new estimate of rotation speed and start the
	// buffer afresh.
	samples_[sample_pointer_] = sample;
	++sample_pointer_;

	if(sample_pointer_ == samples_.size()) {
		sample_pointer_ = 0;

		// The below fits for a function like `a + bc`; it encapsultes the following
		// beliefs:
		//
		//	(i) motor speed is proportional to voltage supplied;
		//	(ii) with pulse-width modulation it's therefore proportional to the duty cycle;
		//	(iii) the Mac pulse-width modulates whatever it reads from the disk speed buffer;
		//	(iv) ... subject to software pulse-width modulation of that pulse-width modulation.
		//
		// So, I believe current motor speed is proportional to a low-pass filtering of
		// the speed buffer. Which I've implemented very coarsely via 'large' bucketed-averages,
		// noting also that exact disk motor speed is always a little approximate.

		// Sum all samples.
		// TODO: if the above is the correct test, do it on sample receipt rather than
		// bothering with an intermediate buffer.
		int sum = 0;
		for(auto s: samples_) {
			sum += s;
		}

		// The formula below was derived from observing values the Mac wrote into its
		// disk-speed buffer. Given that it runs a calibration loop before doing so,
		// I cannot guarantee the accuracy of these numbers beyond being within the
		// range that the computer would accept.
		const float normalised_sum = float(sum) / float(samples_.size());
		const float rotation_speed = (normalised_sum * 27.08f) - 259.0f;

		delegate_->drive_speed_accumulator_set_drive_speed(this, rotation_speed);
	}
}

