// Copyright (c) 2026 Rigless Labs.
// SPDX-License-Identifier: Apache-2.0
//! A machine as its module describes it: the MCUs on the board, each with its SoC, its engine, and its interrupts.
//!
//! A machine module hands the runtime a `Machine`, in `rigless::machine`: its name and its `Target`s, one per MCU on the board, each with its name, its `Soc` with the machine's models bound, the `SidecarCommand` its engine is started as, and the function that turns one of that SoC's interrupt numbers into the engine's `InterruptLine`. Most machines carry one target; the type is a list because a board with a second MCU is a second engine, not a second session. `machine::all()` lists every machine this build carries by the name `rigless run --machine` matches.
//!
//! One module per machine returns a [`Machine`], and [`all`] lists every machine this build
//! carries by the name `rigless run --machine` matches. A core family gets a module of its own,
//! [`armv7m`] first, mirroring the machine the sidecar carries for it.
use crate::sidecar::{InterruptLine, SidecarCommand};
use crate::soc::{Error, Soc};
pub mod armv7m;
#[cfg(feature = "stm32f427")]
pub mod pixracer;
/// A machine's constructor: the SoC built and the sidecar configured, or the SoC's assembly error.
pub type Constructor = fn() -> Result<Machine, Error>;
/// Every machine this build carries, by the name `rigless run --machine` matches, with its constructor.
#[must_use]
pub fn all() -> &'static [(&'static str, Constructor)] {
const MACHINES: &[(&str, Constructor)] = &[
#[cfg(feature = "stm32f427")]
(pixracer::NAME, pixracer::machine),
];
MACHINES
}
/// One MCU of a board: its SoC, how its engine is started, and how its interrupts route.
#[derive(Debug)]
pub struct Target {
/// The name the command line matches and the output labels this target with.
pub name: &'static str,
/// The SoC, built with the machine's models bound.
pub soc: Soc,
/// What this target's engine is started as.
pub sidecar: SidecarCommand,
/// The engine's line for one of the SoC's interrupt numbers, or `None` when it has no line for it.
pub interrupt_line: fn(u16) -> Option<InterruptLine>,
}
/// One machine, ready for a session: its name and the targets on it.
///
/// A session steps the targets in the order the machine lists them, so the order is the machine's to
/// choose and is the same on every run.
#[derive(Debug)]
pub struct Machine {
/// The name `rigless run --machine` matches.
pub name: &'static str,
/// The MCUs on the board, at least one.
pub targets: Vec<Target>,
}
impl Machine {
/// The index of the target called `name`.
#[must_use]
pub fn target(&self, name: &str) -> Option<usize> {
self.targets.iter().position(|target| target.name == name)
}
/// Every target's name, in the machine's order.
pub fn target_names(&self) -> impl Iterator<Item = &'static str> {
self.targets.iter().map(|target| target.name)
}
}