diff --git a/ClockReceiver/ForceInline.h b/ClockReceiver/ForceInline.hpp similarity index 86% rename from ClockReceiver/ForceInline.h rename to ClockReceiver/ForceInline.hpp index 786e41c2d..2b6cf5589 100644 --- a/ClockReceiver/ForceInline.h +++ b/ClockReceiver/ForceInline.hpp @@ -6,8 +6,8 @@ // Copyright © 2017 Thomas Harte. All rights reserved. // -#ifndef ForceInline_h -#define ForceInline_h +#ifndef ForceInline_hpp +#define ForceInline_hpp #ifdef __GNUC__ #define forceinline __attribute__((always_inline)) inline diff --git a/ClockReceiver/Sleeper.h b/ClockReceiver/Sleeper.hpp similarity index 69% rename from ClockReceiver/Sleeper.h rename to ClockReceiver/Sleeper.hpp index caa837cf8..2a6e00e08 100644 --- a/ClockReceiver/Sleeper.h +++ b/ClockReceiver/Sleeper.hpp @@ -6,8 +6,8 @@ // Copyright © 2017 Thomas Harte. All rights reserved. // -#ifndef Sleeper_h -#define Sleeper_h +#ifndef Sleeper_hpp +#define Sleeper_hpp /*! A sleeper is any component that sometimes requires a clock but at other times is 'asleep' — i.e. is not doing @@ -30,17 +30,31 @@ class Sleeper { class SleepObserver { public: /// Called to inform an observer that the component @c component has either gone to sleep or become awake. - void set_component_is_sleeping(void *component, bool is_sleeping) = 0; + virtual void set_component_is_sleeping(void *component, bool is_sleeping) = 0; }; /// Registers @c observer as the new sleep observer; void set_sleep_observer(SleepObserver *observer) { - sleep_observer_ = delegate; + sleep_observer_ = observer; } + /// @returns @c true if the component is currently sleeping; @c false otherwise. + virtual bool is_sleeping() = 0; + protected: /// Provided for subclasses; send sleep announcements to the sleep_observer_. SleepObserver *sleep_observer_; + + /*! + Provided for subclasses; call this whenever is_sleeping might have changed, and the observer will be notified, + if one exists. + + @c is_sleeping will be called only if there is an observer. + */ + void update_sleep_observer() { + if(!sleep_observer_) return; + sleep_observer_->set_component_is_sleeping(this, is_sleeping()); + } }; #endif /* Sleeper_h */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 7ed659817..e77b72e90 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -677,8 +677,8 @@ 4BACC5B01F3DFF7C0037C015 /* CharacterMapper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CharacterMapper.hpp; path = AmstradCPC/CharacterMapper.hpp; sourceTree = ""; }; 4BAD9B941F43D7E900724854 /* UnformattedTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnformattedTrack.cpp; sourceTree = ""; }; 4BAD9B951F43D7E900724854 /* UnformattedTrack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = UnformattedTrack.hpp; sourceTree = ""; }; - 4BB06B211F316A3F00600C7A /* ForceInline.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ForceInline.h; sourceTree = ""; }; - 4BB146C61F49D7D700253439 /* Sleeper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Sleeper.h; sourceTree = ""; }; + 4BB06B211F316A3F00600C7A /* ForceInline.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ForceInline.hpp; sourceTree = ""; }; + 4BB146C61F49D7D700253439 /* Sleeper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Sleeper.hpp; sourceTree = ""; }; 4BB17D4C1ED7909F00ABD1E1 /* tests.expected.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = tests.expected.json; path = FUSE/tests.expected.json; sourceTree = ""; }; 4BB17D4D1ED7909F00ABD1E1 /* tests.in.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = tests.in.json; path = FUSE/tests.in.json; sourceTree = ""; }; 4BB297E51B587D8300A49093 /* start */ = {isa = PBXFileReference; lastKnownFileType = file; path = " start"; sourceTree = ""; }; @@ -2280,8 +2280,8 @@ isa = PBXGroup; children = ( 4BF6606A1F281573002CB053 /* ClockReceiver.hpp */, - 4BB06B211F316A3F00600C7A /* ForceInline.h */, - 4BB146C61F49D7D700253439 /* Sleeper.h */, + 4BB06B211F316A3F00600C7A /* ForceInline.hpp */, + 4BB146C61F49D7D700253439 /* Sleeper.hpp */, ); name = ClockReceiver; path = ../../ClockReceiver; diff --git a/Storage/Disk/DiskController.cpp b/Storage/Disk/DiskController.cpp index 6a7ae1f85..772750e88 100644 --- a/Storage/Disk/DiskController.cpp +++ b/Storage/Disk/DiskController.cpp @@ -46,6 +46,14 @@ void Controller::setup_track() { get_next_event(offset); } +void Controller::set_component_is_sleeping(void *component, bool is_sleeping) { + update_sleep_observer(); +} + +bool Controller::is_sleeping() { + return !(drive_ && drive_->has_disk() && motor_is_on_); +} + void Controller::run_for(const Cycles cycles) { Time zero(0); @@ -208,6 +216,7 @@ void Controller::step(int direction) { void Controller::set_motor_on(bool motor_on) { motor_is_on_ = motor_on; + update_sleep_observer(); } bool Controller::get_motor_on() { @@ -218,6 +227,8 @@ void Controller::set_drive(std::shared_ptr drive) { if(drive_ != drive) { invalidate_track(); drive_ = drive; + drive->set_sleep_observer(this); + update_sleep_observer(); } } diff --git a/Storage/Disk/DiskController.hpp b/Storage/Disk/DiskController.hpp index 399a92d84..4ab4e009c 100644 --- a/Storage/Disk/DiskController.hpp +++ b/Storage/Disk/DiskController.hpp @@ -14,7 +14,9 @@ #include "PCMSegment.hpp" #include "PCMPatchedTrack.hpp" #include "../TimedEventLoop.hpp" + #include "../../ClockReceiver/ClockReceiver.hpp" +#include "../../ClockReceiver/Sleeper.hpp" namespace Storage { namespace Disk { @@ -28,7 +30,7 @@ namespace Disk { TODO: communication of head size and permissible stepping extents, appropriate simulation of gain. */ -class Controller: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop { +class Controller: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop, public Sleeper, public Sleeper::SleepObserver { protected: /*! Constructs a @c DiskDrive that will be run at @c clock_rate and runs its PLL at @c clock_rate*clock_rate_multiplier, @@ -116,6 +118,8 @@ class Controller: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop virtual bool get_drive_is_ready(); bool get_drive_is_read_only(); + bool is_sleeping(); + private: Time bit_length_; int clock_rate_; @@ -142,6 +146,8 @@ class Controller: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop void setup_track(); Time get_time_into_track(); + + void set_component_is_sleeping(void *component, bool is_sleeping); }; } diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 99e8e6d11..817bdd994 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -18,18 +18,24 @@ void Drive::set_disk(const std::shared_ptr &disk) { disk_ = disk; track_ = nullptr; has_disk_ = !!disk_; + update_sleep_observer(); } void Drive::set_disk_with_track(const std::shared_ptr &track) { disk_ = nullptr; track_ = track; has_disk_ = !!track_; + update_sleep_observer(); } bool Drive::has_disk() { return has_disk_; } +bool Drive::is_sleeping() { + return !has_disk_; +} + bool Drive::get_is_track_zero() { return head_position_ == 0; } diff --git a/Storage/Disk/Drive.hpp b/Storage/Disk/Drive.hpp index 009b15dc9..2ed27ea71 100644 --- a/Storage/Disk/Drive.hpp +++ b/Storage/Disk/Drive.hpp @@ -10,12 +10,14 @@ #define Drive_hpp #include + #include "Disk.hpp" +#include "../../ClockReceiver/Sleeper.hpp" namespace Storage { namespace Disk { -class Drive { +class Drive: public Sleeper { public: Drive(); @@ -70,6 +72,9 @@ class Drive { */ bool get_is_ready(); + // As per Sleeper. + bool is_sleeping(); + private: std::shared_ptr track_; std::shared_ptr disk_;