use phoxal_macros::phoxal_api_tree;
pub trait ApiVersion: 'static {
const ID: &'static str;
}
pub trait ContractBody:
serde::Serialize + serde::de::DeserializeOwned + Clone + Send + Sync + 'static
{
type Api: ApiVersion;
const FAMILY: &'static str;
const TOPIC: &'static str;
}
phoxal_api_tree! {
version y2026_1 {
drive {
enum StopReason {
NoTarget,
EmergencyStop,
Fault,
}
enum ActuatorAuthority {
Active,
Stopped,
}
struct Target {
linear_x_mps: f32,
angular_z_radps: f32,
}
struct State {
target: Target,
limited_target: Target,
actuator_authority: ActuatorAuthority,
stop_reason: Option<StopReason>,
}
topic target: pubsub Target;
topic state: pubsub State;
}
motor {
enum Command {
Velocity(f32),
Torque(f32),
Stop,
}
topic command: pubsub Command;
}
component {
enum MotorCommand {
Velocity(f32),
Torque(f32),
Stop,
}
struct EncoderSample {
position_rad: f64,
velocity_radps: f32,
}
topic motor_command(instance, capability): pubsub MotorCommand
= "component/{instance}/motor/{capability}/command";
topic encoder_sample(instance, capability): pubsub EncoderSample
= "component/{instance}/encoder/{capability}/sample";
}
odometry {
struct State {
x_m: f64,
y_m: f64,
yaw_rad: f64,
linear_x_mps: f32,
angular_z_radps: f32,
}
topic state: pubsub State;
}
localize {
struct LocalizationState {
x_m: f64,
y_m: f64,
yaw_rad: f64,
confidence: f32,
}
topic state: pubsub LocalizationState;
}
presence {
enum Readiness {
NotStarted,
Initializing,
Ready,
Degraded,
Failed,
}
struct Heartbeat {
participant: String,
readiness: Readiness,
}
topic heartbeat: pubsub Heartbeat;
}
map {
struct Revision {
revision: u64,
resolution_m: f32,
}
struct SubmapRequest {
min_x_m: f64,
min_y_m: f64,
max_x_m: f64,
max_y_m: f64,
}
struct SubmapResponse {
width: u32,
height: u32,
resolution_m: f32,
cells: Vec<u8>,
}
topic revision: pubsub Revision;
topic submap: query SubmapRequest => SubmapResponse;
}
asset {
struct GetRequest {
path: String,
}
enum GetResponse {
Found { bytes: Vec<u8> },
Missing,
InvalidPath,
}
topic get: query GetRequest => GetResponse;
}
}
version y2026_2 extends y2026_1 {
drive {
struct Target {
linear_x_mps: f32,
angular_z_radps: f32,
curvature_limit_radpm: Option<f32>,
}
topic target: pubsub Target;
}
battery {
struct State {
voltage_v: f32,
current_a: f32,
charge_ratio: f32,
}
topic state: pubsub State;
}
safety {
enum Level {
Nominal,
Warning,
EmergencyStop,
}
enum Concern {
BatteryLow,
BatteryCritical,
DriveFault,
}
struct Status {
level: Level,
concerns: Vec<Concern>,
}
topic state: pubsub Status;
}
}
}
#[cfg(test)]
mod tests;