mokomoking2501/MoonECAT/runtime/simulation does not have a README file

    CoSimAdapter

    pub(open) trait CoSimAdapter {
    fn init_(Self, CoSimConfig) -> Unit
    fn write_outputs(Self,
    ProcessImage
    , ProcessImageSlice) -> Unit
    fn step(Self, SimTime, Int64) -> SimStepResult
    fn read_inputs(Self,
    ProcessImage
    , ProcessImageSlice) -> Unit
    fn shutdown(Self) -> Unit
    }

    CoSimAdapter — the trait that external plant/controller models implement.

    Lifecycle:
    1. init(config) — one-time initialization with cycle period and PI layout
    2. Per cycle: write_outputs(image, slice) → step(dt) → read_inputs(image, slice)
    3. shutdown() — cleanup

    The runtime invokes these in deterministic order within each CycleHook callback.

    Timebase

    pub(open) trait Timebase {
    fn domain(Self) -> ClockDomain
    fn now_ns(Self) -> Int64
    fn resolution_ns(Self) -> Int64
    fn is_monotonic(Self) -> Bool
    }

    Timebase — the trait each clock domain implements.

    All methods are non-blocking and must execute in bounded time. MCU implementations typically read a hardware timer register. Linux implementations use clock_gettime(CLOCK_MONOTONIC). Virtual implementations advance from an explicit schedule.

    BridgeState

    pub(all) enum BridgeState {
    Disconnected
    Connected
    Terminated(String)
    Error(String)
    } derive(Eq,
    Debug
    )

    Connection state of the external bridge.

    BridgeTransport

    pub(all) enum BridgeTransport {
    UnixSocket(String)
    NamedPipe(String)
    SharedMemory(name~ : String, size~ : Int)
    } derive(
    Debug
    )

    Transport type for the external process bridge.

    ClockDomain

    pub(all) enum ClockDomain {
    Mcu
    Linux
    Fpga
    Virtual
    } derive(Eq,
    Debug
    )

    ClockDomain identifies the source of a timestamp.

    CoSimConfig

    pub(all) struct CoSimConfig {
    cycle_period_ns : Int64
    slave_count : Int
    output_size : Int
    input_size : Int
    } derive(Eq,
    Debug
    )

    CoSimConfig provides the adapter with the simulation parameters it needs.

    CycleTimingReport

    pub(all) struct CycleTimingReport {
    nominal_period_ns : Int64
    actual_period_ns : Int64
    jitter_ns : Int64
    domain : ClockDomain
    } derive(Eq,
    Debug
    )

    CycleTimingReport captures per-cycle timing quality metrics.

    DomainTimestamp

    pub(all) struct DomainTimestamp {
    domain : ClockDomain
    ns : Int64
    } derive(Eq,
    Debug
    )

    DomainTimestamp pairs a raw nanosecond value with its clock domain.

    DriftCompensationGains

    pub(all) struct DriftCompensationGains {
    kp_num : Int64
    kp_den : Int64
    ki_num : Int64
    ki_den : Int64
    } derive(Eq,
    Debug
    )

    PI controller gains for drift compensation.

    DriftCompensationGains::aggressive

    DriftCompensationGains::conservative

    DriftCompensationGains::default

    DriftCompensationReport

    pub(all) struct DriftCompensationReport {
    update_count : Int64
    last_error_ns : Int64
    integral_error_ns : Int64
    total_correction_ns : Int64
    estimated_drift_ppb : Int64
    converged : Bool
    } derive(
    Debug
    )

    DriftCompensationReport — diagnostic snapshot.

    DriftCompensator

    pub(all) struct DriftCompensator {
    gains : DriftCompensationGains
    target_offset_ns : Int64
    integral_error_ns : Int64
    last_error_ns : Int64
    total_correction_ns : Int64
    update_count : Int64
    max_integral_ns : Int64
    active : Bool
    } derive(
    Debug
    )

    DriftCompensator — online PI-based drift compensation state.

    DriftCompensator::compensate

    fn DriftCompensator::compensate(self : DriftCompensator, sync : TimebaseSync, reference_ns : Int64, local_ns : Int64) -> Int64

    Compute the correction for the current sync measurement and update the given TimebaseSync's offset.

    Returns the applied correction in nanoseconds.

    DriftCompensator::new

    fn DriftCompensator::new(gains? : DriftCompensationGains, target_offset_ns? : Int64, max_integral_ns? : Int64) -> DriftCompensator

    DriftCompensator::report

    Generate a diagnostic report of the current compensation state.

    DriftCompensator::reset

    fn DriftCompensator::reset(self : DriftCompensator) -> Unit

    Reset the compensator state (e.g., after a large discontinuity).

    ExternalBridgeConfig

    pub(all) struct ExternalBridgeConfig {
    transport : BridgeTransport
    step_timeout_ns : Int64
    auto_launch : Bool
    launch_command : String
    launch_cwd : String
    } derive(
    Debug
    )

    Configuration for the external process bridge.

    ExternalBridgeConfig::named_pipe

    fn ExternalBridgeConfig::named_pipe(name : String) -> ExternalBridgeConfig

    ExternalBridgeConfig::shared_memory

    fn ExternalBridgeConfig::shared_memory(name : String, size : Int) -> ExternalBridgeConfig

    ExternalBridgeConfig::unix_socket

    fn ExternalBridgeConfig::unix_socket(path : String) -> ExternalBridgeConfig

    ExternalProcessBridge

    pub(all) struct ExternalProcessBridge {
    config : ExternalBridgeConfig
    state : BridgeState
    output_size : Int
    input_size : Int
    step_count : Int64
    total_latency_ns : Int64
    } derive(
    Debug
    )

    ExternalProcessBridge — CoSimAdapter that delegates to an external process.

    This struct manages the connection lifecycle and serialization. Actual I/O operations are delegated to platform-specific extern "c" stubs.

    ExternalProcessBridge::avg_latency_ns

    fn ExternalProcessBridge::avg_latency_ns(self : ExternalProcessBridge) -> Int64

    Average round-trip latency in nanoseconds.

    ExternalProcessBridge::new

    LoopbackCoSimAdapter

    pub struct LoopbackCoSimAdapter {
    sim_time : SimTime
    }

    LoopbackCoSimAdapter — trivial adapter that copies outputs to inputs. Useful for communication-closed-loop testing without an external model.

    LoopbackCoSimAdapter::new

    MultiRateAnalysis

    pub(all) struct MultiRateAnalysis {
    hyperperiod : Int
    worst_case_tasks_per_cycle : Int
    peak_cycles : Array[Int]
    is_harmonic : Bool
    worst_case_output_bytes : Int
    worst_case_input_bytes : Int
    } derive(
    Debug
    )

    MultiRateAnalysis — result of analyzing a multi-rate schedule.

    ProcessImageSlice

    pub(all) struct ProcessImageSlice {
    output_offset : Int
    output_length : Int
    input_offset : Int
    input_length : Int
    } derive(Eq,
    Debug
    )

    ProcessImageSlice — an offset/length descriptor defining a task's region within the ProcessImage.

    Design rationale:
    • HIL and multi-axis systems need isolated access to subsets of the PI
    • Each task/controller owns one or more slices
    • Slices are bounded and checked at creation, not at every access
    • Maps directly to DMA descriptor regions on MCU targets

    Note: The copy-based helpers read_slice_inputs/write_slice_outputs operate on the immutable ProcessImage type and allocate on each call. For zero-allocation hot-path access use slice_inputs_view and write_slice_outputs_inplace, which operate on @hal.MutableProcessImage.

    Safety: offsets are validated at slice creation; subsequent access is bounds-checked by the underlying buffer API.

    SimStepResult

    pub(all) enum SimStepResult {
    Ok(SimTime)
    Terminated(String)
    Error(String)
    } derive(Eq,
    Debug
    )

    SimStepResult reports the outcome of one simulation step.

    SimTime

    pub(all) struct SimTime(Int64) derive(Compare, Eq,
    Debug
    )

    SimTime represents simulation time in nanoseconds since simulation start. Distinct from HAL Timestamp to decouple real-time from simulated time.

    SimTime::advance

    fn SimTime::advance(self : SimTime, delta_ns : Int64) -> SimTime

    SimTime::from_ns

    fn SimTime::from_ns(ns : Int64) -> SimTime

    SimTime::to_ns

    fn SimTime::to_ns(self : SimTime) -> Int64

    SimTime::zero

    fn SimTime::zero() -> SimTime

    TaskDescriptor

    pub(all) struct TaskDescriptor {
    name : String
    priority : Int
    cycle_divisor : Int
    slice : ProcessImageSlice
    } derive(Eq,
    Debug
    )

    TaskDescriptor identifies a logical task that owns one PI partition.

    Modeled after IEC 61131-3 task concept:
    • Each task has a unique name, a priority level, and a cycle divisor
    • The cycle divisor controls how often the task executes relative to the base EtherCAT cycle (divisor=1 → every cycle, divisor=4 → every 4th)
    • Priority determines execution order within a single base cycle

    TaskSchedule

    pub(all) struct TaskSchedule {
    base_period_ns : Int64
    tasks : Array[TaskDescriptor]
    } derive(Eq,
    Debug
    )

    TaskSchedule holds an ordered sequence of tasks, sorted by priority, with the base cycle period from the master configuration.

    TimebaseSync

    pub(all) struct TimebaseSync {
    reference_domain : ClockDomain
    local_domain : ClockDomain
    offset_ns : Int64
    drift_ppb : Int64
    sync_count : Int64
    last_sync_ns : Int64
    } derive(Eq,
    Debug
    )

    TimebaseSync captures the synchronization state between two clock domains.

    TimebaseSync::new

    fn TimebaseSync::new(reference_domain : ClockDomain, local_domain : ClockDomain) -> TimebaseSync

    TimebaseSync::to_local

    fn TimebaseSync::to_local(self : TimebaseSync, reference_ns : Int64) -> Int64

    Convert a reference-domain timestamp to the local domain.

    TimebaseSync::to_reference

    fn TimebaseSync::to_reference(self : TimebaseSync, local_ns : Int64) -> Int64

    Convert a local-domain timestamp to the reference domain.

    TimebaseSync::update

    fn TimebaseSync::update(self : TimebaseSync, reference_ns : Int64, local_ns : Int64) -> Unit

    Update the sync state with a new measurement pair.

    VirtualTimebase

    pub struct VirtualTimebase {
    current_ns : Int64
    }

    VirtualTimebase — deterministic timebase for testing and replay. Time only advances when explicitly stepped.

    VirtualTimebase::advance

    fn VirtualTimebase::advance(self : VirtualTimebase, delta_ns : Int64) -> Unit

    VirtualTimebase::new

    VirtualTimebase::set

    fn VirtualTimebase::set(self : VirtualTimebase, ns : Int64) -> Unit

    analyze_multi_rate

    fn analyze_multi_rate(schedule : TaskSchedule) -> MultiRateAnalysis

    Analyze a multi-rate TaskSchedule for worst-case behavior.

    build_task_schedule

    fn build_task_schedule(base_period_ns : Int64, tasks : Array[TaskDescriptor]) -> TaskSchedule?

    Build a TaskSchedule from task descriptors. Validates: no overlapping output PI regions, no overlapping input PI regions, positive divisors, unique names. Returns None if validation fails.

    cycle_timing_report

    fn cycle_timing_report(nominal_period_ns : Int64, prev_ns : Int64, curr_ns : Int64, domain : ClockDomain) -> CycleTimingReport

    Compute a CycleTimingReport from two consecutive timestamps.

    decode_step_response

    fn decode_step_response(data : Bytes, input_size : Int) -> (Byte, Bytes)

    Decode a step response from the wire protocol format.

    Format: [1B status][input_size B inputs][optional tail] Returns: (status_byte, input_data)

    encode_step_request

    fn encode_step_request(sim_time_ns : Int64, dt_ns : Int64, outputs : Bytes, output_size : Int) -> Bytes

    Encode a step request into the wire protocol format.

    Format: [8B sim_time_ns LE][8B dt_ns LE][output_size B outputs]

    partition_by_slave

    Partition a PdoContext into per-slave slices. Returns an array of (station_address, slice) pairs.

    read_slice_inputs

    Read input bytes for a slice from a ProcessImage.

    slice_from_mapping

    Create a ProcessImageSlice from a PdoMapping. Validates that the mapping fits within the given ProcessImage dimensions.

    slice_inputs_view

    fn slice_inputs_view(image :
    MutableProcessImage
    , slice : ProcessImageSlice) -> (FixedArray[Byte], Int, Int)

    Zero-copy read: returns the inputs buffer reference, offset, and length. The caller can index directly into buf at [offset..<offset+len] without any heap allocation.

    tasks_due_at_cycle

    fn tasks_due_at_cycle(schedule : TaskSchedule, cycle : Int64) -> Array[TaskDescriptor]

    validate_multi_rate

    fn validate_multi_rate(schedule : TaskSchedule, max_hyperperiod? : Int, max_tasks_per_cycle? : Int, max_io_bytes_per_cycle? : Int) -> Array[String]

    Validate that a multi-rate schedule is safe for real-time execution.

    Checks:
    1. All divisors > 0 (already enforced by build_task_schedule)
    2. Hyperperiod is bounded (≤ max_hyperperiod)
    3. No cycle exceeds max_tasks_per_cycle
    4. Total worst-case I/O fits within frame budget

    Returns a list of validation messages (empty = all OK).

    write_slice_outputs

    fn write_slice_outputs(image :
    ProcessImage
    , slice : ProcessImageSlice, data : Bytes) -> Unit

    Write output bytes for a slice into a ProcessImage.

    write_slice_outputs_inplace

    fn write_slice_outputs_inplace(image :
    MutableProcessImage
    , slice : ProcessImageSlice, src : FixedArray[Byte], src_offset : Int) -> Unit

    Zero-copy write: writes bytes from src[src_offset..] directly into the outputs buffer at the slice's output_offset. No new buffer is allocated; the update is performed in-place.