From 9f2f388e5af834dc71979396e9c8f6162ed5e1bb Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 14 May 2018 19:17:34 -0400 Subject: [PATCH 1/3] Ensures generation of random noise if too many zeroes exist on a disk surface. --- Storage/Disk/Drive.cpp | 31 ++++++++++++++++++++++++++++++- Storage/Disk/Drive.hpp | 4 ++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 4458f5089..5fed936de 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -12,13 +12,15 @@ #include #include +#include using namespace Storage::Disk; Drive::Drive(unsigned int input_clock_rate, int revolutions_per_minute, int number_of_heads): Storage::TimedEventLoop(input_clock_rate), rotational_multiplier_(60, revolutions_per_minute), - available_heads_(number_of_heads) { + available_heads_(number_of_heads), + random_source_(static_cast(arc4random()) | (static_cast(arc4random()) << 32)) { rotational_multiplier_.simplify(); } @@ -161,10 +163,28 @@ void Drive::get_next_event(const Time &duration_already_passed) { // Grab a new track if not already in possession of one. This will recursively call get_next_event, // supplying a proper duration_already_passed. if(!track_) { + random_interval_.set_zero(); setup_track(); return; } + // If gain has now been turned up so as to generate noise, generate some noise. + if(random_interval_ > Time(0)) { + current_event_.type = Track::Event::IndexHole; + current_event_.length.length = 2 + (random_source_&1); + current_event_.length.clock_rate = 1000000; + random_source_ = (random_source_ >> 1) | (random_source_ << 63); + + if(random_interval_ < current_event_.length) { + current_event_.length = random_interval_; + random_interval_.set_zero(); + } else { + random_interval_ -= current_event_.length; + } + set_next_event_time_interval(current_event_.length); + return; + } + if(track_) { current_event_ = track_->get_next_event(); } else { @@ -178,6 +198,15 @@ void Drive::get_next_event(const Time &duration_already_passed) { assert(current_event_.length <= Time(1) && current_event_.length >= Time(0)); assert(current_event_.length > duration_already_passed); Time interval = (current_event_.length - duration_already_passed) * rotational_multiplier_; + + // An interval greater than 15ms => adjust gain up the point where noise starts happening. + // Seed that up and leave a 15ms gap until it starts. + const Time safe_gain_period(15, 1000000); + if(interval >= safe_gain_period) { + random_interval_ = interval - safe_gain_period; + interval = safe_gain_period; + } + set_next_event_time_interval(interval); } diff --git a/Storage/Disk/Drive.hpp b/Storage/Disk/Drive.hpp index 445999906..a5601ea9a 100644 --- a/Storage/Disk/Drive.hpp +++ b/Storage/Disk/Drive.hpp @@ -199,6 +199,10 @@ class Drive: public Sleeper, public TimedEventLoop { Activity::Observer *observer_ = nullptr; std::string drive_name_; bool announce_motor_led_ = false; + + // A rotating random data source. + uint64_t random_source_; + Time random_interval_; }; From 76802b5e381a1cf29e737ff87e3513cde4104385 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 14 May 2018 20:01:20 -0400 Subject: [PATCH 2/3] Eliminates `arc4random`. It seems not to be as portable as I'd hoped. --- Storage/Disk/Drive.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 5fed936de..3660ffc2b 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -12,16 +12,28 @@ #include #include -#include +#include +#include +#include using namespace Storage::Disk; Drive::Drive(unsigned int input_clock_rate, int revolutions_per_minute, int number_of_heads): Storage::TimedEventLoop(input_clock_rate), rotational_multiplier_(60, revolutions_per_minute), - available_heads_(number_of_heads), - random_source_(static_cast(arc4random()) | (static_cast(arc4random()) << 32)) { + available_heads_(number_of_heads){ rotational_multiplier_.simplify(); + + const auto seed = static_cast(std::chrono::system_clock::now().time_since_epoch().count()); + std::default_random_engine randomiser(seed); + + // Get at least 64 bits of random information; rounding is likey to give this a slight bias. + random_source_ = 0; + auto half_range = (randomiser.max() - randomiser.min()) / 2; + for(int bit = 0; bit < 64; ++bit) { + random_source_ <<= 1; + random_source_ |= ((randomiser() - randomiser.min()) >= half_range) ? 1 : 0; + } } Drive::~Drive() { From 85c4e009f358a4ebc7475704ca45441fa75f713d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 14 May 2018 20:03:32 -0400 Subject: [PATCH 3/3] Undoes reformatting error. --- Storage/Disk/Drive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 3660ffc2b..d2c61f98b 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -21,7 +21,7 @@ using namespace Storage::Disk; Drive::Drive(unsigned int input_clock_rate, int revolutions_per_minute, int number_of_heads): Storage::TimedEventLoop(input_clock_rate), rotational_multiplier_(60, revolutions_per_minute), - available_heads_(number_of_heads){ + available_heads_(number_of_heads) { rotational_multiplier_.simplify(); const auto seed = static_cast(std::chrono::system_clock::now().time_since_epoch().count());