APIC – States development guide

Best Practices — CoreEngine Architecture & Developer guide

Overview

Scope: This guide covers CoreEngine (SimEngine) framework development — the native C++ that runs inside CoreEngine itself (models, states, streams, drivers). This is complete, ordinary C++ with no COM involved. A CoreEngine project already has a working entry point (a main() that calls CSimSetups::Start(...)) — development means adding to or modifying Models, States, Streams, and Drivers inside that existing project, not writing a new entry point. For the separate, optional DLL-based API used by external scripts to control an already-running CoreEngine instance, see the Scripts Interface reference instead.

The APIC Core Engine is a modular, state-driven simulation and execution framework designed to support complex system behavior, real-time data flows, and deterministic state machines. The engine separates generated ICD artifacts, developer-owned logic, configuration, and operator interfaces into well-defined layers.

This guide targets core engine developers and integrators. It assumes familiarity with C++, state-machine design, and real-time system constraints.
Building a new system from scratch? See How to Build an APIC System for Software Engineers for the full step-by-step workflow.

Core Architecture

The engine is organized around the following principles:

  • Strict separation between generated code and developer code
  • Explicit state ownership inside models
  • Configuration-driven wiring of streams and drivers
  • Deterministic startup and runtime behavior
Root
 ├── DBSim
 ├── interfaces
 │   ├── Drivers
 │   └── Streams
 ├── Models
 ├── OGI
 ├── Setups
 └── config.json
    

Folder Structure

Folder Responsibility
DBSim/ Auto-generated ICD C++ sources and headers
interfaces/ Container for the project's Drivers and Streams implementations
interfaces/Drivers/ Project-specific hardware or protocol drivers, one subfolder per driver (see Driver folder layout)
interfaces/Streams/ Logical data streams connecting blocks to drivers, one subfolder per stream
Models/ Logical system models implementing behavior and states
OGI/ Operator Graphical Interface logic and event handling
Setups/ System configuration, layouts, streams, and test data
Drivers and Streams moved under a shared interfaces/ folder. Stream implementations are unchanged — only their location moved. Drivers gained a new internal structure; see Driver folder layout.

Models & States Architecture

Each Model represents a logical subsystem or functional domain. A model may own one or more state machines controller. A state controller holds one or more States.
The model responsible for:

  • Internal state transitions in the states controllers
  • Processing of incoming streams
  • Generation and manipulating the LRUs blocks elements

States Organization

Within a model folder, a states/ directory may exist. This directory contains state controllers, each grouping related states.

Models/
 └── NavigationModel/
     ├── NavigationModel.cpp
     ├── NavigationModel.h
     └── states/
         ├── Alignment/
         │   ├── IdleState.cpp
         │   ├── AligningState.cpp
         │   └── AlignedState.cpp
         └── FaultHandling/
             ├── FaultState.cpp
             └── RecoveryState.cpp
    
A single state is the smallest logical execution unit. It should implement one clear, deterministic responsibility.

Drivers & Streams

Drivers implement the physical or protocol-level interface (e.g., bus, socket, file, or simulated I/O). Streams bind blocks or model endpoints to these drivers using configuration.

Streams Configuration

Streams are defined in streams.json and specify:

  • Source block or model output
  • Target driver
  • Direction and rate
  • Optional transformation or filtering
Key Rule: No hard-coded connections between models and drivers are allowed. All bindings must be configuration-driven.

Setups & Configuration

The Setups/ folder defines how the engine is instantiated for a specific system or project.

File Description
LRU-<project>.json LRUs, blocks, elements, layout, and properties
systemconfig.json Application-specific configuration
streams.json Stream-to-driver bindings

Tests Folder

An optional tests/ folder may exist under setups, containing CSV-based test vectors for:

  • Unit tests
  • Standard compliance tests
  • ATP (Acceptance Test Procedures)

OGI (Operator Graphical Interface)

The OGI layer implements the operator-facing application. It handles:

  • User interactions and commands
  • Visualization of system state
  • Translation of UI events into core engine actions
OGI must not implement business logic or state transitions. All logic belongs in models.

Sequence Diagrams

The following diagrams illustrate the runtime interaction between the Core Engine components. They focus on deterministic startup, stream execution, and state-machine behavior.

1. Application Startup Sequence

This diagram shows how the engine initializes configuration, models, drivers, and streams before entering real-time execution.

Main App Core Engine Models Drivers load config.json reset / init models reset / init streams & drivers load streams.json start realtime

2. Stream Execution Sequence

Streams provide configuration-driven data flow between models and drivers. No direct coupling exists at code level.

Model Stream Driver publish data forward (rate, direction) receive / status deliver to model

3. State Lifecycle Sequence

Each state is a deterministic unit with a clear lifecycle. Transitions are explicit and controlled by the owning model.

Model State Controller State reset / init create initial state set current state run execute return empty / next state stay or transition
States can perform transitions directly by return value in the execute function.

Best Practices

  • Keep generated code (DBSim) read-only
  • One responsibility per state
  • Explicit state transitions only
  • Configuration over hard-coded behavior
  • Fail fast on invalid configuration
Design Rule: If behavior changes between projects, it belongs in configuration. If behavior changes between modes, it belongs in states.