mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Introduces the ActivityObserver
protocol for LEDs, drive events, etc.
The Electron's caps lock LED is the test case.
This commit is contained in:
parent
d1b889aa61
commit
70e6c3b2f6
47
ActivityObserver/ActivityObserver.hpp
Normal file
47
ActivityObserver/ActivityObserver.hpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// Header.h
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 07/05/2018.
|
||||||
|
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef Header_h
|
||||||
|
#define Header_h
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Provides a purely virtual base class for anybody that wants to receive notifications of
|
||||||
|
'activity' — any feedback from an emulated system which a user could perceive other than
|
||||||
|
through the machine's native audio and video outputs.
|
||||||
|
|
||||||
|
So: status LEDs, drive activity, etc. A receiver may choose to make appropriate noises
|
||||||
|
and/or to show or unshow status indicators.
|
||||||
|
*/
|
||||||
|
class ActivityObserver {
|
||||||
|
public:
|
||||||
|
/// Announces to the receiver that there is an LED of name @c name.
|
||||||
|
virtual void register_led(const std::string &name) = 0;
|
||||||
|
|
||||||
|
/// Announces to the receiver that there is a drive of name @c name.
|
||||||
|
virtual void register_drive(const std::string &name) = 0;
|
||||||
|
|
||||||
|
/// Informs the receiver of the new state of the LED with name @c name.
|
||||||
|
virtual void set_led_status(const std::string &name, bool lit) = 0;
|
||||||
|
|
||||||
|
enum class DriveEvent {
|
||||||
|
Step,
|
||||||
|
StepBelowZero,
|
||||||
|
StepBeyondMaximum
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Informs the receiver that the named event just occurred for the drive with name @c name.
|
||||||
|
virtual void announce_drive_event(const std::string &name, DriveEvent event) = 0;
|
||||||
|
|
||||||
|
/// Informs the receiver of the motor-on status of the drive with name @c name.
|
||||||
|
virtual void set_drive_motor_status(const std::string &name, bool is_on) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* Header_h */
|
@ -22,6 +22,10 @@ MultiMachine::MultiMachine(std::vector<std::unique_ptr<DynamicMachine>> &&machin
|
|||||||
crt_machine_.set_delegate(this);
|
crt_machine_.set_delegate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActivitySource::Machine *MultiMachine::activity_source() {
|
||||||
|
return nullptr; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
ConfigurationTarget::Machine *MultiMachine::configuration_target() {
|
ConfigurationTarget::Machine *MultiMachine::configuration_target() {
|
||||||
if(has_picked_) {
|
if(has_picked_) {
|
||||||
return machines_.front()->configuration_target();
|
return machines_.front()->configuration_target();
|
||||||
|
@ -50,6 +50,7 @@ class MultiMachine: public ::Machine::DynamicMachine, public MultiCRTMachine::De
|
|||||||
static bool would_collapse(const std::vector<std::unique_ptr<DynamicMachine>> &machines);
|
static bool would_collapse(const std::vector<std::unique_ptr<DynamicMachine>> &machines);
|
||||||
MultiMachine(std::vector<std::unique_ptr<DynamicMachine>> &&machines);
|
MultiMachine(std::vector<std::unique_ptr<DynamicMachine>> &&machines);
|
||||||
|
|
||||||
|
ActivitySource::Machine *activity_source() override;
|
||||||
ConfigurationTarget::Machine *configuration_target() override;
|
ConfigurationTarget::Machine *configuration_target() override;
|
||||||
CRTMachine::Machine *crt_machine() override;
|
CRTMachine::Machine *crt_machine() override;
|
||||||
JoystickMachine::Machine *joystick_machine() override;
|
JoystickMachine::Machine *joystick_machine() override;
|
||||||
|
24
Machines/ActivitySource.hpp
Normal file
24
Machines/ActivitySource.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// ActivitySource.h
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 07/05/2018.
|
||||||
|
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ActivitySource_h
|
||||||
|
#define ActivitySource_h
|
||||||
|
|
||||||
|
#include "../ActivityObserver/ActivityObserver.hpp"
|
||||||
|
|
||||||
|
namespace ActivitySource {
|
||||||
|
|
||||||
|
class Machine {
|
||||||
|
public:
|
||||||
|
virtual void set_activity_observer(ActivityObserver *receiver) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ActivitySource_h */
|
@ -10,6 +10,7 @@
|
|||||||
#define DynamicMachine_h
|
#define DynamicMachine_h
|
||||||
|
|
||||||
#include "../Configurable/Configurable.hpp"
|
#include "../Configurable/Configurable.hpp"
|
||||||
|
#include "ActivitySource.hpp"
|
||||||
#include "ConfigurationTarget.hpp"
|
#include "ConfigurationTarget.hpp"
|
||||||
#include "CRTMachine.hpp"
|
#include "CRTMachine.hpp"
|
||||||
#include "JoystickMachine.hpp"
|
#include "JoystickMachine.hpp"
|
||||||
@ -24,6 +25,8 @@ namespace Machine {
|
|||||||
*/
|
*/
|
||||||
struct DynamicMachine {
|
struct DynamicMachine {
|
||||||
virtual ~DynamicMachine() {}
|
virtual ~DynamicMachine() {}
|
||||||
|
|
||||||
|
virtual ActivitySource::Machine *activity_source() = 0;
|
||||||
virtual ConfigurationTarget::Machine *configuration_target() = 0;
|
virtual ConfigurationTarget::Machine *configuration_target() = 0;
|
||||||
virtual CRTMachine::Machine *crt_machine() = 0;
|
virtual CRTMachine::Machine *crt_machine() = 0;
|
||||||
virtual JoystickMachine::Machine *joystick_machine() = 0;
|
virtual JoystickMachine::Machine *joystick_machine() = 0;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "Electron.hpp"
|
#include "Electron.hpp"
|
||||||
|
|
||||||
|
#include "../ActivitySource.hpp"
|
||||||
#include "../ConfigurationTarget.hpp"
|
#include "../ConfigurationTarget.hpp"
|
||||||
#include "../CRTMachine.hpp"
|
#include "../CRTMachine.hpp"
|
||||||
#include "../KeyboardMachine.hpp"
|
#include "../KeyboardMachine.hpp"
|
||||||
@ -45,7 +46,8 @@ class ConcreteMachine:
|
|||||||
public Configurable::Device,
|
public Configurable::Device,
|
||||||
public CPU::MOS6502::BusHandler,
|
public CPU::MOS6502::BusHandler,
|
||||||
public Tape::Delegate,
|
public Tape::Delegate,
|
||||||
public Utility::TypeRecipient {
|
public Utility::TypeRecipient,
|
||||||
|
public ActivitySource::Machine {
|
||||||
public:
|
public:
|
||||||
ConcreteMachine() :
|
ConcreteMachine() :
|
||||||
m6502_(*this),
|
m6502_(*this),
|
||||||
@ -215,12 +217,15 @@ class ConcreteMachine:
|
|||||||
|
|
||||||
tape_.set_is_enabled((*value & 6) != 6);
|
tape_.set_is_enabled((*value & 6) != 6);
|
||||||
tape_.set_is_in_input_mode((*value & 6) == 0);
|
tape_.set_is_in_input_mode((*value & 6) == 0);
|
||||||
tape_.set_is_running(((*value)&0x40) ? true : false);
|
tape_.set_is_running((*value & 0x40) ? true : false);
|
||||||
|
|
||||||
// TODO: caps lock LED
|
caps_led_state_ = !!(*value & 0x80);
|
||||||
|
if(activity_observer_)
|
||||||
|
activity_observer_->set_led_status(caps_led, caps_led_state_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// deliberate fallthrough
|
// deliberate fallthrough; fe07 contains the display mode.
|
||||||
|
|
||||||
case 0xfe02: case 0xfe03:
|
case 0xfe02: case 0xfe03:
|
||||||
case 0xfe08: case 0xfe09: case 0xfe0a: case 0xfe0b:
|
case 0xfe08: case 0xfe09: case 0xfe0a: case 0xfe0b:
|
||||||
case 0xfe0c: case 0xfe0d: case 0xfe0e: case 0xfe0f:
|
case 0xfe0c: case 0xfe0d: case 0xfe0e: case 0xfe0f:
|
||||||
@ -322,8 +327,6 @@ class ConcreteMachine:
|
|||||||
if(!ram_[0x247] && service_call == 14) {
|
if(!ram_[0x247] && service_call == 14) {
|
||||||
tape_.set_delegate(nullptr);
|
tape_.set_delegate(nullptr);
|
||||||
|
|
||||||
// TODO: handle tape wrap around.
|
|
||||||
|
|
||||||
int cycles_left_while_plausibly_in_data = 50;
|
int cycles_left_while_plausibly_in_data = 50;
|
||||||
tape_.clear_interrupts(Interrupt::ReceiveDataFull);
|
tape_.clear_interrupts(Interrupt::ReceiveDataFull);
|
||||||
while(!tape_.get_tape()->is_at_end()) {
|
while(!tape_.get_tape()->is_at_end()) {
|
||||||
@ -477,6 +480,14 @@ class ConcreteMachine:
|
|||||||
return selection_set;
|
return selection_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_activity_observer(ActivityObserver *observer) override {
|
||||||
|
activity_observer_ = observer;
|
||||||
|
if(activity_observer_) {
|
||||||
|
activity_observer_->register_led(caps_led);
|
||||||
|
activity_observer_->set_led_status(caps_led, caps_led_state_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// MARK: - Work deferral updates.
|
// MARK: - Work deferral updates.
|
||||||
inline void update_display() {
|
inline void update_display() {
|
||||||
@ -563,6 +574,11 @@ class ConcreteMachine:
|
|||||||
Outputs::Speaker::LowpassSpeaker<SoundGenerator> speaker_;
|
Outputs::Speaker::LowpassSpeaker<SoundGenerator> speaker_;
|
||||||
|
|
||||||
bool speaker_is_enabled_ = false;
|
bool speaker_is_enabled_ = false;
|
||||||
|
|
||||||
|
// MARK: - Caps Lock status and the activity observer.
|
||||||
|
const std::string caps_led = "CAPS";
|
||||||
|
bool caps_led_state_ = false;
|
||||||
|
ActivityObserver *activity_observer_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,10 @@ template<typename T> class TypedDynamicMachine: public ::Machine::DynamicMachine
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActivitySource::Machine *activity_source() override {
|
||||||
|
return get<ActivitySource::Machine>();
|
||||||
|
}
|
||||||
|
|
||||||
ConfigurationTarget::Machine *configuration_target() override {
|
ConfigurationTarget::Machine *configuration_target() override {
|
||||||
return get<ConfigurationTarget::Machine>();
|
return get<ConfigurationTarget::Machine>();
|
||||||
}
|
}
|
||||||
|
@ -697,6 +697,8 @@
|
|||||||
4B055ABE1FAE98000060FFFF /* MachineForTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MachineForTarget.cpp; sourceTree = "<group>"; };
|
4B055ABE1FAE98000060FFFF /* MachineForTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MachineForTarget.cpp; sourceTree = "<group>"; };
|
||||||
4B055ABF1FAE98000060FFFF /* MachineForTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MachineForTarget.hpp; sourceTree = "<group>"; };
|
4B055ABF1FAE98000060FFFF /* MachineForTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MachineForTarget.hpp; sourceTree = "<group>"; };
|
||||||
4B055AF01FAE9C080060FFFF /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
|
4B055AF01FAE9C080060FFFF /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
|
||||||
|
4B055C1E20A113B00014E5AB /* ActivityObserver.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ActivityObserver.hpp; sourceTree = "<group>"; };
|
||||||
|
4B055C1F20A1166A0014E5AB /* ActivitySource.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ActivitySource.hpp; sourceTree = "<group>"; };
|
||||||
4B0783591FC11D10001D12BB /* Configurable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Configurable.cpp; sourceTree = "<group>"; };
|
4B0783591FC11D10001D12BB /* Configurable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Configurable.cpp; sourceTree = "<group>"; };
|
||||||
4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80InterruptTests.swift; sourceTree = "<group>"; };
|
4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80InterruptTests.swift; sourceTree = "<group>"; };
|
||||||
4B08A2761EE39306008B7065 /* TestMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMachine.h; sourceTree = "<group>"; };
|
4B08A2761EE39306008B7065 /* TestMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMachine.h; sourceTree = "<group>"; };
|
||||||
@ -1496,6 +1498,15 @@
|
|||||||
path = ../SDL;
|
path = ../SDL;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
4B055C1D20A113B00014E5AB /* ActivityObserver */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
4B055C1E20A113B00014E5AB /* ActivityObserver.hpp */,
|
||||||
|
);
|
||||||
|
name = ActivityObserver;
|
||||||
|
path = ../../ActivityObserver;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
4B0CCC411C62D0B3001CAC5F /* CRT */ = {
|
4B0CCC411C62D0B3001CAC5F /* CRT */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -2697,6 +2708,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */,
|
4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */,
|
||||||
|
4B055C1D20A113B00014E5AB /* ActivityObserver */,
|
||||||
4B8944E2201967B4007DE474 /* Analyser */,
|
4B8944E2201967B4007DE474 /* Analyser */,
|
||||||
4BB73EA01B587A5100552FC2 /* Clock Signal */,
|
4BB73EA01B587A5100552FC2 /* Clock Signal */,
|
||||||
4BB73EB51B587A5100552FC2 /* Clock SignalTests */,
|
4BB73EB51B587A5100552FC2 /* Clock SignalTests */,
|
||||||
@ -2800,6 +2812,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */,
|
4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */,
|
||||||
|
4B055C1F20A1166A0014E5AB /* ActivitySource.hpp */,
|
||||||
4BA9C3CF1D8164A9002DDB61 /* ConfigurationTarget.hpp */,
|
4BA9C3CF1D8164A9002DDB61 /* ConfigurationTarget.hpp */,
|
||||||
4B046DC31CFE651500E9E45E /* CRTMachine.hpp */,
|
4B046DC31CFE651500E9E45E /* CRTMachine.hpp */,
|
||||||
4BBB709C2020109C002FE009 /* DynamicMachine.hpp */,
|
4BBB709C2020109C002FE009 /* DynamicMachine.hpp */,
|
||||||
|
Loading…
Reference in New Issue
Block a user