mirror of
https://github.com/halleysfifthinc/AVCLAN-Mockingboard.git
synced 2026-09-25 13:22:06 +00:00
Fix deafen semantics
This commit is contained in:
+4
-1
@@ -120,7 +120,10 @@ void Bus::mute(bool mute) {
|
||||
phy_mute(mute);
|
||||
muted_ = mute; // Only update muted_ *AFTER* hardware has finished muting
|
||||
};
|
||||
void Bus::deafen(bool deaf) { deafened_ = deaf; }
|
||||
void Bus::deafen(bool deaf) {
|
||||
phy_deafen(deaf);
|
||||
deafened_ = deaf; // Only update deafened_ *AFTER* the phy has stopped acking
|
||||
}
|
||||
|
||||
auto Bus::read(Frame::Print print)
|
||||
-> expected<std::unique_ptr<Frame>, Error::Read> {
|
||||
|
||||
+2
-1
@@ -81,7 +81,8 @@ public:
|
||||
void mute(bool mute);
|
||||
bool is_muted() const { return muted_; };
|
||||
|
||||
// Set the device to be deaf to (ie ignore) bus activity
|
||||
// Set the device to be deaf to (ie don't react to) bus activity. It is
|
||||
// orthogonal to mute — a deaf device can still send frames.
|
||||
void deafen(bool deaf);
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
@@ -30,6 +30,11 @@ void phy_mute(bool mute);
|
||||
// Non-mutating (e.g. theoretically const qualified/-able)
|
||||
bool phy_is_muted(void);
|
||||
|
||||
// Withhold acknowledgement. Unlike mute this leaves TX alone: a deaf device
|
||||
// can still manipulate the bus/send frames, it just never responds (e.g. ACK,
|
||||
// etc). An empty implementation is sufficient for synchronous ports.
|
||||
void phy_deafen(bool deaf);
|
||||
|
||||
// True when there is a frame to read. This may reflect current bus state (e.g.
|
||||
// a frame can be synchronously read from the bus) or indicate that a buffered
|
||||
// frame is available to "read".
|
||||
@@ -93,6 +98,7 @@ Send phy_send_done(uint8_t *data_index);
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
// Hold the bus at a level until the matching call.
|
||||
void phy_set_dominant(void);
|
||||
void phy_set_recessive(void);
|
||||
|
||||
|
||||
@@ -83,6 +83,10 @@ bool phy_is_muted() {
|
||||
return (((VPORTA_DIR & PIN4_bm) | (VPORTA_DIR & PIN0_bm)) == 0);
|
||||
}
|
||||
|
||||
// No-op: acks are driven from inside the synchronous read path, which a deaf
|
||||
// caller never enters.
|
||||
void phy_deafen([[maybe_unused]] bool deaf) {}
|
||||
|
||||
// True when the bus is being driven (i.e. not idle/floating).
|
||||
bool phy_frame_pending() { return (!BUS_IS_IDLE) != 0; }
|
||||
|
||||
@@ -621,8 +625,22 @@ void phy_guard_leave() {
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
void phy_set_dominant(void) { AVCLAN_setBusDriven(); }
|
||||
void phy_set_recessive(void) { AVCLAN_setBusIdle(); }
|
||||
// Hold the bus at a given level.
|
||||
// Overrides and restores mute state upon release (i.e. set recessive).
|
||||
static void phy_set_state(bool dominant) {
|
||||
static bool saved_mute = false;
|
||||
if (dominant) {
|
||||
saved_mute = phy_is_muted();
|
||||
AVCLAN_setBusDriven();
|
||||
phy_mute(false);
|
||||
} else {
|
||||
AVCLAN_setBusIdle();
|
||||
phy_mute(saved_mute);
|
||||
}
|
||||
}
|
||||
|
||||
void phy_set_dominant(void) { phy_set_state(true); }
|
||||
void phy_set_recessive(void) { phy_set_state(false); }
|
||||
|
||||
#ifdef MEASURE_BUS
|
||||
#include <stdio.h> // phy_measure() reporting (debug builds only)
|
||||
|
||||
@@ -154,6 +154,11 @@ public:
|
||||
sync_ack_arming();
|
||||
}
|
||||
|
||||
void deafen(bool deaf) {
|
||||
deafened_ = deaf;
|
||||
sync_ack_arming();
|
||||
}
|
||||
|
||||
// Disarm RX ACK'ing behavior; called prior to frame TX to prevent
|
||||
// self-ACK'ing. Safe to rearm any time after sending controller addr.
|
||||
void disarm_ack() {
|
||||
@@ -310,7 +315,7 @@ private:
|
||||
// Disarming inverts the Y register (self address + parity), which leaves the
|
||||
// upper 19 bits set and so prevents any read from matching.
|
||||
void sync_ack_arming() {
|
||||
const bool arm = !muted_ && !transmitting_;
|
||||
const bool arm = !muted_ && !deafened_ && !transmitting_;
|
||||
if (arm == ack_armed_)
|
||||
return;
|
||||
pio_sm_exec_wait_blocking(pio_, sm_, pio_encode_mov_not(pio_y, pio_y));
|
||||
@@ -378,6 +383,7 @@ private:
|
||||
|
||||
bool ack_armed_ = false; // hardware: y holds self_addrp_, or its complement
|
||||
bool muted_ = false; // we don't answer on the bus
|
||||
bool deafened_ = false; // we don't answer, but may still transmit
|
||||
bool transmitting_ = false; // our own frame is on the wire
|
||||
|
||||
std::array<RxFrame, RXQ_N> rxq_ = {};
|
||||
@@ -431,6 +437,7 @@ public:
|
||||
// Claims and configures both SMs, but doesn't start them.
|
||||
void init(PIO pio, uint pin_rx, uint pin_tx) {
|
||||
pio_ = pio;
|
||||
pin_tx_ = pin_tx;
|
||||
tx_offset_ = (uint)pio_add_program(pio_, &iebus_tx_program);
|
||||
ack_offset_ = (uint)pio_add_program(pio_, &iebus_ack_program);
|
||||
tx_sm_ = (uint)pio_claim_unused_sm(pio_, true);
|
||||
@@ -474,6 +481,23 @@ public:
|
||||
|
||||
bool is_muted() const { return muted_; }
|
||||
|
||||
// Hold the bus at a given level.
|
||||
// Overrides and restores mute state upon release (i.e. set recessive).
|
||||
void set_state(bool dominant) {
|
||||
static bool saved_mute = false;
|
||||
if (dominant) {
|
||||
saved_mute = muted_;
|
||||
mute(true);
|
||||
pio_sm_set_pins_with_mask(pio_, tx_sm_, 0U, 1U << pin_tx_);
|
||||
} else {
|
||||
pio_sm_set_pins_with_mask(pio_, tx_sm_, 1U << pin_tx_, 1U << pin_tx_);
|
||||
// The ack SM parks on `wait 1 irq`, which consumes a flag raised while it
|
||||
// was down and drives the slot immediately -- Phy::mute's ordering.
|
||||
pio_interrupt_clear(pio_, ack_irq);
|
||||
mute(saved_mute);
|
||||
}
|
||||
}
|
||||
|
||||
// Send start and broadcast bits.
|
||||
Send send_header(bool is_unicast) {
|
||||
if (muted_)
|
||||
@@ -624,6 +648,7 @@ private:
|
||||
IEBusRx &rx_;
|
||||
|
||||
PIO pio_;
|
||||
uint pin_tx_;
|
||||
uint tx_sm_;
|
||||
uint tx_offset_;
|
||||
uint ack_sm_;
|
||||
@@ -768,6 +793,8 @@ extern "C" void phy_mute(bool mute) { phy.mute(mute); }
|
||||
|
||||
extern "C" bool phy_is_muted() { return phy.is_muted(); }
|
||||
|
||||
extern "C" void phy_deafen(bool deaf) { phy.rx().deafen(deaf); }
|
||||
|
||||
extern "C" bool phy_frame_pending() { return phy.rx().frame_pending(); }
|
||||
|
||||
extern "C" void phy_guard_enter() {}
|
||||
@@ -852,8 +879,8 @@ extern "C" Send phy_send_done(uint8_t *data_index) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
void phy_set_dominant() {}
|
||||
void phy_set_recessive() {}
|
||||
extern "C" void phy_set_dominant() { phy.tx().set_state(true); }
|
||||
extern "C" void phy_set_recessive() { phy.tx().set_state(false); }
|
||||
|
||||
#ifdef MEASURE_BUS
|
||||
// Sample and dump bus bit timing over the serial link (REPL `M`).
|
||||
|
||||
Reference in New Issue
Block a user