sim/runtime/reference_device/
profiles.rs1use std::rc::Rc;
2
3use sim_kernel::{Expr, Result, Symbol};
4use sim_lib_stream_device::ModeledDeviceCapsSource;
5use sim_lib_view_device::{
6 DeviceProfile, DeviceProfileParts, EncodedScene, LocalAdapter, RateClass,
7};
8use sim_value::build;
9
10pub fn reference_rich_profile_symbol() -> Symbol {
12 Symbol::qualified("device/reference", "rich-profile")
13}
14
15pub fn reference_glance_profile_symbol() -> Symbol {
17 Symbol::qualified("device/reference", "glance-profile")
18}
19
20pub fn reference_rich_profile() -> DeviceProfile {
22 DeviceProfile::new(DeviceProfileParts {
23 kind: Symbol::qualified("device", "reference-device"),
24 display: symbols(&["stereo", "hud"]),
25 input: symbols(&["tap"]),
26 output: symbols(&["hud", "haptic"]),
27 links: symbols(&["local"]),
28 streams: symbols(&["pose"]),
29 rate: RateClass::stereo(),
30 policy: build::map(vec![
31 ("consent", build::sym("required")),
32 ("retention-ms", build::uint(100)),
33 ]),
34 })
35}
36
37pub fn reference_glance_profile() -> DeviceProfile {
39 DeviceProfile::new(DeviceProfileParts {
40 kind: Symbol::qualified("device", "reference-glance"),
41 display: symbols(&["round"]),
42 input: symbols(&["tap"]),
43 output: symbols(&["haptic"]),
44 links: symbols(&["local"]),
45 streams: Vec::new(),
46 rate: RateClass::watch(),
47 policy: build::map(vec![
48 ("consent", build::sym("visible")),
49 ("retention-ms", build::uint(50)),
50 ]),
51 })
52}
53
54pub fn reference_caps_source() -> ModeledDeviceCapsSource {
56 ModeledDeviceCapsSource::new(
57 Symbol::qualified("device", "reference-device"),
58 vec![Symbol::qualified("device/stream", "pose")],
59 vec![Symbol::qualified("device/input", "tap")],
60 vec![
61 Symbol::qualified("device/output", "hud"),
62 Symbol::qualified("device/output", "haptic"),
63 ],
64 )
65 .with_seq_base(10)
66}
67
68#[derive(Clone, Debug, PartialEq, Eq)]
70pub struct ReferencePose {
71 pub seq: u64,
73 pub yaw_mdeg: i32,
75}
76
77impl ReferencePose {
78 pub fn new(seq: u64, yaw_mdeg: i32) -> Self {
80 Self { seq, yaw_mdeg }
81 }
82}
83
84#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
86pub struct ReferenceRichAdapter;
87
88impl LocalAdapter for ReferenceRichAdapter {
89 type State = ReferencePose;
90
91 fn adapt(
92 &self,
93 scene: &EncodedScene,
94 state: &Self::State,
95 profile: &DeviceProfile,
96 ) -> Result<Rc<Expr>> {
97 Ok(Rc::new(build::map(vec![
98 ("kind", build::qsym("device/reference", "rich-frame")),
99 ("tier", Expr::Symbol(profile.tier.to_symbol())),
100 ("pose-seq", build::uint(state.seq)),
101 ("yaw-mdeg", build::int(i64::from(state.yaw_mdeg))),
102 ("scene", scene.expr().clone()),
103 ])))
104 }
105}
106
107#[derive(Clone, Debug, Default, PartialEq, Eq)]
109pub struct ReferenceSceneEncoder {
110 calls: u64,
111}
112
113impl ReferenceSceneEncoder {
114 pub fn new() -> Self {
116 Self::default()
117 }
118
119 pub fn encode(&mut self) -> EncodedScene {
121 self.calls = self.calls.saturating_add(1);
122 EncodedScene::new(reference_scene())
123 }
124
125 pub fn calls(&self) -> u64 {
127 self.calls
128 }
129}
130
131pub fn reference_scene() -> Expr {
133 build::map(vec![
134 ("kind", build::qsym("scene", "glance")),
135 ("title", build::text("Reference pose")),
136 (
137 "metric",
138 build::map(vec![
139 ("label", build::text("yaw")),
140 ("value", build::text("12 deg")),
141 ]),
142 ),
143 (
144 "action",
145 build::map(vec![
146 ("label", build::text("Acknowledge")),
147 ("target", build::sym("tap")),
148 ]),
149 ),
150 ("urgency", build::sym("info")),
151 ("cells", build::uint(4)),
152 ("bypass-budget", Expr::Bool(false)),
153 ])
154}
155
156fn symbols(names: &[&str]) -> Vec<Symbol> {
157 names.iter().map(|name| Symbol::new(*name)).collect()
158}