From bf7e9cfd621e389d07dbaa8b8f9fc6b2f4934fab Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 2 Nov 2019 19:47:44 -0400 Subject: [PATCH] Pulls the intelligent keyboard into its own file. --- Machines/AtariST/AtariST.cpp | 190 +----------------- Machines/AtariST/IntelligentKeyboard.cpp | 180 +++++++++++++++++ Machines/AtariST/IntelligentKeyboard.hpp | 68 +++++++ .../Clock Signal.xcodeproj/project.pbxproj | 8 + 4 files changed, 257 insertions(+), 189 deletions(-) create mode 100644 Machines/AtariST/IntelligentKeyboard.cpp create mode 100644 Machines/AtariST/IntelligentKeyboard.hpp diff --git a/Machines/AtariST/AtariST.cpp b/Machines/AtariST/AtariST.cpp index 49bbc0fd8..22e559b41 100644 --- a/Machines/AtariST/AtariST.cpp +++ b/Machines/AtariST/AtariST.cpp @@ -18,6 +18,7 @@ #include "../../Components/6850/6850.hpp" #include "DMAController.hpp" +#include "IntelligentKeyboard.hpp" #include "Video.hpp" #include "../../ClockReceiver/JustInTime.hpp" @@ -34,195 +35,6 @@ namespace ST { const int CLOCK_RATE = 8021247; -/*! - A receiver for the Atari ST's "intelligent keyboard" commands, which actually cover - keyboard input and output and mouse handling. -*/ -class IntelligentKeyboard: - public Serial::Line::ReadDelegate, - public ClockingHint::Source { - public: - IntelligentKeyboard(Serial::Line &input, Serial::Line &output) : output_line_(output) { - input.set_read_delegate(this, Storage::Time(2, 15625)); - output_line_.set_writer_clock_rate(15625); - } - - bool serial_line_did_produce_bit(Serial::Line *, int bit) final { - // Shift. - command_ = (command_ >> 1) | (bit << 9); - - // If that's 10 bits, decode a byte and stop. - bit_count_ = (bit_count_ + 1) % 10; - if(!bit_count_) { - dispatch_command(uint8_t(command_ >> 1)); - command_ = 0; - return false; - } - - // Continue. - return true; - } - - ClockingHint::Preference preferred_clocking() final { - return output_line_.transmission_data_time_remaining().as_integral() ? ClockingHint::Preference::RealTime : ClockingHint::Preference::None; - } - - void run_for(HalfCycles duration) { - output_line_.advance_writer(duration); - } - - private: - // MARK: - Serial line state. - int bit_count_ = 0; - int command_ = 0; - Serial::Line &output_line_; - - void output_byte(uint8_t value) { - // Wrap the value in a start and stop bit, and send it on its way. - output_line_.write(2, 10, 0x200 | (value << 1)); - update_clocking_observer(); - } - - // MARK: - Command dispatch. - std::vector command_sequence_; - void dispatch_command(uint8_t command) { - // Enqueue for parsing. - command_sequence_.push_back(command); - - // For each possible command, check that the proper number of bytes are present. - // If not, exit. If so, perform and drop out of the switch. - switch(command_sequence_.front()) { - default: - printf("Unrecognised IKBD command %02x\n", command); - break; - - case 0x80: - /* - Reset: 0x80 0x01. - "Any byte following an 0x80 command byte other than 0x01 is ignored (and causes the 0x80 to be ignored)." - */ - if(command_sequence_.size() != 2) return; - if(command_sequence_[1] == 0x01) { - reset(); - } - break; - - case 0x07: - if(command_sequence_.size() != 2) return; - set_mouse_button_actions(command_sequence_[1]); - break; - - case 0x08: - set_relative_mouse_position_reporting(); - break; - - case 0x09: - if(command_sequence_.size() != 5) return; - set_absolute_mouse_position_reporting( - uint16_t((command_sequence_[1] << 8) | command_sequence_[2]), - uint16_t((command_sequence_[3] << 8) | command_sequence_[4]) - ); - break; - - case 0x0a: - if(command_sequence_.size() != 3) return; - set_mouse_keycode_reporting(command_sequence_[1], command_sequence_[2]); - break; - - case 0x0b: - if(command_sequence_.size() != 3) return; - set_mouse_threshold(command_sequence_[1], command_sequence_[2]); - break; - - case 0x0c: - if(command_sequence_.size() != 3) return; - set_mouse_scale(command_sequence_[1], command_sequence_[2]); - break; - - case 0x0d: - interrogate_mouse_position(); - break; - - case 0x0e: - if(command_sequence_.size() != 6) return; - /* command_sequence_[1] has no defined meaning. */ - set_mouse_position( - uint16_t((command_sequence_[2] << 8) | command_sequence_[3]), - uint16_t((command_sequence_[4] << 8) | command_sequence_[5]) - ); - break; - - case 0x0f: set_mouse_y_upward(); break; - case 0x10: set_mouse_y_downward(); break; - case 0x11: resume(); break; - case 0x12: disable_mouse(); break; - case 0x13: pause(); break; - case 0x1a: disable_joysticks(); break; - } - - // There was no premature exit, so a complete command sequence must have been satisfied. - command_sequence_.clear(); - } - - // MARK: - Flow control. - void reset() { - // Reset should perform a self test, lasting at most 200ms, then post 0xf0. - // Following that it should look for any keys that currently seem to be pressed. - // Those are considered stuck and a break code is generated for them. - output_byte(0xf0); - } - - void resume() { - } - - void pause() { - } - - // MARK: - Mouse commands. - void disable_mouse() { - } - - void set_relative_mouse_position_reporting() { - } - - void set_absolute_mouse_position_reporting(uint16_t max_x, uint16_t max_y) { - } - - void set_mouse_position(uint16_t x, uint16_t y) { - } - - void set_mouse_keycode_reporting(uint8_t delta_x, uint8_t delta_y) { - } - - void set_mouse_threshold(uint8_t x, uint8_t y) { - } - - void set_mouse_scale(uint8_t x, uint8_t y) { - } - - void set_mouse_y_downward() { - } - - void set_mouse_y_upward() { - } - - void set_mouse_button_actions(uint8_t actions) { - } - - void interrogate_mouse_position() { - output_byte(0xf7); // Beginning of mouse response. - output_byte(0x00); // 0000dcba; a = right button down since last interrogation, b = right button up since, c/d = left button. - output_byte(0x00); // x motion: MSB, LSB - output_byte(0x00); - output_byte(0x00); // y motion: MSB, LSB - output_byte(0x00); - } - - // MARK: - Joystick commands. - void disable_joysticks() { - } -}; - using Target = Analyser::Static::Target; class ConcreteMachine: public Atari::ST::Machine, diff --git a/Machines/AtariST/IntelligentKeyboard.cpp b/Machines/AtariST/IntelligentKeyboard.cpp new file mode 100644 index 000000000..b71a70f5c --- /dev/null +++ b/Machines/AtariST/IntelligentKeyboard.cpp @@ -0,0 +1,180 @@ +// +// IntelligentKeyboard.cpp +// Clock Signal +// +// Created by Thomas Harte on 02/11/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#include "IntelligentKeyboard.hpp" + +using namespace Atari::ST; + +IntelligentKeyboard::IntelligentKeyboard(Serial::Line &input, Serial::Line &output) : output_line_(output) { + input.set_read_delegate(this, Storage::Time(2, 15625)); + output_line_.set_writer_clock_rate(15625); +} + +bool IntelligentKeyboard::serial_line_did_produce_bit(Serial::Line *, int bit) { + // Shift. + command_ = (command_ >> 1) | (bit << 9); + + // If that's 10 bits, decode a byte and stop. + bit_count_ = (bit_count_ + 1) % 10; + if(!bit_count_) { + dispatch_command(uint8_t(command_ >> 1)); + command_ = 0; + return false; + } + + // Continue. + return true; +} + +ClockingHint::Preference IntelligentKeyboard::preferred_clocking() { + return output_line_.transmission_data_time_remaining().as_integral() ? ClockingHint::Preference::RealTime : ClockingHint::Preference::None; +} + +void IntelligentKeyboard::run_for(HalfCycles duration) { + output_line_.advance_writer(duration); +} + +void IntelligentKeyboard::output_byte(uint8_t value) { + // Wrap the value in a start and stop bit, and send it on its way. + output_line_.write(2, 10, 0x200 | (value << 1)); + update_clocking_observer(); +} + +void IntelligentKeyboard::dispatch_command(uint8_t command) { + // Enqueue for parsing. + command_sequence_.push_back(command); + + // For each possible command, check that the proper number of bytes are present. + // If not, exit. If so, perform and drop out of the switch. + switch(command_sequence_.front()) { + default: + printf("Unrecognised IKBD command %02x\n", command); + break; + + case 0x80: + /* + Reset: 0x80 0x01. + "Any byte following an 0x80 command byte other than 0x01 is ignored (and causes the 0x80 to be ignored)." + */ + if(command_sequence_.size() != 2) return; + if(command_sequence_[1] == 0x01) { + reset(); + } + break; + + case 0x07: + if(command_sequence_.size() != 2) return; + set_mouse_button_actions(command_sequence_[1]); + break; + + case 0x08: + set_relative_mouse_position_reporting(); + break; + + case 0x09: + if(command_sequence_.size() != 5) return; + set_absolute_mouse_position_reporting( + uint16_t((command_sequence_[1] << 8) | command_sequence_[2]), + uint16_t((command_sequence_[3] << 8) | command_sequence_[4]) + ); + break; + + case 0x0a: + if(command_sequence_.size() != 3) return; + set_mouse_keycode_reporting(command_sequence_[1], command_sequence_[2]); + break; + + case 0x0b: + if(command_sequence_.size() != 3) return; + set_mouse_threshold(command_sequence_[1], command_sequence_[2]); + break; + + case 0x0c: + if(command_sequence_.size() != 3) return; + set_mouse_scale(command_sequence_[1], command_sequence_[2]); + break; + + case 0x0d: + interrogate_mouse_position(); + break; + + case 0x0e: + if(command_sequence_.size() != 6) return; + /* command_sequence_[1] has no defined meaning. */ + set_mouse_position( + uint16_t((command_sequence_[2] << 8) | command_sequence_[3]), + uint16_t((command_sequence_[4] << 8) | command_sequence_[5]) + ); + break; + + case 0x0f: set_mouse_y_upward(); break; + case 0x10: set_mouse_y_downward(); break; + case 0x11: resume(); break; + case 0x12: disable_mouse(); break; + case 0x13: pause(); break; + case 0x1a: disable_joysticks(); break; + } + + // There was no premature exit, so a complete command sequence must have been satisfied. + command_sequence_.clear(); +} + +void IntelligentKeyboard::reset() { + // Reset should perform a self test, lasting at most 200ms, then post 0xf0. + // Following that it should look for any keys that currently seem to be pressed. + // Those are considered stuck and a break code is generated for them. + output_byte(0xf0); +} + +void IntelligentKeyboard::resume() { +} + +void IntelligentKeyboard::pause() { +} + +void IntelligentKeyboard::disable_mouse() { +} + +void IntelligentKeyboard::set_relative_mouse_position_reporting() { +} + +void IntelligentKeyboard::set_absolute_mouse_position_reporting(uint16_t max_x, uint16_t max_y) { +} + +void IntelligentKeyboard::set_mouse_position(uint16_t x, uint16_t y) { +} + +void IntelligentKeyboard::set_mouse_keycode_reporting(uint8_t delta_x, uint8_t delta_y) { +} + +void IntelligentKeyboard::set_mouse_threshold(uint8_t x, uint8_t y) { +} + +void IntelligentKeyboard::set_mouse_scale(uint8_t x, uint8_t y) { +} + +void IntelligentKeyboard::set_mouse_y_downward() { +} + +void IntelligentKeyboard::set_mouse_y_upward() { +} + +void IntelligentKeyboard::set_mouse_button_actions(uint8_t actions) { +} + +void IntelligentKeyboard::interrogate_mouse_position() { + output_byte(0xf7); // Beginning of mouse response. + output_byte(0x00); // 0000dcba; a = right button down since last interrogation, b = right button up since, c/d = left button. + output_byte(0x00); // x motion: MSB, LSB + output_byte(0x00); + output_byte(0x00); // y motion: MSB, LSB + output_byte(0x00); +} + +void IntelligentKeyboard::disable_joysticks() { +} diff --git a/Machines/AtariST/IntelligentKeyboard.hpp b/Machines/AtariST/IntelligentKeyboard.hpp new file mode 100644 index 000000000..ebb2e50b4 --- /dev/null +++ b/Machines/AtariST/IntelligentKeyboard.hpp @@ -0,0 +1,68 @@ +// +// IntelligentKeyboard.hpp +// Clock Signal +// +// Created by Thomas Harte on 02/11/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#ifndef IntelligentKeyboard_hpp +#define IntelligentKeyboard_hpp + +#include "../../ClockReceiver/ClockingHintSource.hpp" +#include "../../Components/SerialPort/SerialPort.hpp" + +namespace Atari { +namespace ST { + +/*! + A receiver for the Atari ST's "intelligent keyboard" commands, which actually cover + keyboard input and output and mouse handling. +*/ +class IntelligentKeyboard: + public Serial::Line::ReadDelegate, + public ClockingHint::Source { + public: + IntelligentKeyboard(Serial::Line &input, Serial::Line &output); + ClockingHint::Preference preferred_clocking() final; + void run_for(HalfCycles duration); + + private: + // MARK: - Serial line state. + int bit_count_ = 0; + int command_ = 0; + Serial::Line &output_line_; + + void output_byte(uint8_t value); + bool serial_line_did_produce_bit(Serial::Line *, int bit) final; + + // MARK: - Command dispatch. + std::vector command_sequence_; + void dispatch_command(uint8_t command); + + // MARK: - Flow control. + void reset(); + void resume(); + void pause(); + + // MARK: - Mouse. + void disable_mouse(); + void set_relative_mouse_position_reporting(); + void set_absolute_mouse_position_reporting(uint16_t max_x, uint16_t max_y); + void set_mouse_position(uint16_t x, uint16_t y); + void set_mouse_keycode_reporting(uint8_t delta_x, uint8_t delta_y); + void set_mouse_threshold(uint8_t x, uint8_t y); + void set_mouse_scale(uint8_t x, uint8_t y); + void set_mouse_y_downward(); + void set_mouse_y_upward(); + void set_mouse_button_actions(uint8_t actions); + void interrogate_mouse_position(); + + // MARK: - Joystick. + void disable_joysticks(); +}; + +} +} + +#endif /* IntelligentKeyboard_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index d47cae82d..b93eda641 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -341,6 +341,8 @@ 4BA3189422E7A4CA00D18CFA /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; 4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BA61EAF1D91515900B3C876 /* NSData+StdVector.mm */; }; 4BA91E1D216D85BA00F79557 /* MasterSystemVDPTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BA91E1C216D85BA00F79557 /* MasterSystemVDPTests.mm */; }; + 4BAC075E236E4B11003C3AB1 /* IntelligentKeyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BAC075C236E4B11003C3AB1 /* IntelligentKeyboard.cpp */; }; + 4BAC075F236E4B11003C3AB1 /* IntelligentKeyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BAC075C236E4B11003C3AB1 /* IntelligentKeyboard.cpp */; }; 4BAD13441FF709C700FD114A /* MSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E61051FF34737002A9DBD /* MSX.cpp */; }; 4BAE49582032881E004BE78E /* CSZX8081.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B14978E1EE4B4D200CE2596 /* CSZX8081.mm */; }; 4BAE495920328897004BE78E /* ZX8081OptionsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B95FA9C1F11893B0008E395 /* ZX8081OptionsPanel.swift */; }; @@ -1149,6 +1151,8 @@ 4BAA167B21582B1D008A3276 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = ""; }; 4BAB62AC1D3272D200DF5BA0 /* Disk.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Disk.hpp; sourceTree = ""; }; 4BAB62AE1D32730D00DF5BA0 /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Storage.hpp; sourceTree = ""; }; + 4BAC075C236E4B11003C3AB1 /* IntelligentKeyboard.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IntelligentKeyboard.cpp; sourceTree = ""; }; + 4BAC075D236E4B11003C3AB1 /* IntelligentKeyboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = IntelligentKeyboard.hpp; sourceTree = ""; }; 4BAF2B4C2004580C00480230 /* DMK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DMK.cpp; sourceTree = ""; }; 4BAF2B4D2004580C00480230 /* DMK.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DMK.hpp; sourceTree = ""; }; 4BB06B211F316A3F00600C7A /* ForceInline.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ForceInline.hpp; sourceTree = ""; }; @@ -3238,9 +3242,11 @@ children = ( 4BC131682346C61100E4FF3D /* AtariST.cpp */, 4B21922B236523CB007FEEBC /* DMAController.cpp */, + 4BAC075C236E4B11003C3AB1 /* IntelligentKeyboard.cpp */, 4BB50DC6234828A20057B9CA /* Video.cpp */, 4BC131692346C61100E4FF3D /* AtariST.hpp */, 4B21922C236523CB007FEEBC /* DMAController.hpp */, + 4BAC075D236E4B11003C3AB1 /* IntelligentKeyboard.hpp */, 4BB50DC7234828A20057B9CA /* Video.hpp */, ); path = AtariST; @@ -4184,6 +4190,7 @@ 4B055A971FAE85BB0060FFFF /* ZX8081.cpp in Sources */, 4B055AAD1FAE85FD0060FFFF /* PCMTrack.cpp in Sources */, 4BD67DD1209BF27B00AB2146 /* Encoder.cpp in Sources */, + 4BAC075F236E4B11003C3AB1 /* IntelligentKeyboard.cpp in Sources */, 4B055AC61FAE9AEE0060FFFF /* TIASound.cpp in Sources */, 4B89451F201967B4007DE474 /* Tape.cpp in Sources */, 4B055AA81FAE85EF0060FFFF /* Shifter.cpp in Sources */, @@ -4331,6 +4338,7 @@ 4BEA52631DF339D7007E74F2 /* SoundGenerator.cpp in Sources */, 4BD67DD0209BF27B00AB2146 /* Encoder.cpp in Sources */, 4BB50DC8234828A20057B9CA /* Video.cpp in Sources */, + 4BAC075E236E4B11003C3AB1 /* IntelligentKeyboard.cpp in Sources */, 4BAE495920328897004BE78E /* ZX8081OptionsPanel.swift in Sources */, 4B89451A201967B4007DE474 /* ConfidenceSummary.cpp in Sources */, 4B54C0C51F8D91D90050900F /* Keyboard.cpp in Sources */,