From 52c38e72f665e52658b5f49ff5e03818513b61bf Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 14 Feb 2021 20:37:33 -0500 Subject: [PATCH] Starts seeking to automate register 3 handling. Immediate pitfall: byte capture on the bus side isn't working correctly. --- Machines/Apple/ADB/Bus.cpp | 2 + Machines/Apple/ADB/Bus.hpp | 9 ++- Machines/Apple/ADB/ReactiveDevice.cpp | 86 +++++++++++++++++++++++---- Machines/Apple/ADB/ReactiveDevice.hpp | 18 +++++- 4 files changed, 99 insertions(+), 16 deletions(-) diff --git a/Machines/Apple/ADB/Bus.cpp b/Machines/Apple/ADB/Bus.cpp index 976b04e48..709011fd4 100644 --- a/Machines/Apple/ADB/Bus.cpp +++ b/Machines/Apple/ADB/Bus.cpp @@ -50,6 +50,7 @@ void Bus::set_device_output(size_t device_id, bool output) { device->adb_bus_did_observe_event(Event::Attention); } shift_register_ = 1; + printf("!!! atn\n"); } else if(low_microseconds < 50.0) { shift(1); } else if(low_microseconds < 72.0) { @@ -71,6 +72,7 @@ void Bus::set_device_output(size_t device_id, bool output) { void Bus::shift(unsigned int value) { shift_register_ = (shift_register_ << 1) | value; + printf("!!! %d\n", value); // Trigger a byte whenever a start bit hits bit 8. if(shift_register_ & 0x100) { diff --git a/Machines/Apple/ADB/Bus.hpp b/Machines/Apple/ADB/Bus.hpp index 9c8335e82..872be4709 100644 --- a/Machines/Apple/ADB/Bus.hpp +++ b/Machines/Apple/ADB/Bus.hpp @@ -29,9 +29,12 @@ struct Command { /// The host wishes the device to broadcast register contents. Talk }; - const Type type = Type::Reserved; - const uint8_t device = 0xff; - const uint8_t reg = 0xff; + static constexpr uint8_t AllDevices = 0xff; + static constexpr uint8_t NoRegister = 0xff; + + Type type = Type::Reserved; + uint8_t device = AllDevices; + uint8_t reg = NoRegister; Command() {} Command(Type type) : type(type) {} diff --git a/Machines/Apple/ADB/ReactiveDevice.cpp b/Machines/Apple/ADB/ReactiveDevice.cpp index 3b736f544..02fba6983 100644 --- a/Machines/Apple/ADB/ReactiveDevice.cpp +++ b/Machines/Apple/ADB/ReactiveDevice.cpp @@ -16,7 +16,9 @@ using namespace Apple::ADB; ReactiveDevice::ReactiveDevice(Apple::ADB::Bus &bus, uint8_t adb_device_id) : bus_(bus), device_id_(bus.add_device(this)), - adb_device_id_(adb_device_id) {} + default_adb_device_id_(adb_device_id) { + reset(); +} void ReactiveDevice::post_response(const std::vector &&response) { response_ = std::move(response); @@ -28,6 +30,18 @@ void ReactiveDevice::advance_state(double microseconds, bool current_level) { // Do nothing if not in the process of posting a response. if(response_.empty()) return; + /* + Total process below: + + (1) assume that the data was enqueued before the stop bit had + concluded; wait for the end of that; + (2) wait for the stop-to-start time period; + (3) output a start bit of '1'; + (4) output all enqueued bytes, MSB to LSB; + (5) output a stop bit of '0'; and + (6) return this device's output level to high and top. + */ + // Wait for the bus to be clear if transmission has not yet begun. if(!current_level && bit_offset_ == -2) return; @@ -73,22 +87,72 @@ void ReactiveDevice::advance_state(double microseconds, bool current_level) { } void ReactiveDevice::adb_bus_did_observe_event(Bus::Event event, uint8_t value) { - if(!next_is_command_ && event != Bus::Event::Attention) { + if(phase_ == Phase::AwaitingAttention) { + if(event != Bus::Event::Attention) return; + phase_ = Phase::AwaitingCommand; return; } - if(next_is_command_ && event == Bus::Event::Byte) { - next_is_command_ = false; + if(event != Bus::Event::Byte) return; - const auto command = decode_command(value); - LOG(command); - if(command.device == adb_device_id_) { - // TODO: handle fixed commands here (like register 3?) - perform_command(command); + if(phase_ == Phase::AwaitingContent) { + content_.push_back(value); + if(content_.size() == expected_content_size_) { + phase_ = Phase::AwaitingAttention; + + if(command_.reg == 3) { + register3_ = uint16_t((content_[0] << 8) | content_[1]); + } else { + did_receive_data(command_, content_); + } + content_.clear(); } - } else if(event == Bus::Event::Attention) { - next_is_command_ = true; } + + if(phase_ == Phase::AwaitingCommand) { + phase_ = Phase::AwaitingAttention; + + command_ = decode_command(value); + LOG(command_); + + // Don't do anything if this command isn't relevant here. + if(command_.device != Command::AllDevices && command_.device != ((register3_ >> 8) & 0xf)) { + return; + } + + // Handle reset and register 3 here automatically; pass everything else along. + switch(command_.type) { + case Command::Type::Reset: + reset(); + [[fallthrough]]; + default: + perform_command(command_); + break; + + case Command::Type::Listen: + case Command::Type::Talk: + if(command_.reg == 3) { + if(command_.type == Command::Type::Talk) { + post_response({uint8_t(register3_ >> 8), uint8_t(register3_ & 0xff)}); + } else { + receive_bytes(2); + } + } else { + perform_command(command_); + } + break; + } + } +} + +void ReactiveDevice::receive_bytes(size_t count) { + content_.clear(); + expected_content_size_ = count; + phase_ = Phase::AwaitingContent; +} + +void ReactiveDevice::reset() { + register3_ = uint16_t(0x6000 | (default_adb_device_id_ << 8)); } void ReactiveDevice::post_service_request() { diff --git a/Machines/Apple/ADB/ReactiveDevice.hpp b/Machines/Apple/ADB/ReactiveDevice.hpp index 13b68377e..af52e3855 100644 --- a/Machines/Apple/ADB/ReactiveDevice.hpp +++ b/Machines/Apple/ADB/ReactiveDevice.hpp @@ -23,7 +23,10 @@ class ReactiveDevice: public Bus::Device { void post_response(const std::vector &&response); void post_service_request(); + void receive_bytes(size_t count); + virtual void perform_command(const Command &command) = 0; + virtual void did_receive_data(const Command &, const std::vector &) {} private: void advance_state(double microseconds, bool current_level) override; @@ -37,8 +40,19 @@ class ReactiveDevice: public Bus::Device { int bit_offset_ = 0; double microseconds_at_bit_ = 0; - bool next_is_command_ = false; - uint8_t adb_device_id_; + enum class Phase { + AwaitingAttention, + AwaitingCommand, + AwaitingContent, + } phase_ = Phase::AwaitingAttention; + std::vector content_; + size_t expected_content_size_ = 0; + Command command_; + + uint16_t register3_; + const uint8_t default_adb_device_id_; + + void reset(); }; }