Skip to content

Commit 099d914

Browse files
committed
Improve DTX command line output
1 parent 4da45e2 commit 099d914

File tree

4 files changed

+272
-13
lines changed

4 files changed

+272
-13
lines changed

Cargo.lock

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ nix = "0.20.0"
1818
thiserror = "1.0.24"
1919
anyhow = "1.0.38"
2020
smallvec = "1.6.1"
21+
serde = "1.0.124"
22+
serde_json = "1.0.64"
2123

2224
[build-dependencies]
2325
clap = "2.33.3"
@@ -26,6 +28,8 @@ nix = "0.20.0"
2628
thiserror = "1.0.24"
2729
anyhow = "1.0.38"
2830
smallvec = "1.6.1"
31+
serde = "1.0.124"
32+
serde_json = "1.0.64"
2933

3034
[profile.release]
3135
lto = true

src/cli/dtx.rs

Lines changed: 235 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,15 @@ impl Command {
152152
.context("Failed to get base info")?;
153153

154154
if !m.is_present("quiet") {
155-
println!("State: {}", info.state);
156-
println!("Device-Type: {}", info.device_type);
157-
println!("ID: {:#04x}", info.id);
158-
159-
} else if let sys::dtx::DeviceType::Unknown(ty) = info.device_type {
160-
println!("{{ \"state\": \"{}\", \"type\": {}, \"id\": {} }}",
161-
info.state, ty, info.id);
155+
println!("State: {}", info.state);
156+
println!("Type: {}", info.device_type);
157+
println!("ID: {:#04x}", info.id);
162158

163159
} else {
164-
println!("{{ \"state\": \"{}\", \"type\": \"{}\", \"id\": {} }}",
165-
info.state, info.device_type, info.id);
160+
let text = serde_json::to_string(&PrettyBaseInfo(info))
161+
.context("Failed to serialize data")?;
162+
163+
println!("{}", text);
166164
}
167165

168166
Ok(())
@@ -198,21 +196,247 @@ impl Command {
198196
Ok(())
199197
}
200198

201-
fn monitor(&self, _m: &clap::ArgMatches) -> Result<()> {
199+
fn monitor(&self, m: &clap::ArgMatches) -> Result<()> {
202200
let mut device = sys::dtx::Device::open()
203201
.context("Failed to open DTX device")?;
204202

205203
let events = device.events()
206204
.context("Failed to set up event stream")?;
207205

206+
let quiet = m.is_present("quiet");
207+
208208
for event in events {
209209
let event = event
210210
.map_err(|source| sys::Error::IoError { source })
211211
.context("Error reading event")?;
212212

213-
println!("{:?}", event);
213+
if !quiet {
214+
println!("{}", PrettyEvent(event));
215+
216+
} else {
217+
let text = serde_json::to_string(&PrettyEvent(event))
218+
.context("Failed to serialize data")?;
219+
220+
println!("{}", text);
221+
}
214222
}
215223

216224
Ok(())
217225
}
218226
}
227+
228+
229+
struct PrettyBaseInfo(sys::dtx::BaseInfo);
230+
231+
impl serde::Serialize for PrettyBaseInfo {
232+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
233+
where
234+
S: serde::Serializer
235+
{
236+
use serde::ser::SerializeStruct;
237+
238+
let mut s = serializer.serialize_struct("BaseInfo", 3)?;
239+
240+
match self.0.state {
241+
sys::dtx::BaseState::Attached => s.serialize_field("state", "attached"),
242+
sys::dtx::BaseState::Detached => s.serialize_field("state", "detached"),
243+
sys::dtx::BaseState::NotFeasible => s.serialize_field("state", "not-feasible"),
244+
}?;
245+
246+
match self.0.device_type {
247+
sys::dtx::DeviceType::Hid => s.serialize_field("type", "hid"),
248+
sys::dtx::DeviceType::Ssh => s.serialize_field("type", "ssh"),
249+
sys::dtx::DeviceType::Unknown(x) => s.serialize_field("type", &x),
250+
}?;
251+
252+
s.serialize_field("id", &self.0.id)?;
253+
s.end()
254+
}
255+
}
256+
257+
258+
struct PrettyEvent(sys::dtx::Event);
259+
260+
impl serde::Serialize for PrettyEvent {
261+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
262+
where
263+
S: serde::Serializer
264+
{
265+
use serde::ser::SerializeStruct;
266+
use sys::dtx::{DeviceType, Event, HardwareError, RuntimeError, uapi};
267+
use sys::dtx::event::{BaseState, CancelReason, DeviceMode, LatchStatus};
268+
269+
match &self.0 {
270+
Event::Request => {
271+
let mut s = serializer.serialize_struct("Event", 1)?;
272+
s.serialize_field("type", "request")?;
273+
s.end()
274+
},
275+
276+
Event::Cancel { reason } => {
277+
let mut s = serializer.serialize_struct("Event", 2)?;
278+
s.serialize_field("type", "cancel")?;
279+
280+
match reason {
281+
CancelReason::Hardware(err) => match err {
282+
HardwareError::FailedToOpen => s.serialize_field("reason", "failed-to-open"),
283+
HardwareError::FailedToRemainOpen => s.serialize_field("reason", "failed-to-remain-open"),
284+
HardwareError::FailedToClose => s.serialize_field("reason", "failed-to-close"),
285+
HardwareError::Unknown(x) => {
286+
s.serialize_field("reason", &(*x as u16 | uapi::SDTX_CATEGORY_HARDWARE_ERROR))
287+
},
288+
},
289+
CancelReason::Runtime(err) => match err {
290+
RuntimeError::NotFeasible => s.serialize_field("reason", "not-feasible"),
291+
RuntimeError::Timeout => s.serialize_field("reason", "timeout"),
292+
RuntimeError::Unknown(x) => {
293+
s.serialize_field("reason", &(*x as u16 | uapi::SDTX_CATEGORY_RUNTIME_ERROR))
294+
},
295+
},
296+
CancelReason::Unknown(x) => s.serialize_field("reason", x),
297+
}?;
298+
299+
s.end()
300+
},
301+
302+
Event::BaseConnection { state, device_type, id } => {
303+
let mut s = serializer.serialize_struct("Event", 4)?;
304+
s.serialize_field("type", "base-connection")?;
305+
306+
match state {
307+
BaseState::Attached => s.serialize_field("state", "attached"),
308+
BaseState::Detached => s.serialize_field("state", "detached"),
309+
BaseState::NotFeasible => s.serialize_field("state", "not-feasible"),
310+
BaseState::Unknown(x) => s.serialize_field("state", x),
311+
}?;
312+
313+
match device_type {
314+
DeviceType::Hid => s.serialize_field("device-type", "hid"),
315+
DeviceType::Ssh => s.serialize_field("device-type", "ssh"),
316+
DeviceType::Unknown(x) => s.serialize_field("device-type", &x),
317+
}?;
318+
319+
s.serialize_field("id", id)?;
320+
s.end()
321+
},
322+
323+
Event::LatchStatus { status } => {
324+
let mut s = serializer.serialize_struct("Event", 2)?;
325+
s.serialize_field("type", "latch-status")?;
326+
327+
match status {
328+
LatchStatus::Closed => s.serialize_field("status", "closed"),
329+
LatchStatus::Opened => s.serialize_field("status", "opened"),
330+
LatchStatus::Error(err) => match err {
331+
HardwareError::FailedToOpen => s.serialize_field("status", "failed-to-open"),
332+
HardwareError::FailedToRemainOpen => s.serialize_field("status", "failed-to-remain-open"),
333+
HardwareError::FailedToClose => s.serialize_field("status", "failed-to-close"),
334+
HardwareError::Unknown(x) => {
335+
s.serialize_field("status", &(*x as u16 | uapi::SDTX_CATEGORY_HARDWARE_ERROR))
336+
},
337+
},
338+
LatchStatus::Unknown(x) => s.serialize_field("status", x),
339+
}?;
340+
341+
s.end()
342+
},
343+
344+
Event::DeviceMode { mode } => {
345+
let mut s = serializer.serialize_struct("Event", 2)?;
346+
s.serialize_field("type", "device-mode")?;
347+
348+
match mode {
349+
DeviceMode::Tablet => s.serialize_field("mode", "tablet"),
350+
DeviceMode::Laptop => s.serialize_field("mode", "laptop"),
351+
DeviceMode::Studio => s.serialize_field("mode", "studio"),
352+
DeviceMode::Unknown(x) => s.serialize_field("mode", x),
353+
}?;
354+
355+
s.end()
356+
},
357+
358+
Event::Unknown { code, data } => {
359+
let mut s = serializer.serialize_struct("Event", 2)?;
360+
s.serialize_field("type", code)?;
361+
s.serialize_field("data", data)?;
362+
s.end()
363+
},
364+
}
365+
}
366+
}
367+
368+
impl std::fmt::Display for PrettyEvent {
369+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
370+
use sys::dtx::{DeviceType, Event};
371+
use sys::dtx::event::{BaseState, CancelReason, DeviceMode, LatchStatus};
372+
373+
match &self.0 {
374+
Event::Request => {
375+
write!(f, "Request")
376+
},
377+
378+
Event::Cancel { reason } => {
379+
write!(f, "Cancel {{ Reason: ")?;
380+
381+
match reason {
382+
CancelReason::Hardware(err) => write!(f, "\"{}\"", err),
383+
CancelReason::Runtime(err) => write!(f, "\"{}\"", err),
384+
CancelReason::Unknown(err) => write!(f, "{:#04x}", err),
385+
}?;
386+
387+
write!(f, " }}")
388+
},
389+
390+
Event::BaseConnection { state, device_type, id } => {
391+
write!(f, "BaseConnection {{ State: ")?;
392+
393+
match state {
394+
BaseState::Detached => write!(f, "Detached"),
395+
BaseState::Attached => write!(f, "Attached"),
396+
BaseState::NotFeasible => write!(f, "NotFeasible"),
397+
BaseState::Unknown(x) => write!(f, "{:#04x}", x),
398+
}?;
399+
400+
write!(f, ", DeviceType: ")?;
401+
402+
match device_type {
403+
DeviceType::Hid => write!(f, "Hid"),
404+
DeviceType::Ssh => write!(f, "Ssh"),
405+
DeviceType::Unknown(x) => write!(f, "{:#04x}", x),
406+
}?;
407+
408+
write!(f, ", Id: {:#04x} }}", id)
409+
},
410+
411+
Event::LatchStatus { status } => {
412+
write!(f, "LatchStatus {{ Status: ")?;
413+
414+
match status {
415+
LatchStatus::Closed => write!(f, "Closed"),
416+
LatchStatus::Opened => write!(f, "Opened"),
417+
LatchStatus::Error(err) => write!(f, "\"Error: {}\"", err),
418+
LatchStatus::Unknown(x) => write!(f, "{:#04x}", x),
419+
}?;
420+
421+
write!(f, " }}")
422+
},
423+
424+
Event::DeviceMode { mode } => {
425+
write!(f, "DeviceMode {{ Status: ")?;
426+
427+
match mode {
428+
DeviceMode::Tablet => write!(f, "Tablet"),
429+
DeviceMode::Laptop => write!(f, "Laptop"),
430+
DeviceMode::Studio => write!(f, "Studio"),
431+
DeviceMode::Unknown(x) => write!(f, "{:#04x}", x),
432+
}?;
433+
434+
write!(f, " }}")
435+
},
436+
437+
Event::Unknown { code, data } => {
438+
write!(f, "Unknown {{ Code: {:#04x}, Data: {:02x?} }}", code, data)
439+
},
440+
}
441+
}
442+
}

src/sys/dtx.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ pub enum Event {
227227
Unknown { code: u16, data: Vec<u8> },
228228
}
229229

230-
mod event {
230+
pub mod event {
231231
use super::*;
232232

233233
use std::convert::TryInto;
@@ -600,7 +600,7 @@ impl<'a> Iterator for EventStream<'a> {
600600

601601

602602
#[allow(clippy::identity_op)]
603-
mod uapi {
603+
pub mod uapi {
604604
use nix::{ioctl_none, ioctl_read};
605605

606606
// status/error categories

0 commit comments

Comments
 (0)