1use sim_citizen_derive::Citizen;
4use sim_kernel::CapabilityName;
5
6use crate::{
7 AUTO_CONTROL_EXEC, AUTO_DIAGNOSTICS_READ, AUTO_MANIFEST_READ, AUTO_ORDER, AUTO_SERVICE_WRITE,
8 AUTO_TELEMETRY_READ, AUTO_TRANSPORT_CONNECT,
9};
10
11mod fields;
12
13#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
15#[citizen(symbol = "auto/VehicleId", version = 0)]
16pub struct VehicleId {
17 pub namespace: String,
19 pub key: String,
21}
22
23impl Default for VehicleId {
24 fn default() -> Self {
25 vehicle_id_example()
26 }
27}
28
29impl VehicleId {
30 pub fn new(namespace: impl Into<String>, key: impl Into<String>) -> Self {
32 Self {
33 namespace: namespace.into(),
34 key: key.into(),
35 }
36 }
37}
38
39#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
41#[citizen(symbol = "auto/Dtc", version = 0)]
42pub struct Dtc {
43 pub system: String,
45 pub code: String,
47 pub description: String,
49 #[citizen(with = "fields::dtc_status_field")]
51 pub status: DtcStatus,
52}
53
54impl Default for Dtc {
55 fn default() -> Self {
56 dtc_example()
57 }
58}
59
60impl Dtc {
61 pub fn new(
63 system: impl Into<String>,
64 code: impl Into<String>,
65 description: impl Into<String>,
66 ) -> Self {
67 Self::with_status(system, code, description, DtcStatus::default())
68 }
69
70 pub fn with_status(
72 system: impl Into<String>,
73 code: impl Into<String>,
74 description: impl Into<String>,
75 status: DtcStatus,
76 ) -> Self {
77 Self {
78 system: system.into(),
79 code: code.into(),
80 description: description.into(),
81 status,
82 }
83 }
84}
85
86#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Citizen)]
88#[citizen(symbol = "auto/DtcStatus", version = 0)]
89pub struct DtcStatus {
90 pub test_failed: bool,
92 pub test_failed_this_operation_cycle: bool,
94 pub pending: bool,
96 pub confirmed: bool,
98 pub test_not_completed_since_clear: bool,
100 pub test_failed_since_clear: bool,
102 pub test_not_completed_this_operation_cycle: bool,
104 pub warning_indicator: bool,
106}
107
108impl DtcStatus {
109 pub fn from_byte(byte: u8) -> Self {
111 Self {
112 test_failed: byte & 0x01 != 0,
113 test_failed_this_operation_cycle: byte & 0x02 != 0,
114 pending: byte & 0x04 != 0,
115 confirmed: byte & 0x08 != 0,
116 test_not_completed_since_clear: byte & 0x10 != 0,
117 test_failed_since_clear: byte & 0x20 != 0,
118 test_not_completed_this_operation_cycle: byte & 0x40 != 0,
119 warning_indicator: byte & 0x80 != 0,
120 }
121 }
122
123 pub fn to_byte(self) -> u8 {
125 u8::from(self.test_failed)
126 | (u8::from(self.test_failed_this_operation_cycle) << 1)
127 | (u8::from(self.pending) << 2)
128 | (u8::from(self.confirmed) << 3)
129 | (u8::from(self.test_not_completed_since_clear) << 4)
130 | (u8::from(self.test_failed_since_clear) << 5)
131 | (u8::from(self.test_not_completed_this_operation_cycle) << 6)
132 | (u8::from(self.warning_indicator) << 7)
133 }
134}
135
136#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
138#[citizen(symbol = "auto/BrandCaps", version = 0)]
139pub struct BrandCaps {
140 pub brand: String,
142 pub capabilities: Vec<CapabilityName>,
144}
145
146impl Default for BrandCaps {
147 fn default() -> Self {
148 brand_caps_example()
149 }
150}
151
152impl BrandCaps {
153 pub fn new(brand: impl Into<String>, capabilities: Vec<CapabilityName>) -> Self {
155 Self {
156 brand: brand.into(),
157 capabilities,
158 }
159 }
160}
161
162#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
164#[citizen(symbol = "auto/AutoLane", version = 0)]
165pub struct AutoLane {
166 pub name: String,
168}
169
170impl Default for AutoLane {
171 fn default() -> Self {
172 auto_lane_example()
173 }
174}
175
176impl AutoLane {
177 pub fn new(name: impl Into<String>) -> Self {
179 Self { name: name.into() }
180 }
181}
182
183#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
185#[citizen(symbol = "auto/EffectClass", version = 0)]
186pub struct EffectClass {
187 pub name: String,
189}
190
191impl Default for EffectClass {
192 fn default() -> Self {
193 effect_class_example()
194 }
195}
196
197impl EffectClass {
198 pub fn new(name: impl Into<String>) -> Self {
200 Self { name: name.into() }
201 }
202}
203
204#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
206#[citizen(symbol = "auto/OpCap", version = 0)]
207pub struct OpCap {
208 pub operation: String,
210 pub capability: CapabilityName,
212 pub effect_class: String,
214}
215
216impl Default for OpCap {
217 fn default() -> Self {
218 op_cap_example()
219 }
220}
221
222impl OpCap {
223 pub fn new(
225 operation: impl Into<String>,
226 capability: CapabilityName,
227 effect_class: impl Into<String>,
228 ) -> Self {
229 Self {
230 operation: operation.into(),
231 capability,
232 effect_class: effect_class.into(),
233 }
234 }
235}
236
237#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
239#[citizen(symbol = "auto/TransportSpec", version = 0)]
240pub struct TransportSpec {
241 pub name: String,
243 pub protocol: String,
245 pub lane: String,
247 pub read_capability: CapabilityName,
249 pub write_capability: CapabilityName,
251}
252
253impl Default for TransportSpec {
254 fn default() -> Self {
255 transport_spec_example()
256 }
257}
258
259impl TransportSpec {
260 pub fn new(
262 name: impl Into<String>,
263 protocol: impl Into<String>,
264 lane: impl Into<String>,
265 read_capability: CapabilityName,
266 write_capability: CapabilityName,
267 ) -> Self {
268 Self {
269 name: name.into(),
270 protocol: protocol.into(),
271 lane: lane.into(),
272 read_capability,
273 write_capability,
274 }
275 }
276}
277
278#[derive(Clone, Debug, PartialEq, Eq, Citizen)]
280#[citizen(symbol = "auto/SiteManifest", version = 0)]
281pub struct SiteManifest {
282 pub site: String,
284 pub vehicle: String,
286 pub brand: String,
288 pub makes: Vec<String>,
290 pub lanes: Vec<String>,
292 pub transports: Vec<String>,
294 pub operations: Vec<String>,
296 #[citizen(with = "fields::op_caps_field")]
298 pub op_caps: Vec<OpCap>,
299 pub ceiling: Vec<CapabilityName>,
301}
302
303impl Default for SiteManifest {
304 fn default() -> Self {
305 site_manifest_example()
306 }
307}
308
309impl SiteManifest {
310 pub fn new(
312 site: impl Into<String>,
313 vehicle: impl Into<String>,
314 brand: impl Into<String>,
315 lanes: Vec<String>,
316 transports: Vec<String>,
317 operations: Vec<String>,
318 ) -> Self {
319 let brand = brand.into();
320 Self {
321 site: site.into(),
322 vehicle: vehicle.into(),
323 makes: vec![brand.clone()],
324 brand,
325 lanes,
326 transports,
327 operations,
328 op_caps: Vec::new(),
329 ceiling: Vec::new(),
330 }
331 }
332
333 pub fn with_makes(mut self, makes: Vec<String>) -> Self {
335 self.makes = makes;
336 self
337 }
338
339 pub fn with_op_caps(mut self, op_caps: Vec<OpCap>) -> Self {
341 self.op_caps = op_caps;
342 self
343 }
344
345 pub fn with_ceiling(mut self, ceiling: Vec<CapabilityName>) -> Self {
347 self.ceiling = ceiling;
348 self
349 }
350}
351
352pub fn diagnostic_lane() -> AutoLane {
354 auto_lane("diagnostics")
355}
356
357pub fn telemetry_lane() -> AutoLane {
359 auto_lane("telemetry")
360}
361
362pub fn manifest_lane() -> AutoLane {
364 auto_lane("manifest")
365}
366
367pub fn auto_lane(name: impl Into<String>) -> AutoLane {
369 AutoLane::new(name)
370}
371
372pub fn diagnostic_effect() -> EffectClass {
374 EffectClass::new("diagnostic-read")
375}
376
377pub fn control_effect() -> EffectClass {
379 EffectClass::new("control-write")
380}
381
382fn vehicle_id_example() -> VehicleId {
383 VehicleId::new("fixture", "vehicle-alpha")
384}
385
386fn dtc_example() -> Dtc {
387 Dtc::with_status(
388 "body",
389 "B0000",
390 "modeled diagnostic",
391 DtcStatus::from_byte(0x08),
392 )
393}
394
395fn brand_caps_example() -> BrandCaps {
396 BrandCaps::new(
397 "fixture-brand",
398 vec![
399 CapabilityName::new(AUTO_DIAGNOSTICS_READ),
400 CapabilityName::new(AUTO_TELEMETRY_READ),
401 ],
402 )
403}
404
405fn auto_lane_example() -> AutoLane {
406 diagnostic_lane()
407}
408
409fn effect_class_example() -> EffectClass {
410 diagnostic_effect()
411}
412
413fn op_cap_example() -> OpCap {
414 OpCap::new(
415 "diagnostics/read-dtc",
416 CapabilityName::new(AUTO_DIAGNOSTICS_READ),
417 "diagnostic-read",
418 )
419}
420
421fn transport_spec_example() -> TransportSpec {
422 TransportSpec::new(
423 "fixture-transport",
424 "modeled-bus",
425 "diagnostics",
426 CapabilityName::new(AUTO_TRANSPORT_CONNECT),
427 CapabilityName::new(AUTO_SERVICE_WRITE),
428 )
429}
430
431fn site_manifest_example() -> SiteManifest {
432 SiteManifest::new(
433 "fixture-site",
434 "vehicle-alpha",
435 "fixture-brand",
436 vec!["diagnostics".to_owned(), "telemetry".to_owned()],
437 vec!["fixture-transport".to_owned()],
438 vec!["diagnostics/read-dtc".to_owned()],
439 )
440}
441
442#[allow(dead_code)]
443fn capability_examples() -> [CapabilityName; 5] {
444 [
445 CapabilityName::new(AUTO_CONTROL_EXEC),
446 CapabilityName::new(AUTO_MANIFEST_READ),
447 CapabilityName::new(AUTO_SERVICE_WRITE),
448 CapabilityName::new(AUTO_ORDER),
449 CapabilityName::new(AUTO_TELEMETRY_READ),
450 ]
451}