RustV2XSimulator: Developer & Agent Guide
This guide describes the architecture of rustv2xsimulator, how it integrates with rustflexstack, and how downstream research repositories (such as experiment testbenches and paper evaluation suites) should import, override, and collect custom metrics.
1. Architectural Philosophy
rustv2xsimulator is designed as a lean, unopinionated discrete-event simulation (DES) framework for vehicular communications (V2X). It provides the physics, medium access, mobility, and event scheduling environment, while relying on rustflexstack for the ETSI C-ITS protocol stack.
flowchart TD
subgraph Downstream ["Research Repository (e.g. set_of_tests)"]
custom_cam["Custom CA Basic Service / New CAM Standard"]
custom_metrics["Custom Metrics & Telemetry (PDR, Latency, CSV/JSON)"]
sim_runner["Experiment Runner / Scenarios"]
end
subgraph Sim ["RustV2XSimulator"]
direction LR
des["Discrete-Event Scheduler (Calendar Queue)"]
phy["Radio Medium (802.11p, Dual-Slope, Knife-Edge SINR)"]
mac["EDCA MAC (4 Access Categories, CSMA/CA Backoff)"]
dcc["Decentralized Congestion Control (Reactive / LIMERIC)"]
mobility["Mobility Engine (SUMO TraCI / Synthetic Platoon / Highway)"]
link_layer["SimulatorLinkLayer (Adapter)"]
pcap["PCAP Writer (EtherType 0x8947)"]
end
subgraph Stack ["RustFlexstack"]
geonet["GeoNetworking (SHB, GBC, Location Table)"]
btp["BTP Router (Port 2001 CAM, Port 2002 DENM)"]
facilities["CA Basic Service / DEN Service / LDM"]
security["ETSI TS 103 097 Security (PKI, Sign, Verify)"]
end
Downstream -->|Imports & configures| Sim
Downstream -->|Imports & can override| Stack
custom_cam -.->|Replaces/Wraps| facilities
custom_metrics -.->|Observes events / link-layer| Sim
Sim <-->|Bridges packets| Stack
Separation of Responsibilities
| Responsibility | Handled By | Description |
|---|---|---|
| Event Scheduling & Time | rustv2xsimulator::scheduler |
Deterministic, discrete-event calendar queue (SimTime in 100 ns ticks). |
| Wireless Channel & RF | rustv2xsimulator::phy |
Path loss (dual-slope), shadow fading, knife-edge diffraction, cumulative SINR. |
| Channel Access & Contention | rustv2xsimulator::mac |
IEEE 802.11p EDCA 4 Access Categories (AC_VO, AC_VI, AC_BE, AC_BK), CBR monitor. |
| Vehicular Mobility | rustv2xsimulator::mobility |
SUMO TraCI client, synthetic grid/highway/platoon generators, Krauß-safe actuation. |
| Packet Trace Capture | rustv2xsimulator::pcap |
High-speed libpcap export parseable directly in Wireshark (0x8947). |
| ETSI Protocol Layers | rustflexstack |
GeoNetworking (EN 302 636-4-1), BTP (EN 302 636-5-1), Facilities (TS 103 900), Security (TS 103 097). |
| Metrics & Research Logic | Downstream Repository | PDR curves, throughput, latency distributions, paper-specific metrics collectors. |
2. Downstream Repository Setup
When starting a new research experiment (e.g. testing a modified CAM standard or a custom congestion control mechanism), create a new Cargo workspace or package that imports both crates:
[dependencies]
# Simulator engine (DES, PHY, MAC, Mobility, PCAP)
rustv2xsimulator = { git = "https://github.com/Fundacio-i2CAT/RustV2XSimulator.git" }
# Note: Once published to crates.io, replace with:
# rustv2xsimulator = "0.1"
# ETSI C-ITS Protocol Stack (from crates.io)
rustflexstack = "0.3.4"
[!NOTE] Future Crates.io Release: Once
rustv2xsimulatoris officially published to crates.io, downstream research repositories will be able to reference the crate directly by version (e.g.,rustv2xsimulator = "0.1") rather than via the GitHub repository URL.
3. How to Override Components
Example A: Overriding the CA Basic Service (New CAM Standard)
Suppose you are designing a new CAM standard with an extended sensor container or an adaptive generation condition. In your downstream crate:
- Define your custom message struct and encoder (or extend
rustflexstack::facilities::ca_basic_service::Cam). - Implement your custom transmission logic:
use rustflexstack::btp::router::BTPRouterHandle;
use rustflexstack::btp::service_access_point::BTPDataRequest;
use rustflexstack::geonet::service_access_point::CommonNH;
use rustv2xsimulator::common::SimTime;
pub struct CustomCamService {
btp_handle: BTPRouterHandle,
station_id: u32,
last_gen_time: SimTime,
}
impl CustomCamService {
pub fn new(station_id: u32, btp_handle: BTPRouterHandle) -> Self {
Self {
btp_handle,
station_id,
last_gen_time: SimTime::ZERO,
}
}
/// Custom generation trigger: e.g. event-based or high-frequency sensor sharing
pub fn check_and_generate(&mut self, now: SimTime, payload: Vec<u8>) {
if now - self.last_gen_time >= SimTime::from_millis(100) {
self.last_gen_time = now;
// Form BTP-B packet targeting port 2001 (CAM)
let btp_req = BTPDataRequest {
btp_type: CommonNH::BtpB,
source_port: 0,
destination_port: 2001,
destination: None,
data: payload,
// ... standard transport parameters ...
};
self.btp_handle.send_btp_data_request(btp_req);
}
}
}
- Connect your custom service to
VehicleAgent'sbtp_handleinside your simulation loop.
Example B: Custom Metrics Collection
rustv2xsimulator leaves metrics collection entirely to downstream repositories. This ensures the simulator remains general, fast, and does not impose unnecessary allocations or opinionated storage formats (such as specific CSV schemas or Parquet tables).
Researchers can collect metrics using any of the following patterns:
Pattern 1: Stepping the Simulation Engine Directly
Instead of running engine.run()? monolithically, control the simulation step-by-step using engine.step():
use rustv2xsimulator::engine::{EngineConfig, SimulationEngine};
use rustv2xsimulator::geometry::polygon::BuildingMap;
use rustv2xsimulator::scheduler::EventPayload;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = EngineConfig::default();
let buildings = BuildingMap::default();
let mut engine = SimulationEngine::new(config, buildings)?;
let mut total_transmissions = 0u64;
let mut custom_pdr_collector = MyPdrCollector::new();
// Step through discrete events
while let Ok(Some(event)) = engine.step() {
match event.payload {
EventPayload::MacTxStart { sender_id, packet_id, .. } => {
total_transmissions += 1;
custom_pdr_collector.record_tx(event.timestamp, sender_id, packet_id);
}
EventPayload::PhyRxDelivery { receiver_id, sender_id, is_success, .. } => {
if is_success {
custom_pdr_collector.record_rx(event.timestamp, receiver_id, sender_id);
}
}
_ => {}
}
}
// Export custom metrics formatted specifically for your research paper
custom_pdr_collector.export_csv("my_paper_results.csv")?;
Ok(())
}
Pattern 2: Inspecting Generated Wireshark PCAPs
If enable_pcap: true is configured in EngineConfig:
rustv2xsimulatorgenerates a binary libpcap capture file atsimulation.pcap.- Downstream projects can analyze it offline using
pyshark,scapy,tshark, or custom Python/Rust packet dissecting scripts.
4. Running the Included Example
The repository includes a complete example simulating vehicles exchanging CAMs in a realistic SUMO scenario with 802.11p EDCA, DCC, and ETSI TS 103 097 security:
cargo run --release --example cam_simulation -- \
--num-vehicles 10 \
--scenario diagonal \
--scenario-dir scenarios/diagonal \
--duration 30.0 \
--generate-pcap
This generates:
results/cam_example/simulation.pcap: Packet capture with Ethernet II framing (0x8947), GeoNetworking headers, BTP-B, and ASN.1 UPER encoded CAMs.
To inspect with Wireshark:
5. Verification & Test Suite
Run the full suite of integration tests and conformance checks: