rigless 0.0.5

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; a fork of QEMU is built in and executes 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 is given. Both words are as they travel, after the controller's bit order has had its say, because
/// that is what is on the wire. The controller calls this and never learns what is behind it; a chip
/// implements it and never learns there is 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; the same shape [`Card`](crate::chip::sd::Card) on the card interface has.
    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, and for a stand-in with no state of its own it is the only thing
    /// that can say a stream arrived: what the controller believes it sent, a model that never reaches its
    /// peer would fill just as happily. A chip answers from its own state instead, and that is its record.
    fn received(&self) -> &[u16] {
        &[]
    }
}