rigless 0.0.6

Virtual hardware-in-the-loop runtime: run unmodified firmware on an emulated MCU with every peripheral, chip model and unit of virtual time in Rust, and a fork of QEMU built in to execute the instructions
Documentation
// Copyright (c) 2026 Rigless Labs.
// SPDX-License-Identifier: MIT OR Apache-2.0
//! The chip end of a serial peripheral interface bus.

use std::any::Any;

use crate::device::DeviceContext;

/// An integrated circuit on a serial interface's wires: what a board hangs off an MCU.
///
/// The bus is full duplex. A word crosses each way at the same time, so a peer answers in the same
/// call it's given. Both words are as they travel, after the controller's bit order has had its
/// say, because that's what's on the wire. The controller calls this and never learns what's behind
/// it. A chip implements it and never learns there's a controller. What a chip measures is set
/// through the chip's own methods, which the board that hung it reaches through the interface's
/// `chip_mut`. Nothing of the world crosses here.
pub trait Peer: std::fmt::Debug + Send + Any {
    /// The word this peer puts on `MISO` while `mosi` crosses on the controller's line.
    ///
    /// `context` is the peer's own, at the instant of the word, so a chip that needs the time to
    /// answer can ask for it. [`Card`](crate::chip::sd::Card) has the same shape on the card
    /// interface.
    fn transfer(&mut self, mosi: u16, context: &DeviceContext<'_>) -> u16;

    /// Its chip select reaching the level that selects it. Nothing, for a peer with no state to begin.
    fn select(&mut self, _context: &DeviceContext<'_>) {}

    /// Its chip select leaving that level, which for most chips ends whatever command was under way.
    fn deselect(&mut self, _context: &DeviceContext<'_>) {}

    /// Every word this peer has been sent, oldest first, or nothing where it keeps no log.
    ///
    /// This is the far end's own record. For a stand-in with no state of its own, it's the only
    /// thing that can say a stream arrived. A model that never reaches its peer would fill what the
    /// controller believes it sent just as happily. A chip answers from its own state instead, and
    /// that's its record.
    fn received(&self) -> &[u16] {
        &[]
    }
}