use phoxal_macros::phoxal_api_tree;
pub use phoxal_bus::{ApiVersion, ContractBody};
phoxal_api_tree! {
version v0_1 {
drive {
enum StopReason {
TargetStale,
TargetNotFinite,
ActuatorCommandNotFinite,
Inactive,
EmergencyStop,
Fault,
}
enum ActuatorAuthority {
Active,
Stopped,
}
struct Target {
linear_x_mps: f32,
angular_z_radps: f32,
curvature_limit_radpm: Option<f32>,
}
struct State {
target: Target,
limited_target: Target,
actuator_authority: ActuatorAuthority,
stop_reason: Option<StopReason>,
}
topic target: command Target;
topic state: state State;
}
joint(joint) {
struct JointState {
position_rad: f64,
velocity_radps: f64,
effort_nm: Option<f64>,
}
topic state: state JointState;
}
frame {
struct FrameTransform {
parent_frame_id: String,
child_frame_id: String,
translation_m: [f64; 3],
rotation_quat_xyzw: [f64; 4],
stamp: Option<::phoxal_bus::RobotInstant>,
}
struct StaticTransforms {
transforms: Vec<FrameTransform>,
}
struct Tree {
transforms: Vec<FrameTransform>,
}
struct LookupRequest {
target_frame_id: String,
source_frame_id: String,
at: Option<::phoxal_bus::RobotInstant>,
}
struct LookupResponse {
transform: Option<FrameTransform>,
}
topic tree: state Tree;
topic static_transforms: state StaticTransforms;
topic lookup: query LookupRequest => LookupResponse;
}
power {
#[derive(Copy, Eq)]
enum Command {
Reboot,
Shutdown,
}
#[derive(Copy, Eq)]
enum Status {
Idle,
Rebooting,
ShuttingDown,
Failed,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum RejectedReason {
HostIntegrationUnavailable,
CommandRejected,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum FailedReason {
HostCommandFailed,
}
struct State {
status: Status,
detail: Option<String>,
}
topic command: command Command;
topic state: state State;
}
motion {
struct Target {
linear_x_mps: f32,
angular_z_radps: f32,
curvature_limit_radpm: Option<f32>,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum Source {
Manual,
Navigation,
EmergencyStop,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum ZeroReason {
NoCandidate,
NavigationCandidateStale,
ManualCandidateNotFinite,
NavigationCandidateNotFinite,
EmergencyStopEngaged,
SafetyConstraintsUnavailable,
SafetyProtectiveStop,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum SafetyRuntime {
Absent,
Present,
}
struct ManualCommand {
linear_x_mps: f64,
angular_z_radps: f64,
}
struct State {
manual_observed_age_ns: Option<u64>,
autonomous_candidate_age_ns: Option<u64>,
safety_constraints_age_ns: Option<u64>,
selected_source: Option<Source>,
final_target: Target,
zero_reason: Option<ZeroReason>,
safety_runtime: SafetyRuntime,
component_estop_blocked: bool,
active_safety_constraints: Vec<super::safety::Constraint>,
}
topic manual: command ManualCommand;
topic state: state State;
}
safety {
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum ConstraintReason {
WorldUnavailable,
MapUnavailable,
DrivableSpaceUnavailable,
LocalizationUnavailable,
LocalizationUncertain,
ObstacleProximity,
RangeSensorFault,
DriveFault,
BatteryLow,
BatteryCritical,
SpeedZone,
OperatorPolicy,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum ConstraintSourceKind {
WorldModel,
Map,
Localization,
Range,
Drive,
Battery,
Operator,
}
struct ConstraintSource {
kind: ConstraintSourceKind,
participant_id: String,
component_id: Option<String>,
capability_id: Option<String>,
}
struct Constraint {
reason: ConstraintReason,
source: ConstraintSource,
stop: bool,
max_linear_speed_mps: Option<f32>,
max_angular_speed_radps: Option<f32>,
observed_value: Option<f32>,
valid_from: ::phoxal_bus::RobotInstant,
expires_at: ::phoxal_bus::RobotInstant,
}
struct MotionConstraints {
sequence: u64,
stop: bool,
max_linear_speed_mps: Option<f32>,
max_angular_speed_radps: Option<f32>,
constraints: Vec<Constraint>,
expires_at: ::phoxal_bus::RobotInstant,
}
struct State {
clear: bool,
motion: MotionConstraints,
}
topic constraints: state MotionConstraints;
topic state: state State;
}
navigation {
#[derive(Eq)]
struct RequestId {
value: String,
}
struct Pose {
x_m: f64,
y_m: f64,
yaw_rad: Option<f64>,
}
struct Path {
poses: Vec<Pose>,
map_revision: Option<u64>,
}
enum RequestKind {
GotoPose(Pose),
FollowPath(Path),
Cancel(RequestId),
}
struct Request {
request_id: RequestId,
kind: RequestKind,
}
enum State {
Idle,
Accepted(RequestId),
Running(RequestId),
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum FailureReason {
LocalizationUnavailable,
MapUnavailable,
MapChanged,
NoPath,
Blocked,
Internal,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum RefusalReason {
Busy,
InvalidRequest,
Unsupported,
}
enum Outcome {
Succeeded,
Failed(FailureReason),
Refused(RefusalReason),
Cancelled,
TimedOut,
}
struct Progress {
request_id: RequestId,
distance_remaining_m: f64,
path_index: u32,
}
struct Result {
request_id: RequestId,
outcome: Outcome,
}
struct Candidate {
request_id: RequestId,
linear_x_mps: f32,
angular_z_radps: f32,
}
struct FrontierRequest {
map_revision: Option<u64>,
}
struct Frontier {
x_m: f64,
y_m: f64,
score: f32,
size: u32,
}
struct FrontierResponse {
frontier: Option<Frontier>,
map_revision: Option<u64>,
}
topic request: command Request;
topic state: state State;
topic progress: state Progress;
topic result: state Result;
topic candidate: state Candidate;
topic next_frontier: query FrontierRequest => FrontierResponse;
}
behavior {
#[derive(Eq)]
struct RequestId {
value: String,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum ConflictPolicy {
Reject,
Queue,
Interrupt,
}
enum Value {
Bool(bool),
Integer(i64),
Number(f64),
String(String),
Pose(super::navigation::Pose),
}
struct Request {
request_id: RequestId,
behavior_id: String,
args: ::std::collections::BTreeMap<String, Value>,
priority: u8,
conflict_policy: ConflictPolicy,
}
enum Command {
Pause,
Resume,
Cancel,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum ExecutionStatus {
Idle,
Running,
Paused,
Succeeded,
Failed,
Cancelled,
Abandoned,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum NodeStatus {
Idle,
Running,
Succeeded,
Failed,
Skipped,
Waiting,
Cancelling,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum FailureReason {
MissingCapability,
ActionRefused,
ActionFailed,
ActionTimedOut,
ActionCancelled,
ConditionFailed,
SafetyStopped,
EmergencyStopped,
ResourceConflict,
InvalidArgument,
InvalidBlackboardValue,
SubtreeFailed,
ExecutionAbandoned,
InternalError,
}
struct Failure {
reason: FailureReason,
detail: Option<String>,
node_path: Option<String>,
action_id: Option<String>,
}
struct DefinitionRef {
id: String,
version: String,
content_hash: String,
}
struct State {
execution_id: Option<String>,
root_behavior_id: Option<String>,
active_request_id: Option<RequestId>,
active_behavior_id: Option<String>,
status: ExecutionStatus,
active_node_path: Option<String>,
failure: Option<Failure>,
}
struct Snapshot {
execution_id: Option<String>,
root: Option<DefinitionRef>,
definition_stack: Vec<DefinitionRef>,
active_request_id: Option<RequestId>,
active_behavior_id: Option<String>,
status: ExecutionStatus,
node_statuses: ::std::collections::BTreeMap<String, NodeStatus>,
active_node_path: Option<String>,
blackboard: ::std::collections::BTreeMap<String, Value>,
args: ::std::collections::BTreeMap<String, Value>,
started_at: Option<::phoxal_bus::RobotInstant>,
failure: Option<Failure>,
}
enum EventKind {
ExecutionStarted,
ExecutionPaused,
ExecutionResumed,
ExecutionCompleted,
ExecutionCancelled,
ExecutionAbandoned,
NodeTransition(NodeStatus),
RequestAccepted,
RequestCompleted(ExecutionStatus),
RequestRejected(FailureReason),
}
struct Event {
sequence: u64,
execution_id: Option<String>,
request_id: Option<RequestId>,
behavior_id: Option<String>,
content_hash: Option<String>,
node_path: Option<String>,
kind: EventKind,
failure: Option<Failure>,
participant_id: String,
}
topic command: command Command;
topic request: command Request;
topic state: state State;
topic snapshot: state Snapshot;
topic event: state Event;
}
logs(participant_id) {
struct Timestamp {
unix_seconds: i64,
nanos: u32,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum Level {
Error,
Warn,
Info,
Debug,
Trace,
}
#[serde(untagged)]
enum LogValue {
Bool(bool),
I64(i64),
U64(u64),
F64(f64),
String(String),
}
struct Event {
seq: u64,
time: Timestamp,
level: Level,
target: String,
message: String,
fields: ::std::collections::BTreeMap<String, LogValue>,
dropped: u32,
#[serde(default)]
truncated: u32,
}
topic self: diagnostic Event;
}
tool {
#[derive(Eq)]
struct Cursor {
generation: String,
sequence: u64,
}
#[derive(Copy, Eq, Ord, PartialOrd)]
#[serde(rename_all = "snake_case")]
enum RuntimeDirection {
Publish,
Subscribe,
Mixed,
}
#[derive(Copy, Eq, Ord, PartialOrd)]
#[serde(rename_all = "snake_case")]
enum RuntimeBufferKind {
Outbound,
Latest,
Subscriber,
Mixed,
}
struct RuntimeStep {
target_period_ns: u64,
completed: u64,
errors: u64,
mean_duration_ns: u64,
max_duration_ns: u64,
mean_lateness_ns: u64,
max_lateness_ns: u64,
missed_ticks: u64,
overruns: u64,
}
struct RuntimeTopic {
topic: String,
direction: RuntimeDirection,
buffer_kind: RuntimeBufferKind,
count: u64,
rate_hz: f32,
drops: u64,
latest_overwrites: u64,
bounded_evictions: u64,
capacity: u64,
current_depth: u64,
high_water_depth: u64,
decode_errors: u64,
timeline_filtered: u64,
overflowed_rows: u32,
}
log {
struct SnapshotRequest {}
struct Timestamp {
unix_seconds: i64,
nanos: u32,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum Level {
Error,
Warn,
Info,
Debug,
Trace,
}
#[serde(untagged)]
enum LogValue {
Bool(bool),
I64(i64),
U64(u64),
F64(f64),
String(String),
}
struct Record {
sequence: u64,
participant_id: String,
source_sequence: u64,
time: Timestamp,
level: Level,
target: String,
message: String,
fields: ::std::collections::BTreeMap<String, LogValue>,
dropped: u32,
truncated: u32,
}
struct Snapshot {
cursor: crate::v0_1::tool::Cursor,
ingest_dropped: u64,
records: Vec<Record>,
}
struct Follow {
cursor: crate::v0_1::tool::Cursor,
ingest_dropped: u64,
record: Record,
}
topic snapshot: query SnapshotRequest => Snapshot;
topic follow: diagnostic Follow;
}
bus {
struct SnapshotRequest {}
struct TopicMetric {
topic: String,
from_participant: String,
ingress_rate_hz: f32,
count: u64,
}
struct Window {
sequence: u64,
topics: Vec<TopicMetric>,
throughput_msg_s: f32,
window_ns: u64,
}
struct Snapshot {
cursor: crate::v0_1::tool::Cursor,
current: Option<Window>,
windows: Vec<Window>,
}
struct Follow {
cursor: crate::v0_1::tool::Cursor,
window: Window,
}
topic snapshot: query SnapshotRequest => Snapshot;
topic follow: diagnostic Follow;
}
device {
struct Disk {
mount_point: String,
file_system: String,
used_bytes: u64,
total_bytes: u64,
}
struct Sample {
cpu_pct: Option<f32>,
ram_used_bytes: Option<u64>,
ram_total_bytes: Option<u64>,
swap_used_bytes: Option<u64>,
swap_total_bytes: Option<u64>,
load_1m: Option<f32>,
load_5m: Option<f32>,
load_15m: Option<f32>,
uptime_s: Option<u64>,
disks: Option<Vec<Disk>>,
window_ns: u64,
}
struct SnapshotRequest {
limit: u32,
before_sequence: Option<u64>,
}
struct Record {
sequence: u64,
sample: Sample,
truncated: u32,
}
struct Snapshot {
cursor: crate::v0_1::tool::Cursor,
records: Vec<Record>,
capacity_evictions: u64,
next_before_sequence: Option<u64>,
}
struct Follow {
cursor: crate::v0_1::tool::Cursor,
record: Record,
}
topic sample: diagnostic Sample;
topic snapshot: query SnapshotRequest => Snapshot;
topic follow: diagnostic Follow;
}
runtime {
struct Rollup {
window_ns: u64,
step: Option<crate::v0_1::tool::RuntimeStep>,
topics: Vec<crate::v0_1::tool::RuntimeTopic>,
overflow: Option<crate::v0_1::tool::RuntimeTopic>,
}
struct SnapshotRequest {
participant_id: Option<String>,
limit: u32,
before_sequence: Option<u64>,
}
struct Record {
sequence: u64,
participant_id: String,
truncated: u32,
window_ns: u64,
step: Option<crate::v0_1::tool::RuntimeStep>,
topics: Vec<crate::v0_1::tool::RuntimeTopic>,
overflow: Option<crate::v0_1::tool::RuntimeTopic>,
}
struct Snapshot {
cursor: crate::v0_1::tool::Cursor,
records: Vec<Record>,
capacity_evictions: u64,
next_before_sequence: Option<u64>,
}
struct Follow {
cursor: crate::v0_1::tool::Cursor,
record: Record,
}
topic rollup: diagnostic Rollup;
topic snapshot: query SnapshotRequest => Snapshot;
topic follow: diagnostic Follow;
}
}
bus {
uplink {
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum UplinkPhase {
Disabled,
Connecting,
Connected,
Retrying,
}
struct State {
phase: UplinkPhase,
connect: Option<String>,
retry_attempt: u32,
detail: Option<String>,
}
topic state: diagnostic State;
}
}
perception {
struct Detection {
class_id: String,
confidence: f32,
position_m: [f64; 3],
frame_id: String,
track_id: Option<u64>,
}
struct Detections {
detections: Vec<Detection>,
stamp: Option<::phoxal_bus::RobotInstant>,
}
struct State {
healthy: bool,
detector: String,
}
topic detections: state Detections;
topic state: state State;
}
video {
struct OpenRequest {
capability: String,
width_px: Option<u32>,
height_px: Option<u32>,
}
struct OpenResponse {
stream_id: String,
}
topic open: query OpenRequest => OpenResponse;
stream(stream) {
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum StreamPhase {
Starting,
Active,
Stopped,
}
struct StreamState {
phase: StreamPhase,
frames_seen: u64,
}
topic state: state StreamState;
}
}
simulation {
struct Clock {
step: u64,
}
topic clock: state Clock;
}
component(instance) {
motor(capability) {
enum Command {
Velocity(f32),
Torque(f32),
Stop,
}
topic command: command Command;
}
encoder(capability) {
struct Sample {
position_rad: f64,
velocity_radps: f32,
}
topic sample: measurement Sample;
}
accelerometer(capability) {
struct Sample {
linear_acceleration: [f32; 3],
}
topic sample: measurement Sample;
}
gyroscope(capability) {
struct Sample {
angular_velocity: [f32; 3],
}
topic sample: measurement Sample;
}
magnetometer(capability) {
struct Sample {
magnetic_field: [f32; 3],
}
topic sample: measurement Sample;
}
imu(capability) {
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum SensorHealth {
Nominal,
Degraded,
Fault,
}
#[derive(Copy)]
struct Bias {
angular_velocity_radps: [f32; 3],
linear_acceleration_mps2: [f32; 3],
}
struct Sample {
orientation: Option<[f32; 4]>,
angular_velocity_radps: [f32; 3],
linear_acceleration_mps2: [f32; 3],
covariance: Option<[f32; 9]>,
noise_density: Option<[f32; 3]>,
sensor_frame_id: Option<String>,
health: SensorHealth,
bias: Option<Bias>,
}
topic sample: measurement Sample;
}
range(capability) {
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum SensorHealth {
Nominal,
Degraded,
Fault,
}
#[derive(Copy)]
struct Limits {
min_m: f32,
max_m: f32,
}
#[derive(Copy)]
struct SampleQuality {
valid: bool,
confidence: Option<f32>,
}
struct Sample {
distance_m: f32,
limits: Option<Limits>,
quality: Option<SampleQuality>,
health: SensorHealth,
}
topic sample: measurement Sample;
}
gnss(capability) {
struct Sample {
latitude: f64,
longitude: f64,
altitude: f64,
position_covariance: [f64; 9],
}
topic sample: measurement Sample;
}
camera(capability) {
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum Encoding {
Jpeg,
Png,
L8,
Rgb8,
Rgba8,
}
#[derive(Copy)]
struct Intrinsics {
fx: f32,
fy: f32,
cx: f32,
cy: f32,
}
struct Distortion {
model: String,
coefficients: Vec<f32>,
}
#[derive(Copy)]
struct ExposureTiming {
exposure_start_ns: Option<u64>,
exposure_duration_ns: Option<u64>,
}
struct CalibrationIdentity {
id: String,
version: String,
}
struct Frame {
width: u32,
height: u32,
encoding: Encoding,
intrinsics: Option<Intrinsics>,
distortion: Option<Distortion>,
exposure: Option<ExposureTiming>,
calibration: Option<CalibrationIdentity>,
#[serde(with = "serde_bytes")]
data: Vec<u8>,
}
topic frame: measurement Frame;
}
depth(capability) {
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum Encoding {
U16Millimeters,
}
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum InvalidSamplePolicy {
ZeroIsInvalid,
NonFiniteIsInvalid,
}
#[derive(Copy)]
struct Intrinsics {
fx: f32,
fy: f32,
cx: f32,
cy: f32,
}
struct Distortion {
model: String,
coefficients: Vec<f32>,
}
#[derive(Copy)]
struct ExposureTiming {
exposure_start_ns: Option<u64>,
exposure_duration_ns: Option<u64>,
}
struct CalibrationIdentity {
id: String,
version: String,
}
struct Frame {
samples_mm: Vec<u16>,
encoding: Encoding,
invalid_sample_policy: InvalidSamplePolicy,
width: Option<u32>,
height: Option<u32>,
intrinsics: Option<Intrinsics>,
distortion: Option<Distortion>,
exposure: Option<ExposureTiming>,
calibration: Option<CalibrationIdentity>,
}
topic frame: measurement Frame;
}
lidar(capability) {
#[derive(Copy, Eq)]
#[serde(rename_all = "snake_case")]
enum SensorHealth {
Nominal,
Degraded,
Fault,
}
#[derive(Copy)]
struct ScanGeometry {
angle_min_rad: f32,
angle_increment_rad: f32,
}
#[derive(Copy)]
struct RangeLimits {
min_m: f32,
max_m: f32,
}
#[derive(Copy)]
struct ScanQuality {
valid_points: u32,
}
struct Ranges {
ranges: Vec<f32>,
geometry: Option<ScanGeometry>,
limits: Option<RangeLimits>,
quality: Option<ScanQuality>,
health: SensorHealth,
}
struct Points {
points: Vec<[f32; 3]>,
limits: Option<RangeLimits>,
quality: Option<ScanQuality>,
health: SensorHealth,
}
#[serde(tag = "kind", rename_all = "snake_case")]
enum Scan {
Ranges(Ranges),
Points(Points),
}
topic scan: measurement Scan;
}
mmwave(capability) {
#[derive(Copy)]
struct Detection {
position: [f32; 3],
velocity: [f32; 3],
snr: f32,
}
struct Scan {
detections: Vec<Detection>,
}
topic scan: measurement Scan;
}
microphone(capability) {
struct Frame {
data: Vec<u8>,
}
topic frame: measurement Frame;
}
led(capability) {
#[derive(Copy, Eq)]
enum Command {
On,
Off,
}
topic command: command Command;
}
emergency_stop(capability) {
#[derive(Eq)]
struct State {
engaged: bool,
}
topic state: state State;
}
}
odometry {
struct State {
x_m: f64,
y_m: f64,
yaw_rad: f64,
linear_x_mps: f32,
angular_z_radps: f32,
}
topic state: state State;
}
localize {
struct LocalizationState {
x_m: f64,
y_m: f64,
yaw_rad: f64,
confidence: f32,
}
topic state: state LocalizationState;
}
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: state Revision;
topic submap: query SubmapRequest => SubmapResponse;
}
asset {
struct GetRequest {
path: String,
}
enum GetResponse {
Found { bytes: Vec<u8> },
Missing,
InvalidPath,
}
topic get: query GetRequest => GetResponse;
}
battery {
struct State {
voltage_v: f32,
current_a: f32,
charge_ratio: f32,
}
topic state: state State;
}
joypad {
enum DeviceStatus {
Ready,
Disconnected,
Unsupported,
}
struct Device {
id: String,
name: String,
status: DeviceStatus,
}
struct Devices {
available: Vec<Device>,
selected: Option<String>,
enabled: bool,
unavailable_reason: Option<String>,
last_error: Option<String>,
}
struct Select {
id: String,
}
struct SetEnabled {
enabled: bool,
}
struct Rescan {}
topic devices: diagnostic Devices;
topic select: command Select;
topic set_enabled: command SetEnabled;
topic rescan: command Rescan;
}
}
latest v0_1;
}
#[cfg(test)]
mod tests;