Skip to main content

agent_can/cli/
output.rs

1use crate::protocol::{MessageObservation, Response, ResponseData};
2
3pub fn print_response(response: &Response, json: bool) {
4    if json {
5        println!(
6            "{}",
7            serde_json::to_string_pretty(response).expect("response should serialize")
8        );
9        return;
10    }
11
12    if !response.success {
13        eprintln!(
14            "{}",
15            response
16                .error
17                .as_deref()
18                .unwrap_or("request failed without error payload")
19        );
20        return;
21    }
22
23    match response.data.as_ref() {
24        Some(ResponseData::AdaptersList { adapters }) => {
25            if adapters.is_empty() {
26                println!("no supported adapters available on this platform");
27            } else {
28                for adapter in adapters {
29                    println!("{adapter}");
30                }
31            }
32        }
33        Some(ResponseData::Connected(connect)) => {
34            println!(
35                "connected created={} already_connected={} adapter={} bitrate={} bitrate_data={} fd={} dbcs={}",
36                connect.created,
37                connect.already_connected,
38                connect.status.adapter,
39                connect.status.bitrate,
40                connect.status.bitrate_data.unwrap_or(0),
41                connect.status.fd,
42                connect.status.dbcs.len()
43            );
44        }
45        Some(ResponseData::Disconnected) => println!("disconnected"),
46        Some(ResponseData::Status(status)) => {
47            println!(
48                "state={} adapter={} bitrate={} bitrate_data={} fd={} dbcs={} trace={} schedules={} backend_error={}",
49                status.connection_state,
50                status.adapter,
51                status.bitrate,
52                status.bitrate_data.unwrap_or(0),
53                status.fd,
54                status.dbcs.len(),
55                status.trace_path.as_deref().unwrap_or("-"),
56                status.periodic_schedules.len(),
57                status.backend_error.as_deref().unwrap_or("-"),
58            );
59        }
60        Some(ResponseData::Schema { messages }) => {
61            for message in messages {
62                println!(
63                    "{} arb_id=0x{:X} len={} signals={}",
64                    message.qualified_name,
65                    message.arb_id,
66                    message.len,
67                    message.signals.len()
68                );
69            }
70        }
71        Some(ResponseData::MessageList { messages }) => {
72            for message in messages {
73                println!(
74                    "{} kind={:?} arb_id=0x{:X} rx={} tx={} last_seen_unix_ms={}",
75                    message.label,
76                    message.kind,
77                    message.arb_id,
78                    message.has_rx,
79                    message.has_tx,
80                    message.last_seen_unix_ms
81                );
82            }
83        }
84        Some(ResponseData::MessageRead(read)) => print_observations(&read.observations),
85        Some(ResponseData::MessageSent(sent)) => {
86            println!(
87                "sent target={} arb_id=0x{:X} len={} periodicity_ms={}",
88                sent.target,
89                sent.arb_id,
90                sent.len,
91                sent.periodicity_ms
92                    .map(|value| value.to_string())
93                    .unwrap_or_else(|| "-".to_string())
94            );
95        }
96        Some(ResponseData::MessageStopped { target, stopped }) => {
97            println!("stopped target={target} stopped={stopped}");
98        }
99        Some(ResponseData::TraceStarted { path }) => println!("trace started path={path}"),
100        Some(ResponseData::TraceStopped { path }) => {
101            println!("trace stopped path={}", path.as_deref().unwrap_or("-"));
102        }
103        None => println!("ok"),
104    }
105}
106
107fn print_observations(observations: &[MessageObservation]) {
108    for observation in observations {
109        match observation {
110            MessageObservation::Raw {
111                seq,
112                direction,
113                arb_id,
114                payload_hex,
115                ..
116            } => {
117                println!(
118                    "seq={seq} direction={direction:?} arb_id=0x{arb_id:X} data={payload_hex}"
119                );
120            }
121            MessageObservation::Semantic {
122                seq,
123                direction,
124                qualified_name,
125                payload_hex,
126                signals,
127                ..
128            } => {
129                let signal_summary = signals
130                    .iter()
131                    .map(|signal| match &signal.unit {
132                        Some(unit) => format!("{}={} {}", signal.name, signal.value, unit),
133                        None => format!("{}={}", signal.name, signal.value),
134                    })
135                    .collect::<Vec<_>>()
136                    .join(", ");
137                println!(
138                    "seq={seq} direction={direction:?} message={qualified_name} data={payload_hex} signals={signal_summary}"
139                );
140            }
141        }
142    }
143}