1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 18:30:07 +00:00

Starts seeking to automate register 3 handling.

Immediate pitfall: byte capture on the bus side isn't working correctly.
This commit is contained in:
Thomas Harte 2021-02-14 20:37:33 -05:00
parent a51d143c35
commit 52c38e72f6
4 changed files with 99 additions and 16 deletions

View File

@ -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) {

View File

@ -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) {}

View File

@ -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<uint8_t> &&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() {

View File

@ -23,7 +23,10 @@ class ReactiveDevice: public Bus::Device {
void post_response(const std::vector<uint8_t> &&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<uint8_t> &) {}
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<uint8_t> content_;
size_t expected_content_size_ = 0;
Command command_;
uint16_t register3_;
const uint8_t default_adb_device_id_;
void reset();
};
}