scs_sdk/channel.rs
1use core::ffi::{CStr, c_void};
2use core::marker::PhantomData;
3use core::ops::{BitOr, BitOrAssign};
4
5use crate::{
6 GameSchemaAvailability, SdkCall, SdkError, SdkIndex, SdkResult, SdkValue, ValueRef, ValueType,
7 sys,
8};
9
10/// Value types which can be requested from an SCS telemetry channel.
11///
12/// The game validates whether a particular channel supports the requested
13/// representation. For example, placement channels commonly accept placement,
14/// vector, or Euler representations, while `u32` channels commonly accept
15/// `u64`. Unsupported requests return [`SdkError::UnsupportedType`].
16pub trait ChannelValue: SdkValue {}
17
18impl<T: SdkValue> ChannelValue for T {}
19
20#[derive(Debug, PartialEq, Eq)]
21pub struct Channel<T> {
22 name: &'static CStr,
23 indexed: bool,
24 availability: GameSchemaAvailability,
25 marker: PhantomData<fn() -> T>,
26}
27
28/// A telemetry channel descriptor after erasing its Rust marker type.
29///
30/// Framework code needs a uniform representation because a plugin can
31/// subscribe to channels carrying many different SDK value types. Erasure does
32/// not discard the ABI type discriminator: [`AnyChannel::value_type`] remains
33/// available and callback values must still carry that exact tag before typed
34/// decoding succeeds.
35///
36/// Application plugins normally construct this value through
37/// [`Channel::erase`] rather than directly.
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39pub struct AnyChannel {
40 name: &'static CStr,
41 value_type: ValueType,
42 indexed: bool,
43 availability: GameSchemaAvailability,
44}
45
46impl AnyChannel {
47 /// Returns the canonical, NUL-terminated channel name from the SDK header.
48 #[must_use]
49 pub const fn name(self) -> &'static CStr {
50 self.name
51 }
52
53 /// Returns the concrete tagged-union member requested during registration.
54 #[must_use]
55 pub const fn value_type(self) -> ValueType {
56 self.value_type
57 }
58
59 /// Whether the channel requires a separate zero-based SDK index.
60 ///
61 /// This index is used for arrays such as wheels. It is distinct from the
62 /// trailer number embedded in a multi-trailer channel name.
63 #[must_use]
64 pub const fn is_indexed(self) -> bool {
65 self.indexed
66 }
67
68 /// Returns the official per-game schema history for this channel.
69 ///
70 /// Type erasure retains availability so framework code can reject a
71 /// required channel, or skip an optional channel, before asking an older
72 /// game schema to register a name it cannot expose.
73 #[must_use]
74 pub const fn availability(self) -> GameSchemaAvailability {
75 self.availability
76 }
77}
78
79impl<T> Clone for Channel<T> {
80 fn clone(&self) -> Self {
81 *self
82 }
83}
84
85impl<T> Copy for Channel<T> {}
86
87impl<T: ChannelValue> Channel<T> {
88 #[must_use]
89 pub const fn new(name: &'static CStr, availability: GameSchemaAvailability) -> Self {
90 Self {
91 name,
92 indexed: false,
93 availability,
94 marker: PhantomData,
95 }
96 }
97
98 /// Creates a descriptor whose values are selected through the SDK `index`
99 /// parameter, such as individual wheel or H-shifter selector channels.
100 #[must_use]
101 pub const fn indexed(name: &'static CStr, availability: GameSchemaAvailability) -> Self {
102 Self {
103 name,
104 indexed: true,
105 availability,
106 marker: PhantomData,
107 }
108 }
109
110 #[must_use]
111 pub const fn name(self) -> &'static CStr {
112 self.name
113 }
114
115 #[must_use]
116 pub const fn value_type(self) -> sys::ScsValueType {
117 T::TYPE
118 }
119
120 /// Whether registration requires an explicit zero-based SDK index.
121 #[must_use]
122 pub const fn is_indexed(self) -> bool {
123 self.indexed
124 }
125
126 /// Returns the first official ETS2 and ATS schemas for this channel.
127 #[must_use]
128 pub const fn availability(self) -> GameSchemaAvailability {
129 self.availability
130 }
131
132 /// Requests the same channel using another SDK value representation.
133 ///
134 /// SCS performs the authoritative compatibility check during registration
135 /// and reports `SCS_RESULT_unsupported_type` when conversion is unavailable.
136 #[must_use]
137 pub const fn requesting<U: ChannelValue>(self) -> Channel<U> {
138 Channel {
139 name: self.name,
140 indexed: self.indexed,
141 availability: self.availability,
142 marker: PhantomData,
143 }
144 }
145
146 /// Erases the Rust marker type while preserving the SDK value discriminator.
147 ///
148 /// This is the representation used by the plugin framework's heterogeneous
149 /// subscription table. A value can later be decoded with the original
150 /// typed descriptor only when the names, index mode, and value types match.
151 #[must_use]
152 pub const fn erase(self) -> AnyChannel {
153 AnyChannel {
154 name: self.name,
155 value_type: T::VALUE_TYPE,
156 indexed: self.indexed,
157 availability: self.availability,
158 }
159 }
160
161 /// Decodes a callback value according to this descriptor's requested type.
162 #[must_use]
163 pub fn decode(self, value: ValueRef<'_>) -> Option<T::Decoded<'_>> {
164 T::decode(value)
165 }
166}
167
168#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
169#[repr(transparent)]
170pub struct ChannelFlags(sys::ScsU32);
171
172impl ChannelFlags {
173 pub const NONE: Self = Self(sys::SCS_TELEMETRY_CHANNEL_FLAG_NONE);
174 pub const EACH_FRAME: Self = Self(sys::SCS_TELEMETRY_CHANNEL_FLAG_EACH_FRAME);
175 pub const NO_VALUE: Self = Self(sys::SCS_TELEMETRY_CHANNEL_FLAG_NO_VALUE);
176
177 #[must_use]
178 pub const fn bits(self) -> sys::ScsU32 {
179 self.0
180 }
181}
182
183impl BitOr for ChannelFlags {
184 type Output = Self;
185
186 fn bitor(self, rhs: Self) -> Self::Output {
187 Self(self.0 | rhs.0)
188 }
189}
190
191impl BitOrAssign for ChannelFlags {
192 fn bitor_assign(&mut self, rhs: Self) {
193 self.0 |= rhs.0;
194 }
195}
196
197impl SdkCall<'_> {
198 /// Registers a typed telemetry channel callback.
199 ///
200 /// # Safety
201 ///
202 /// `callback` must implement the exact SDK ABI, must decode the value
203 /// according to `T`, and must not unwind across the ABI boundary. `context`
204 /// must remain valid for every invocation of `callback`. This method must
205 /// be called from initialization or an SCS event callback, never from a
206 /// worker thread or another channel callback.
207 ///
208 /// # Errors
209 ///
210 /// Returns the result reported by the game's registration function.
211 pub unsafe fn register_channel<T: ChannelValue>(
212 &self,
213 channel: Channel<T>,
214 index: Option<SdkIndex>,
215 flags: ChannelFlags,
216 callback: sys::ScsTelemetryChannelCallback,
217 context: *mut c_void,
218 ) -> SdkResult {
219 // SAFETY: The caller upholds the SDK callback, context, and call-site
220 // restrictions documented above.
221 let result = unsafe {
222 (self.table.register_for_channel)(
223 channel.name().as_ptr(),
224 index.map_or(sys::SCS_U32_NIL, SdkIndex::raw),
225 channel.value_type(),
226 flags.bits(),
227 callback,
228 context,
229 )
230 };
231 SdkError::from_code(result)
232 }
233
234 /// Unregisters a telemetry channel callback.
235 ///
236 /// # Safety
237 ///
238 /// Must be called from initialization, shutdown, or an SCS event callback,
239 /// never from a channel callback or a worker thread. Context storage
240 /// associated with the old registration must remain alive until this
241 /// function succeeds and no invocation of that callback is active.
242 ///
243 /// # Errors
244 ///
245 /// Returns the result reported by the game's unregistration function.
246 pub unsafe fn unregister_channel<T: ChannelValue>(
247 &self,
248 channel: Channel<T>,
249 index: Option<SdkIndex>,
250 ) -> SdkResult {
251 // SAFETY: The caller upholds the SDK call-site restriction.
252 let result = unsafe {
253 (self.table.unregister_from_channel)(
254 channel.name().as_ptr(),
255 index.map_or(sys::SCS_U32_NIL, SdkIndex::raw),
256 channel.value_type(),
257 )
258 };
259 SdkError::from_code(result)
260 }
261
262 /// Registers a channel whose Rust marker type has been erased by a
263 /// framework subscription table.
264 ///
265 /// Unlike [`SdkCall::register_channel`], the channel name may be owned by
266 /// the caller. This is required for multi-trailer names such as
267 /// `trailer.3.connected`, which do not exist as static macros in the C
268 /// header.
269 ///
270 /// # Safety
271 ///
272 /// `callback` must implement the exact SDK ABI, verify every received value
273 /// against `value_type`, and prevent unwinding across the ABI boundary.
274 /// `name` and `context` must remain valid for the complete registration
275 /// lifetime. This method may only be called at an SDK-approved registration
276 /// point on the game main thread.
277 ///
278 /// # Errors
279 ///
280 /// Returns the exact result reported by the game's registration function.
281 pub unsafe fn register_erased_channel(
282 &self,
283 name: &CStr,
284 index: Option<SdkIndex>,
285 value_type: ValueType,
286 flags: ChannelFlags,
287 callback: sys::ScsTelemetryChannelCallback,
288 context: *mut c_void,
289 ) -> SdkResult {
290 // SAFETY: The caller owns the name/context lifetime and callback ABI
291 // invariants documented above.
292 let result = unsafe {
293 (self.table.register_for_channel)(
294 name.as_ptr(),
295 index.map_or(sys::SCS_U32_NIL, SdkIndex::raw),
296 value_type.raw(),
297 flags.bits(),
298 callback,
299 context,
300 )
301 };
302 SdkError::from_code(result)
303 }
304
305 /// Unregisters one previously registered type-erased channel.
306 ///
307 /// # Safety
308 ///
309 /// This must run at an SDK-approved unregistration point on the game main
310 /// thread. The callback context and channel name must remain alive until
311 /// unregistration succeeds and any active callback has returned.
312 ///
313 /// # Errors
314 ///
315 /// Returns the exact result reported by the game's unregistration function.
316 pub unsafe fn unregister_erased_channel(
317 &self,
318 name: &CStr,
319 index: Option<SdkIndex>,
320 value_type: ValueType,
321 ) -> SdkResult {
322 // SAFETY: The caller upholds the SDK call-site and storage-lifetime
323 // restrictions documented above.
324 let result = unsafe {
325 (self.table.unregister_from_channel)(
326 name.as_ptr(),
327 index.map_or(sys::SCS_U32_NIL, SdkIndex::raw),
328 value_type.raw(),
329 )
330 };
331 SdkError::from_code(result)
332 }
333}
334
335/// Complete typed channel catalog for SCS Telemetry SDK 1.14.
336pub mod channels {
337 use super::AnyChannel;
338 use crate::{GameSchemaAvailability, game};
339
340 // These constants encode the game-schema history documented by the ETS2
341 // and ATS headers. They are deliberately named by both version domains:
342 // an ETS2 minor must never be reused as though it were the equivalent ATS
343 // minor merely because both games expose the same common C macro.
344 const INITIAL: GameSchemaAvailability =
345 GameSchemaAvailability::new(Some(game::ets2::V1_00), Some(game::ats::V1_00));
346 const ETS2_1_01_ATS_1_00: GameSchemaAvailability =
347 GameSchemaAvailability::new(Some(game::ets2::V1_01), Some(game::ats::V1_00));
348 const ETS2_1_02_ATS_1_00: GameSchemaAvailability =
349 GameSchemaAvailability::new(Some(game::ets2::V1_02), Some(game::ats::V1_00));
350 const ETS2_1_04_ATS_1_00: GameSchemaAvailability =
351 GameSchemaAvailability::new(Some(game::ets2::V1_04), Some(game::ats::V1_00));
352 const ETS2_1_09_ATS_1_00: GameSchemaAvailability =
353 GameSchemaAvailability::new(Some(game::ets2::V1_09), Some(game::ats::V1_00));
354 const ETS2_1_10_ATS_1_00: GameSchemaAvailability =
355 GameSchemaAvailability::new(Some(game::ets2::V1_10), Some(game::ats::V1_00));
356 const ETS2_1_11_ATS_1_00: GameSchemaAvailability =
357 GameSchemaAvailability::new(Some(game::ets2::V1_11), Some(game::ats::V1_00));
358 const ETS2_1_12_ATS_1_00: GameSchemaAvailability =
359 GameSchemaAvailability::new(Some(game::ets2::V1_12), Some(game::ats::V1_00));
360 const ETS2_ONLY_1_12: GameSchemaAvailability =
361 GameSchemaAvailability::new(Some(game::ets2::V1_12), None);
362 const ETS2_1_14_ATS_1_01: GameSchemaAvailability = game::capabilities::MULTI_TRAILER;
363 const ETS2_1_17_ATS_1_04: GameSchemaAvailability =
364 GameSchemaAvailability::new(Some(game::ets2::V1_17), Some(game::ats::V1_04));
365 const ETS2_1_18_ATS_1_05: GameSchemaAvailability =
366 GameSchemaAvailability::new(Some(game::ets2::V1_18), Some(game::ats::V1_05));
367
368 /// First schema which supports the numbered `trailer.[index].*` namespace.
369 ///
370 /// The static `trailer.*` descriptors predate this feature. Framework code
371 /// must combine their individual availability with this capability when it
372 /// constructs a numbered multi-trailer channel name.
373 pub const MULTI_TRAILER_AVAILABILITY: GameSchemaAvailability =
374 game::capabilities::MULTI_TRAILER;
375
376 /// Channels declared by `scssdk_telemetry_common_channels.h`.
377 pub mod common {
378 use super::super::{AnyChannel, Channel};
379 use super::{ETS2_1_09_ATS_1_00, ETS2_1_18_ATS_1_05, INITIAL};
380
381 /// Number of typed descriptors in this catalog group.
382 pub const COUNT: usize = 4;
383
384 /// Scale applied to distance and time to compensate
385 /// for the scale of the map (e.g. 1s of real time corresponds to `local_scale`
386 /// seconds of simulated game time).
387 ///
388 /// Games which use real 1:1 maps will not provide this
389 /// channel.
390 ///
391 /// Type: float
392 pub const LOCAL_SCALE: Channel<f32> = Channel::new(c"local.scale", INITIAL);
393
394 /// Absolute in-game time.
395 ///
396 /// Represented in number of in-game minutes since beginning (i.e. 00:00)
397 /// of the first in-game day.
398 ///
399 /// Type: u32
400 pub const GAME_TIME: Channel<u32> = Channel::new(c"game.time", ETS2_1_09_ATS_1_00);
401
402 /// Offset from the `game_time` simulated in the local economy to the
403 /// game time of the Convoy multiplayer server.
404 ///
405 /// The value of this channel can change frequently during the Convoy
406 /// session. For example when the user enters the desktop, the local
407 /// economy time stops however the multiplayer time continues to run
408 /// so the value will start to change.
409 ///
410 /// Represented in in-game minutes. Set to 0 when multiplayer is not active.
411 ///
412 /// Type: s32
413 pub const MULTIPLAYER_TIME_OFFSET: Channel<i32> =
414 Channel::new(c"multiplayer.time.offset", ETS2_1_18_ATS_1_05);
415
416 /// Time until next rest stop.
417 ///
418 /// When the fatique simulation is disabled, the behavior of this channel
419 /// is implementation dependent. The game might provide the value which would
420 /// apply if it was enabled or provide no value at all.
421 ///
422 /// Represented in in-game minutes.
423 ///
424 /// Type: s32
425 pub const NEXT_REST_STOP: Channel<i32> = Channel::new(c"rest.stop", ETS2_1_09_ATS_1_00);
426
427 /// Every common channel in the order used by the SDK 1.14 header.
428 ///
429 /// The marker types are erased only so callers can enumerate mixed
430 /// channel types. Each entry still retains its exact value type and
431 /// indexed/scalar registration mode.
432 pub const ALL: [AnyChannel; COUNT] = [
433 LOCAL_SCALE.erase(),
434 GAME_TIME.erase(),
435 MULTIPLAYER_TIME_OFFSET.erase(),
436 NEXT_REST_STOP.erase(),
437 ];
438 }
439
440 /// Channels declared by `scssdk_telemetry_truck_common_channels.h`.
441 pub mod truck {
442 use super::super::{AnyChannel, Channel};
443 use super::{
444 ETS2_1_01_ATS_1_00, ETS2_1_02_ATS_1_00, ETS2_1_04_ATS_1_00, ETS2_1_10_ATS_1_00,
445 ETS2_1_11_ATS_1_00, ETS2_1_12_ATS_1_00, ETS2_1_17_ATS_1_04, ETS2_ONLY_1_12, INITIAL,
446 };
447
448 /// Number of typed descriptors in this catalog group.
449 pub const COUNT: usize = 84;
450
451 /// Represents world space position and orientation of the truck.
452 ///
453 /// Type: dplacement
454 pub const WORLD_PLACEMENT: Channel<crate::DPlacement> =
455 Channel::new(c"truck.world.placement", INITIAL);
456
457 /// Represents vehicle space linear velocity of the truck measured
458 /// in meters per second.
459 ///
460 /// Type: fvector
461 pub const LOCAL_LINEAR_VELOCITY: Channel<crate::FVector> =
462 Channel::new(c"truck.local.velocity.linear", INITIAL);
463
464 /// Represents vehicle space angular velocity of the truck measured
465 /// in rotations per second.
466 ///
467 /// Type: fvector
468 pub const LOCAL_ANGULAR_VELOCITY: Channel<crate::FVector> =
469 Channel::new(c"truck.local.velocity.angular", INITIAL);
470
471 /// Represents vehicle space linear acceleration of the truck measured
472 /// in meters per second^2
473 ///
474 /// Type: fvector
475 pub const LOCAL_LINEAR_ACCELERATION: Channel<crate::FVector> =
476 Channel::new(c"truck.local.acceleration.linear", INITIAL);
477
478 /// Represents vehicle space angular acceleration of the truck meassured
479 /// in rotations per second^2
480 ///
481 /// Type: fvector
482 pub const LOCAL_ANGULAR_ACCELERATION: Channel<crate::FVector> =
483 Channel::new(c"truck.local.acceleration.angular", INITIAL);
484
485 /// Represents a vehicle space position and orientation delta
486 /// of the cabin from its default position.
487 ///
488 /// Type: fplacement
489 pub const CABIN_OFFSET: Channel<crate::FPlacement> =
490 Channel::new(c"truck.cabin.offset", ETS2_1_02_ATS_1_00);
491
492 /// Represents cabin space angular velocity of the cabin measured
493 /// in rotations per second.
494 ///
495 /// Type: fvector
496 pub const CABIN_ANGULAR_VELOCITY: Channel<crate::FVector> =
497 Channel::new(c"truck.cabin.velocity.angular", INITIAL);
498
499 /// Represents cabin space angular acceleration of the cabin
500 /// measured in rotations per second^2
501 ///
502 /// Type: fvector
503 pub const CABIN_ANGULAR_ACCELERATION: Channel<crate::FVector> =
504 Channel::new(c"truck.cabin.acceleration.angular", INITIAL);
505
506 /// Represents a cabin space position and orientation delta
507 /// of the driver head from its default position.
508 ///
509 /// Note that this value might change rapidly as result of
510 /// the user switching between cameras or camera presets.
511 ///
512 /// Type: fplacement
513 pub const HEAD_OFFSET: Channel<crate::FPlacement> =
514 Channel::new(c"truck.head.offset", INITIAL);
515
516 /// Speedometer speed in meters per second.
517 ///
518 /// Uses negative value to represent reverse movement.
519 ///
520 /// Type: float
521 pub const SPEED: Channel<f32> = Channel::new(c"truck.speed", INITIAL);
522
523 /// RPM of the engine.
524 ///
525 /// Type: float
526 pub const ENGINE_RPM: Channel<f32> = Channel::new(c"truck.engine.rpm", INITIAL);
527
528 /// Gear currently selected in the engine.
529 ///
530 /// - >0 - Forwad gears
531 /// - 0 - Neutral
532 /// - <0 - Reverse gears
533 ///
534 /// Type: s32
535 pub const ENGINE_GEAR: Channel<i32> = Channel::new(c"truck.engine.gear", INITIAL);
536
537 /// Gear currently displayed on dashboard.
538 ///
539 /// - >0 - Forwad gears
540 /// - 0 - Neutral
541 /// - <0 - Reverse gears
542 ///
543 /// Type: s32
544 pub const DISPLAYED_GEAR: Channel<i32> =
545 Channel::new(c"truck.displayed.gear", ETS2_1_11_ATS_1_00);
546
547 /// Steering received from input <-1;1>.
548 ///
549 /// Note that it is interpreted counterclockwise.
550 ///
551 /// If the user presses the steer right button on digital input
552 /// (e.g. keyboard) this value goes immediatelly to -1.0
553 ///
554 /// Type: float
555 pub const INPUT_STEERING: Channel<f32> = Channel::new(c"truck.input.steering", INITIAL);
556
557 /// Throttle received from input <0;1>
558 ///
559 /// If the user presses the forward button on digital input
560 /// (e.g. keyboard) this value goes immediatelly to 1.0
561 ///
562 /// Type: float
563 pub const INPUT_THROTTLE: Channel<f32> = Channel::new(c"truck.input.throttle", INITIAL);
564
565 /// Brake received from input <0;1>
566 ///
567 /// If the user presses the brake button on digital input
568 /// (e.g. keyboard) this value goes immediatelly to 1.0
569 ///
570 /// Type: float
571 pub const INPUT_BRAKE: Channel<f32> = Channel::new(c"truck.input.brake", INITIAL);
572
573 /// Clutch received from input <0;1>
574 ///
575 /// If the user presses the clutch button on digital input
576 /// (e.g. keyboard) this value goes immediatelly to 1.0
577 ///
578 /// Type: float
579 pub const INPUT_CLUTCH: Channel<f32> = Channel::new(c"truck.input.clutch", INITIAL);
580
581 /// Steering as used by the simulation <-1;1>
582 ///
583 /// Note that it is interpreted counterclockwise.
584 ///
585 /// Accounts for interpolation speeds and simulated
586 /// counterfoces for digital inputs.
587 ///
588 /// Type: float
589 pub const EFFECTIVE_STEERING: Channel<f32> =
590 Channel::new(c"truck.effective.steering", INITIAL);
591
592 /// Throttle pedal input as used by the simulation <0;1>
593 ///
594 /// Accounts for the press attack curve for digital inputs
595 /// or cruise-control input.
596 ///
597 /// Type: float
598 pub const EFFECTIVE_THROTTLE: Channel<f32> =
599 Channel::new(c"truck.effective.throttle", INITIAL);
600
601 /// Brake pedal input as used by the simulation <0;1>
602 ///
603 /// Accounts for the press attack curve for digital inputs. Does
604 /// not contain retarder, parking or engine brake.
605 ///
606 /// Type: float
607 pub const EFFECTIVE_BRAKE: Channel<f32> = Channel::new(c"truck.effective.brake", INITIAL);
608
609 /// Clutch pedal input as used by the simulation <0;1>
610 ///
611 /// Accounts for the automatic shifting or interpolation of
612 /// player input.
613 ///
614 /// Type: float
615 pub const EFFECTIVE_CLUTCH: Channel<f32> = Channel::new(c"truck.effective.clutch", INITIAL);
616
617 /// Speed selected for the cruise control in m/s
618 ///
619 /// Is zero if cruise control is disabled.
620 ///
621 /// Type: float
622 pub const CRUISE_CONTROL: Channel<f32> = Channel::new(c"truck.cruise_control", INITIAL);
623
624 /// Gearbox slot the h-shifter handle is currently in.
625 ///
626 /// 0 means that no slot is selected.
627 ///
628 /// Type: u32
629 pub const HSHIFTER_SLOT: Channel<u32> = Channel::new(c"truck.hshifter.slot", INITIAL);
630
631 /// Enabled state of range/splitter selector toggles.
632 ///
633 /// Mapping between the range/splitter functionality and
634 /// selector index is described by HSHIFTER configuration.
635 ///
636 /// Type: indexed bool
637 pub const HSHIFTER_SELECTOR: Channel<bool> =
638 Channel::indexed(c"truck.hshifter.select", INITIAL);
639
640 /// Is the parking brake enabled?
641 ///
642 /// Type: bool
643 pub const PARKING_BRAKE: Channel<bool> = Channel::new(c"truck.brake.parking", INITIAL);
644
645 /// Is the engine brake enabled?
646 ///
647 /// Type: bool
648 pub const MOTOR_BRAKE: Channel<bool> = Channel::new(c"truck.brake.motor", INITIAL);
649
650 /// Current level of the retarder.
651 ///
652 /// <0;max> where 0 is disabled retarder and max is maximum
653 /// value found in TRUCK configuration.
654 ///
655 /// Type: u32
656 pub const RETARDER_LEVEL: Channel<u32> = Channel::new(c"truck.brake.retarder", INITIAL);
657
658 /// Pressure in the brake air tank in psi
659 ///
660 /// Type: float
661 pub const BRAKE_AIR_PRESSURE: Channel<f32> =
662 Channel::new(c"truck.brake.air.pressure", INITIAL);
663
664 /// Is the air pressure warning active?
665 ///
666 /// Type: bool
667 pub const BRAKE_AIR_PRESSURE_WARNING: Channel<bool> =
668 Channel::new(c"truck.brake.air.pressure.warning", INITIAL);
669
670 /// Are the emergency brakes active as result of low air pressure?
671 ///
672 /// Type: bool
673 pub const BRAKE_AIR_PRESSURE_EMERGENCY: Channel<bool> =
674 Channel::new(c"truck.brake.air.pressure.emergency", ETS2_1_01_ATS_1_00);
675
676 /// Temperature of the brakes in degrees celsius.
677 ///
678 /// Aproximated for entire truck, not at the wheel level.
679 ///
680 /// Type: float
681 pub const BRAKE_TEMPERATURE: Channel<f32> =
682 Channel::new(c"truck.brake.temperature", INITIAL);
683
684 /// Amount of fuel in liters
685 ///
686 /// Type: float
687 pub const FUEL: Channel<f32> = Channel::new(c"truck.fuel.amount", INITIAL);
688
689 /// Is the low fuel warning active?
690 ///
691 /// Type: bool
692 pub const FUEL_WARNING: Channel<bool> = Channel::new(c"truck.fuel.warning", INITIAL);
693
694 /// Average consumption of the fuel in liters/km
695 ///
696 /// Type: float
697 pub const FUEL_AVERAGE_CONSUMPTION: Channel<f32> =
698 Channel::new(c"truck.fuel.consumption.average", INITIAL);
699
700 /// Estimated range of truck with current amount of fuel in km
701 ///
702 /// Type: float
703 pub const FUEL_RANGE: Channel<f32> = Channel::new(c"truck.fuel.range", ETS2_1_12_ATS_1_00);
704
705 /// Amount of `AdBlue` in liters
706 ///
707 /// Type: float
708 pub const ADBLUE: Channel<f32> = Channel::new(c"truck.adblue", ETS2_ONLY_1_12);
709
710 /// Is the low adblue warning active?
711 ///
712 /// Type: bool
713 pub const ADBLUE_WARNING: Channel<bool> =
714 Channel::new(c"truck.adblue.warning", ETS2_ONLY_1_12);
715
716 /// Average consumption of the adblue in liters/km
717 ///
718 /// Type: float
719 pub const ADBLUE_AVERAGE_CONSUMPTION: Channel<f32> =
720 Channel::new(c"truck.adblue.consumption.average", ETS2_ONLY_1_12);
721
722 /// Pressure of the oil in psi
723 ///
724 /// Type: float
725 pub const OIL_PRESSURE: Channel<f32> = Channel::new(c"truck.oil.pressure", INITIAL);
726
727 /// Is the oil pressure warning active?
728 ///
729 /// Type: bool
730 pub const OIL_PRESSURE_WARNING: Channel<bool> =
731 Channel::new(c"truck.oil.pressure.warning", INITIAL);
732
733 /// Temperature of the oil in degrees celsius.
734 ///
735 /// Type: float
736 pub const OIL_TEMPERATURE: Channel<f32> = Channel::new(c"truck.oil.temperature", INITIAL);
737
738 /// Temperature of the water in degrees celsius.
739 ///
740 /// Type: float
741 pub const WATER_TEMPERATURE: Channel<f32> =
742 Channel::new(c"truck.water.temperature", INITIAL);
743
744 /// Is the water temperature warning active?
745 ///
746 /// Type: bool
747 pub const WATER_TEMPERATURE_WARNING: Channel<bool> =
748 Channel::new(c"truck.water.temperature.warning", INITIAL);
749
750 /// Voltage of the battery in volts.
751 ///
752 /// Type: float
753 pub const BATTERY_VOLTAGE: Channel<f32> = Channel::new(c"truck.battery.voltage", INITIAL);
754
755 /// Is the battery voltage/not charging warning active?
756 ///
757 /// Type: bool
758 pub const BATTERY_VOLTAGE_WARNING: Channel<bool> =
759 Channel::new(c"truck.battery.voltage.warning", INITIAL);
760
761 /// Is the electric enabled?
762 ///
763 /// Type: bool
764 pub const ELECTRIC_ENABLED: Channel<bool> =
765 Channel::new(c"truck.electric.enabled", INITIAL);
766
767 /// Is the engine enabled?
768 ///
769 /// Type: bool
770 pub const ENGINE_ENABLED: Channel<bool> = Channel::new(c"truck.engine.enabled", INITIAL);
771
772 /// Is the left blinker enabled?
773 ///
774 /// This represents the logical enable state of the blinker. It
775 /// it is true as long the blinker is enabled regardless of the
776 /// physical enabled state of the light (i.e. it does not blink
777 /// and ignores enable state of electric).
778 ///
779 /// Type: bool
780 pub const LBLINKER: Channel<bool> = Channel::new(c"truck.lblinker", INITIAL);
781
782 /// Is the right blinker enabled?
783 ///
784 /// This represents the logical enable state of the blinker. It
785 /// it is true as long the blinker is enabled regardless of the
786 /// physical enabled state of the light (i.e. it does not blink
787 /// and ignores enable state of electric).
788 ///
789 /// Type: bool
790 pub const RBLINKER: Channel<bool> = Channel::new(c"truck.rblinker", INITIAL);
791
792 /// Are the hazard warning light enabled?
793 ///
794 /// This represents the logical enable state of the hazard warning.
795 /// It it is true as long it is enabled regardless of the physical
796 /// enabled state of the light (i.e. it does not blink).
797 ///
798 /// Type: bool
799 pub const HAZARD_WARNING: Channel<bool> =
800 Channel::new(c"truck.hazard.warning", ETS2_1_17_ATS_1_04);
801
802 /// Is the light in the left blinker currently on?
803 ///
804 /// Type: bool
805 pub const LIGHT_LBLINKER: Channel<bool> =
806 Channel::new(c"truck.light.lblinker", ETS2_1_04_ATS_1_00);
807
808 /// Is the light in the right blinker currently on?
809 ///
810 /// Type: bool
811 pub const LIGHT_RBLINKER: Channel<bool> =
812 Channel::new(c"truck.light.rblinker", ETS2_1_04_ATS_1_00);
813
814 /// Are the parking lights enabled?
815 ///
816 /// Type: bool
817 pub const LIGHT_PARKING: Channel<bool> = Channel::new(c"truck.light.parking", INITIAL);
818
819 /// Are the low beam lights enabled?
820 ///
821 /// Type: bool
822 pub const LIGHT_LOW_BEAM: Channel<bool> = Channel::new(c"truck.light.beam.low", INITIAL);
823
824 /// Are the high beam lights enabled?
825 ///
826 /// Type: bool
827 pub const LIGHT_HIGH_BEAM: Channel<bool> = Channel::new(c"truck.light.beam.high", INITIAL);
828
829 /// Are the auxiliary front lights active?
830 ///
831 /// Those lights have several intensity levels:
832 /// - 1 - dimmed state
833 /// - 2 - full state
834 ///
835 /// Type: u32
836 pub const LIGHT_AUX_FRONT: Channel<u32> = Channel::new(c"truck.light.aux.front", INITIAL);
837
838 /// Are the auxiliary roof lights active?
839 ///
840 /// Those lights have several intensity levels:
841 /// - 1 - dimmed state
842 /// - 2 - full state
843 ///
844 /// Type: u32
845 pub const LIGHT_AUX_ROOF: Channel<u32> = Channel::new(c"truck.light.aux.roof", INITIAL);
846
847 /// Are the beacon lights enabled?
848 ///
849 /// Type: bool
850 pub const LIGHT_BEACON: Channel<bool> = Channel::new(c"truck.light.beacon", INITIAL);
851
852 /// Is the brake light active?
853 ///
854 /// Type: bool
855 pub const LIGHT_BRAKE: Channel<bool> = Channel::new(c"truck.light.brake", INITIAL);
856
857 /// Is the reverse light active?
858 ///
859 /// Type: bool
860 pub const LIGHT_REVERSE: Channel<bool> = Channel::new(c"truck.light.reverse", INITIAL);
861
862 /// Are the wipers enabled?
863 ///
864 /// Type: bool
865 pub const WIPERS: Channel<bool> = Channel::new(c"truck.wipers", INITIAL);
866
867 /// Intensity of the dashboard backlight as factor <0;1>
868 ///
869 /// Type: float
870 pub const DASHBOARD_BACKLIGHT: Channel<f32> =
871 Channel::new(c"truck.dashboard.backlight", INITIAL);
872
873 /// Is the differential lock enabled?
874 ///
875 /// Type: bool
876 pub const DIFFERENTIAL_LOCK: Channel<bool> =
877 Channel::new(c"truck.differential_lock", ETS2_1_17_ATS_1_04);
878
879 /// Is the lift axle control set to lifted state?
880 ///
881 /// Type: bool
882 pub const LIFT_AXLE: Channel<bool> = Channel::new(c"truck.lift_axle", ETS2_1_17_ATS_1_04);
883
884 /// Is the lift axle indicator lit?
885 ///
886 /// Type: bool
887 pub const LIFT_AXLE_INDICATOR: Channel<bool> =
888 Channel::new(c"truck.lift_axle.indicator", ETS2_1_17_ATS_1_04);
889
890 /// Is the trailer lift axle control set to lifted state?
891 ///
892 /// Type: bool
893 pub const TRAILER_LIFT_AXLE: Channel<bool> =
894 Channel::new(c"truck.trailer.lift_axle", ETS2_1_17_ATS_1_04);
895
896 /// Is the trailer lift axle indicator lit?
897 ///
898 /// Type: bool
899 pub const TRAILER_LIFT_AXLE_INDICATOR: Channel<bool> =
900 Channel::new(c"truck.trailer.lift_axle.indicator", ETS2_1_17_ATS_1_04);
901
902 /// Wear of the engine accessory as <0;1>
903 ///
904 /// Type: float
905 pub const WEAR_ENGINE: Channel<f32> = Channel::new(c"truck.wear.engine", INITIAL);
906
907 /// Wear of the transmission accessory as <0;1>
908 ///
909 /// Type: float
910 pub const WEAR_TRANSMISSION: Channel<f32> =
911 Channel::new(c"truck.wear.transmission", INITIAL);
912
913 /// Wear of the cabin accessory as <0;1>
914 ///
915 /// Type: float
916 pub const WEAR_CABIN: Channel<f32> = Channel::new(c"truck.wear.cabin", INITIAL);
917
918 /// Wear of the chassis accessory as <0;1>
919 ///
920 /// Type: float
921 pub const WEAR_CHASSIS: Channel<f32> = Channel::new(c"truck.wear.chassis", INITIAL);
922
923 /// Average wear across the wheel accessories as <0;1>
924 ///
925 /// Type: float
926 pub const WEAR_WHEELS: Channel<f32> = Channel::new(c"truck.wear.wheels", INITIAL);
927
928 /// The value of the odometer in km.
929 ///
930 /// Type: float
931 pub const ODOMETER: Channel<f32> = Channel::new(c"truck.odometer", INITIAL);
932
933 /// The value of truck's navigation distance (in meters).
934 ///
935 /// This is the value used by the advisor.
936 ///
937 /// Type: float
938 pub const NAVIGATION_DISTANCE: Channel<f32> =
939 Channel::new(c"truck.navigation.distance", ETS2_1_12_ATS_1_00);
940
941 /// The value of truck's navigation eta (in second).
942 ///
943 /// This is the value used by the advisor.
944 ///
945 /// Type: float
946 pub const NAVIGATION_TIME: Channel<f32> =
947 Channel::new(c"truck.navigation.time", ETS2_1_12_ATS_1_00);
948
949 /// The value of truck's navigation speed limit (in m/s).
950 ///
951 /// This is the value used by the advisor and respects the
952 /// current state of the "Route Advisor speed limit" option.
953 ///
954 /// Type: float
955 pub const NAVIGATION_SPEED_LIMIT: Channel<f32> =
956 Channel::new(c"truck.navigation.speed.limit", ETS2_1_12_ATS_1_00);
957
958 /// Vertical displacement of the wheel from its
959 /// axis in meters.
960 ///
961 /// Type: indexed float
962 pub const WHEEL_SUSP_DEFLECTION: Channel<f32> =
963 Channel::indexed(c"truck.wheel.suspension.deflection", INITIAL);
964
965 /// Is the wheel in contact with ground?
966 ///
967 /// Type: indexed bool
968 pub const WHEEL_ON_GROUND: Channel<bool> =
969 Channel::indexed(c"truck.wheel.on_ground", INITIAL);
970
971 /// Substance below the whell.
972 ///
973 /// Index of substance as delivered trough SUBSTANCE config.
974 ///
975 /// Type: indexed u32
976 pub const WHEEL_SUBSTANCE: Channel<u32> =
977 Channel::indexed(c"truck.wheel.substance", INITIAL);
978
979 /// Angular velocity of the wheel in rotations per
980 /// second.
981 ///
982 /// Positive velocity corresponds to forward movement.
983 ///
984 /// Type: indexed float
985 pub const WHEEL_VELOCITY: Channel<f32> =
986 Channel::indexed(c"truck.wheel.angular_velocity", INITIAL);
987
988 /// Steering rotation of the wheel in rotations.
989 ///
990 /// Value is from <-0.25,0.25> range in counterclockwise direction
991 /// when looking from top (e.g. 0.25 corresponds to left and
992 /// -0.25 corresponds to right).
993 ///
994 /// Set to zero for non-steered wheels.
995 ///
996 /// Type: indexed float
997 pub const WHEEL_STEERING: Channel<f32> = Channel::indexed(c"truck.wheel.steering", INITIAL);
998
999 /// Rolling rotation of the wheel in rotations.
1000 ///
1001 /// Value is from <0.0,1.0) range in which value
1002 /// increase corresponds to forward movement.
1003 ///
1004 /// Type: indexed float
1005 pub const WHEEL_ROTATION: Channel<f32> = Channel::indexed(c"truck.wheel.rotation", INITIAL);
1006
1007 /// Lift state of the wheel <0;1>
1008 ///
1009 /// For use with simple lifted/non-lifted test or logical
1010 /// visualization of the lifting progress.
1011 ///
1012 /// Value of 0 corresponds to non-lifted axle.
1013 /// Value of 1 corresponds to fully lifted axle.
1014 ///
1015 /// Set to zero or not provided for non-liftable axles.
1016 ///
1017 /// Type: indexed float
1018 pub const WHEEL_LIFT: Channel<f32> =
1019 Channel::indexed(c"truck.wheel.lift", ETS2_1_10_ATS_1_00);
1020
1021 /// Vertical displacement of the wheel axle
1022 /// from its normal position in meters as result of
1023 /// lifting.
1024 ///
1025 /// Might have non-linear relation to lift ratio.
1026 ///
1027 /// Set to zero or not provided for non-liftable axles.
1028 ///
1029 /// Type: indexed float
1030 pub const WHEEL_LIFT_OFFSET: Channel<f32> =
1031 Channel::indexed(c"truck.wheel.lift.offset", ETS2_1_10_ATS_1_00);
1032
1033 /// Every truck channel in the order used by the SDK 1.14 header.
1034 ///
1035 /// Indexed wheel and H-shifter entries keep `is_indexed() == true`;
1036 /// the array itself never supplies or guesses a runtime index.
1037 pub const ALL: [AnyChannel; COUNT] = [
1038 WORLD_PLACEMENT.erase(),
1039 LOCAL_LINEAR_VELOCITY.erase(),
1040 LOCAL_ANGULAR_VELOCITY.erase(),
1041 LOCAL_LINEAR_ACCELERATION.erase(),
1042 LOCAL_ANGULAR_ACCELERATION.erase(),
1043 CABIN_OFFSET.erase(),
1044 CABIN_ANGULAR_VELOCITY.erase(),
1045 CABIN_ANGULAR_ACCELERATION.erase(),
1046 HEAD_OFFSET.erase(),
1047 SPEED.erase(),
1048 ENGINE_RPM.erase(),
1049 ENGINE_GEAR.erase(),
1050 DISPLAYED_GEAR.erase(),
1051 INPUT_STEERING.erase(),
1052 INPUT_THROTTLE.erase(),
1053 INPUT_BRAKE.erase(),
1054 INPUT_CLUTCH.erase(),
1055 EFFECTIVE_STEERING.erase(),
1056 EFFECTIVE_THROTTLE.erase(),
1057 EFFECTIVE_BRAKE.erase(),
1058 EFFECTIVE_CLUTCH.erase(),
1059 CRUISE_CONTROL.erase(),
1060 HSHIFTER_SLOT.erase(),
1061 HSHIFTER_SELECTOR.erase(),
1062 PARKING_BRAKE.erase(),
1063 MOTOR_BRAKE.erase(),
1064 RETARDER_LEVEL.erase(),
1065 BRAKE_AIR_PRESSURE.erase(),
1066 BRAKE_AIR_PRESSURE_WARNING.erase(),
1067 BRAKE_AIR_PRESSURE_EMERGENCY.erase(),
1068 BRAKE_TEMPERATURE.erase(),
1069 FUEL.erase(),
1070 FUEL_WARNING.erase(),
1071 FUEL_AVERAGE_CONSUMPTION.erase(),
1072 FUEL_RANGE.erase(),
1073 ADBLUE.erase(),
1074 ADBLUE_WARNING.erase(),
1075 ADBLUE_AVERAGE_CONSUMPTION.erase(),
1076 OIL_PRESSURE.erase(),
1077 OIL_PRESSURE_WARNING.erase(),
1078 OIL_TEMPERATURE.erase(),
1079 WATER_TEMPERATURE.erase(),
1080 WATER_TEMPERATURE_WARNING.erase(),
1081 BATTERY_VOLTAGE.erase(),
1082 BATTERY_VOLTAGE_WARNING.erase(),
1083 ELECTRIC_ENABLED.erase(),
1084 ENGINE_ENABLED.erase(),
1085 LBLINKER.erase(),
1086 RBLINKER.erase(),
1087 HAZARD_WARNING.erase(),
1088 LIGHT_LBLINKER.erase(),
1089 LIGHT_RBLINKER.erase(),
1090 LIGHT_PARKING.erase(),
1091 LIGHT_LOW_BEAM.erase(),
1092 LIGHT_HIGH_BEAM.erase(),
1093 LIGHT_AUX_FRONT.erase(),
1094 LIGHT_AUX_ROOF.erase(),
1095 LIGHT_BEACON.erase(),
1096 LIGHT_BRAKE.erase(),
1097 LIGHT_REVERSE.erase(),
1098 WIPERS.erase(),
1099 DASHBOARD_BACKLIGHT.erase(),
1100 DIFFERENTIAL_LOCK.erase(),
1101 LIFT_AXLE.erase(),
1102 LIFT_AXLE_INDICATOR.erase(),
1103 TRAILER_LIFT_AXLE.erase(),
1104 TRAILER_LIFT_AXLE_INDICATOR.erase(),
1105 WEAR_ENGINE.erase(),
1106 WEAR_TRANSMISSION.erase(),
1107 WEAR_CABIN.erase(),
1108 WEAR_CHASSIS.erase(),
1109 WEAR_WHEELS.erase(),
1110 ODOMETER.erase(),
1111 NAVIGATION_DISTANCE.erase(),
1112 NAVIGATION_TIME.erase(),
1113 NAVIGATION_SPEED_LIMIT.erase(),
1114 WHEEL_SUSP_DEFLECTION.erase(),
1115 WHEEL_ON_GROUND.erase(),
1116 WHEEL_SUBSTANCE.erase(),
1117 WHEEL_VELOCITY.erase(),
1118 WHEEL_STEERING.erase(),
1119 WHEEL_ROTATION.erase(),
1120 WHEEL_LIFT.erase(),
1121 WHEEL_LIFT_OFFSET.erase(),
1122 ];
1123 }
1124
1125 /// Channels declared by `scssdk_telemetry_trailer_common_channels.h`.
1126 pub mod trailer {
1127 use super::super::{AnyChannel, Channel};
1128 use super::{ETS2_1_14_ATS_1_01, ETS2_1_18_ATS_1_05, INITIAL};
1129
1130 /// Number of typed descriptors in this catalog group.
1131 pub const COUNT: usize = 18;
1132
1133 /// Is the trailer connected to the truck?
1134 ///
1135 /// Type: bool
1136 ///
1137 /// For trailer indices above zero, the plugin framework derives the
1138 /// `trailer.[index].*` channel name described by the official SDK.
1139 pub const CONNECTED: Channel<bool> = Channel::new(c"trailer.connected", INITIAL);
1140
1141 /// How much is the cargo damaged that is loaded to this trailer in <0.0, 1.0> range.
1142 ///
1143 /// Type: float
1144 ///
1145 /// For trailer indices above zero, the plugin framework derives the
1146 /// `trailer.[index].*` channel name described by the official SDK.
1147 pub const CARGO_DAMAGE: Channel<f32> =
1148 Channel::new(c"trailer.cargo.damage", ETS2_1_14_ATS_1_01);
1149
1150 /// world placement trailer telemetry.
1151 ///
1152 /// Type: dplacement
1153 ///
1154 /// For trailer indices above zero, the plugin framework derives the
1155 /// `trailer.[index].*` channel name described by the official SDK.
1156 pub const WORLD_PLACEMENT: Channel<crate::DPlacement> =
1157 Channel::new(c"trailer.world.placement", INITIAL);
1158
1159 /// local linear velocity trailer telemetry.
1160 ///
1161 /// Type: fvector
1162 ///
1163 /// For trailer indices above zero, the plugin framework derives the
1164 /// `trailer.[index].*` channel name described by the official SDK.
1165 pub const LOCAL_LINEAR_VELOCITY: Channel<crate::FVector> =
1166 Channel::new(c"trailer.velocity.linear", INITIAL);
1167
1168 /// local angular velocity trailer telemetry.
1169 ///
1170 /// Type: fvector
1171 ///
1172 /// For trailer indices above zero, the plugin framework derives the
1173 /// `trailer.[index].*` channel name described by the official SDK.
1174 pub const LOCAL_ANGULAR_VELOCITY: Channel<crate::FVector> =
1175 Channel::new(c"trailer.velocity.angular", INITIAL);
1176
1177 /// local linear acceleration trailer telemetry.
1178 ///
1179 /// Type: fvector
1180 ///
1181 /// For trailer indices above zero, the plugin framework derives the
1182 /// `trailer.[index].*` channel name described by the official SDK.
1183 pub const LOCAL_LINEAR_ACCELERATION: Channel<crate::FVector> =
1184 Channel::new(c"trailer.acceleration.linear", INITIAL);
1185
1186 /// local angular acceleration trailer telemetry.
1187 ///
1188 /// Type: fvector
1189 ///
1190 /// For trailer indices above zero, the plugin framework derives the
1191 /// `trailer.[index].*` channel name described by the official SDK.
1192 pub const LOCAL_ANGULAR_ACCELERATION: Channel<crate::FVector> =
1193 Channel::new(c"trailer.acceleration.angular", INITIAL);
1194
1195 /// wear body trailer telemetry.
1196 ///
1197 /// Type: float
1198 ///
1199 /// For trailer indices above zero, the plugin framework derives the
1200 /// `trailer.[index].*` channel name described by the official SDK.
1201 pub const WEAR_BODY: Channel<f32> = Channel::new(c"trailer.wear.body", ETS2_1_18_ATS_1_05);
1202
1203 /// wear chassis trailer telemetry.
1204 ///
1205 /// Type: float
1206 ///
1207 /// For trailer indices above zero, the plugin framework derives the
1208 /// `trailer.[index].*` channel name described by the official SDK.
1209 pub const WEAR_CHASSIS: Channel<f32> = Channel::new(c"trailer.wear.chassis", INITIAL);
1210
1211 /// wear wheels trailer telemetry.
1212 ///
1213 /// Type: float
1214 ///
1215 /// For trailer indices above zero, the plugin framework derives the
1216 /// `trailer.[index].*` channel name described by the official SDK.
1217 pub const WEAR_WHEELS: Channel<f32> =
1218 Channel::new(c"trailer.wear.wheels", ETS2_1_14_ATS_1_01);
1219
1220 /// wheel susp deflection trailer telemetry.
1221 ///
1222 /// Type: indexed float
1223 ///
1224 /// For trailer indices above zero, the plugin framework derives the
1225 /// `trailer.[index].*` channel name described by the official SDK.
1226 pub const WHEEL_SUSP_DEFLECTION: Channel<f32> =
1227 Channel::indexed(c"trailer.wheel.suspension.deflection", INITIAL);
1228
1229 /// wheel on ground trailer telemetry.
1230 ///
1231 /// Type: indexed bool
1232 ///
1233 /// For trailer indices above zero, the plugin framework derives the
1234 /// `trailer.[index].*` channel name described by the official SDK.
1235 pub const WHEEL_ON_GROUND: Channel<bool> =
1236 Channel::indexed(c"trailer.wheel.on_ground", INITIAL);
1237
1238 /// wheel substance trailer telemetry.
1239 ///
1240 /// Type: indexed u32
1241 ///
1242 /// For trailer indices above zero, the plugin framework derives the
1243 /// `trailer.[index].*` channel name described by the official SDK.
1244 pub const WHEEL_SUBSTANCE: Channel<u32> =
1245 Channel::indexed(c"trailer.wheel.substance", INITIAL);
1246
1247 /// wheel velocity trailer telemetry.
1248 ///
1249 /// Type: indexed float
1250 ///
1251 /// For trailer indices above zero, the plugin framework derives the
1252 /// `trailer.[index].*` channel name described by the official SDK.
1253 pub const WHEEL_VELOCITY: Channel<f32> =
1254 Channel::indexed(c"trailer.wheel.angular_velocity", INITIAL);
1255
1256 /// wheel steering trailer telemetry.
1257 ///
1258 /// Type: indexed float
1259 ///
1260 /// For trailer indices above zero, the plugin framework derives the
1261 /// `trailer.[index].*` channel name described by the official SDK.
1262 pub const WHEEL_STEERING: Channel<f32> =
1263 Channel::indexed(c"trailer.wheel.steering", INITIAL);
1264
1265 /// wheel rotation trailer telemetry.
1266 ///
1267 /// Type: indexed float
1268 ///
1269 /// For trailer indices above zero, the plugin framework derives the
1270 /// `trailer.[index].*` channel name described by the official SDK.
1271 pub const WHEEL_ROTATION: Channel<f32> =
1272 Channel::indexed(c"trailer.wheel.rotation", INITIAL);
1273
1274 /// wheel lift trailer telemetry.
1275 ///
1276 /// Type: indexed float
1277 ///
1278 /// For trailer indices above zero, the plugin framework derives the
1279 /// `trailer.[index].*` channel name described by the official SDK.
1280 pub const WHEEL_LIFT: Channel<f32> =
1281 Channel::indexed(c"trailer.wheel.lift", ETS2_1_14_ATS_1_01);
1282
1283 /// wheel lift offset trailer telemetry.
1284 ///
1285 /// Type: indexed float
1286 ///
1287 /// For trailer indices above zero, the plugin framework derives the
1288 /// `trailer.[index].*` channel name described by the official SDK.
1289 pub const WHEEL_LIFT_OFFSET: Channel<f32> =
1290 Channel::indexed(c"trailer.wheel.lift.offset", ETS2_1_14_ATS_1_01);
1291
1292 /// Every first-trailer channel in SDK 1.14 header order.
1293 ///
1294 /// These canonical names use the backward-compatible `trailer.*`
1295 /// form. Multi-trailer subscription remains an explicit framework
1296 /// operation which derives `trailer.[index].*` for indices 0 through
1297 /// 9; catalog enumeration itself performs no such expansion.
1298 pub const ALL: [AnyChannel; COUNT] = [
1299 CONNECTED.erase(),
1300 CARGO_DAMAGE.erase(),
1301 WORLD_PLACEMENT.erase(),
1302 LOCAL_LINEAR_VELOCITY.erase(),
1303 LOCAL_ANGULAR_VELOCITY.erase(),
1304 LOCAL_LINEAR_ACCELERATION.erase(),
1305 LOCAL_ANGULAR_ACCELERATION.erase(),
1306 WEAR_BODY.erase(),
1307 WEAR_CHASSIS.erase(),
1308 WEAR_WHEELS.erase(),
1309 WHEEL_SUSP_DEFLECTION.erase(),
1310 WHEEL_ON_GROUND.erase(),
1311 WHEEL_SUBSTANCE.erase(),
1312 WHEEL_VELOCITY.erase(),
1313 WHEEL_STEERING.erase(),
1314 WHEEL_ROTATION.erase(),
1315 WHEEL_LIFT.erase(),
1316 WHEEL_LIFT_OFFSET.erase(),
1317 ];
1318 }
1319
1320 /// Channels declared by `scssdk_telemetry_job_common_channels.h`.
1321 pub mod job {
1322 use super::super::{AnyChannel, Channel};
1323 use super::ETS2_1_14_ATS_1_01;
1324
1325 /// Number of typed descriptors in this catalog group.
1326 pub const COUNT: usize = 1;
1327
1328 /// The total damage of the cargo in range 0.0 to 1.0.
1329 ///
1330 /// Type: float
1331 pub const CARGO_DAMAGE: Channel<f32> =
1332 Channel::new(c"job.cargo.damage", ETS2_1_14_ATS_1_01);
1333
1334 /// Every job channel in SDK 1.14 header order.
1335 pub const ALL: [AnyChannel; COUNT] = [CARGO_DAMAGE.erase()];
1336 }
1337
1338 /// Total number of typed descriptors in the catalog.
1339 pub const COUNT: usize = common::COUNT + truck::COUNT + trailer::COUNT + job::COUNT;
1340
1341 /// Every public telemetry channel from the SDK 1.14 header bundle.
1342 ///
1343 /// Entries follow header grouping and declaration order: common, truck,
1344 /// trailer, then job. The catalog is descriptive only. Merely iterating it
1345 /// never registers anything; plugin code must still call the appropriate
1346 /// explicit `PluginContext::subscribe*` method for every desired channel,
1347 /// index, trailer number, delivery flag, and requested representation.
1348 pub const ALL: [AnyChannel; COUNT] = [
1349 common::LOCAL_SCALE.erase(),
1350 common::GAME_TIME.erase(),
1351 common::MULTIPLAYER_TIME_OFFSET.erase(),
1352 common::NEXT_REST_STOP.erase(),
1353 truck::WORLD_PLACEMENT.erase(),
1354 truck::LOCAL_LINEAR_VELOCITY.erase(),
1355 truck::LOCAL_ANGULAR_VELOCITY.erase(),
1356 truck::LOCAL_LINEAR_ACCELERATION.erase(),
1357 truck::LOCAL_ANGULAR_ACCELERATION.erase(),
1358 truck::CABIN_OFFSET.erase(),
1359 truck::CABIN_ANGULAR_VELOCITY.erase(),
1360 truck::CABIN_ANGULAR_ACCELERATION.erase(),
1361 truck::HEAD_OFFSET.erase(),
1362 truck::SPEED.erase(),
1363 truck::ENGINE_RPM.erase(),
1364 truck::ENGINE_GEAR.erase(),
1365 truck::DISPLAYED_GEAR.erase(),
1366 truck::INPUT_STEERING.erase(),
1367 truck::INPUT_THROTTLE.erase(),
1368 truck::INPUT_BRAKE.erase(),
1369 truck::INPUT_CLUTCH.erase(),
1370 truck::EFFECTIVE_STEERING.erase(),
1371 truck::EFFECTIVE_THROTTLE.erase(),
1372 truck::EFFECTIVE_BRAKE.erase(),
1373 truck::EFFECTIVE_CLUTCH.erase(),
1374 truck::CRUISE_CONTROL.erase(),
1375 truck::HSHIFTER_SLOT.erase(),
1376 truck::HSHIFTER_SELECTOR.erase(),
1377 truck::PARKING_BRAKE.erase(),
1378 truck::MOTOR_BRAKE.erase(),
1379 truck::RETARDER_LEVEL.erase(),
1380 truck::BRAKE_AIR_PRESSURE.erase(),
1381 truck::BRAKE_AIR_PRESSURE_WARNING.erase(),
1382 truck::BRAKE_AIR_PRESSURE_EMERGENCY.erase(),
1383 truck::BRAKE_TEMPERATURE.erase(),
1384 truck::FUEL.erase(),
1385 truck::FUEL_WARNING.erase(),
1386 truck::FUEL_AVERAGE_CONSUMPTION.erase(),
1387 truck::FUEL_RANGE.erase(),
1388 truck::ADBLUE.erase(),
1389 truck::ADBLUE_WARNING.erase(),
1390 truck::ADBLUE_AVERAGE_CONSUMPTION.erase(),
1391 truck::OIL_PRESSURE.erase(),
1392 truck::OIL_PRESSURE_WARNING.erase(),
1393 truck::OIL_TEMPERATURE.erase(),
1394 truck::WATER_TEMPERATURE.erase(),
1395 truck::WATER_TEMPERATURE_WARNING.erase(),
1396 truck::BATTERY_VOLTAGE.erase(),
1397 truck::BATTERY_VOLTAGE_WARNING.erase(),
1398 truck::ELECTRIC_ENABLED.erase(),
1399 truck::ENGINE_ENABLED.erase(),
1400 truck::LBLINKER.erase(),
1401 truck::RBLINKER.erase(),
1402 truck::HAZARD_WARNING.erase(),
1403 truck::LIGHT_LBLINKER.erase(),
1404 truck::LIGHT_RBLINKER.erase(),
1405 truck::LIGHT_PARKING.erase(),
1406 truck::LIGHT_LOW_BEAM.erase(),
1407 truck::LIGHT_HIGH_BEAM.erase(),
1408 truck::LIGHT_AUX_FRONT.erase(),
1409 truck::LIGHT_AUX_ROOF.erase(),
1410 truck::LIGHT_BEACON.erase(),
1411 truck::LIGHT_BRAKE.erase(),
1412 truck::LIGHT_REVERSE.erase(),
1413 truck::WIPERS.erase(),
1414 truck::DASHBOARD_BACKLIGHT.erase(),
1415 truck::DIFFERENTIAL_LOCK.erase(),
1416 truck::LIFT_AXLE.erase(),
1417 truck::LIFT_AXLE_INDICATOR.erase(),
1418 truck::TRAILER_LIFT_AXLE.erase(),
1419 truck::TRAILER_LIFT_AXLE_INDICATOR.erase(),
1420 truck::WEAR_ENGINE.erase(),
1421 truck::WEAR_TRANSMISSION.erase(),
1422 truck::WEAR_CABIN.erase(),
1423 truck::WEAR_CHASSIS.erase(),
1424 truck::WEAR_WHEELS.erase(),
1425 truck::ODOMETER.erase(),
1426 truck::NAVIGATION_DISTANCE.erase(),
1427 truck::NAVIGATION_TIME.erase(),
1428 truck::NAVIGATION_SPEED_LIMIT.erase(),
1429 truck::WHEEL_SUSP_DEFLECTION.erase(),
1430 truck::WHEEL_ON_GROUND.erase(),
1431 truck::WHEEL_SUBSTANCE.erase(),
1432 truck::WHEEL_VELOCITY.erase(),
1433 truck::WHEEL_STEERING.erase(),
1434 truck::WHEEL_ROTATION.erase(),
1435 truck::WHEEL_LIFT.erase(),
1436 truck::WHEEL_LIFT_OFFSET.erase(),
1437 trailer::CONNECTED.erase(),
1438 trailer::CARGO_DAMAGE.erase(),
1439 trailer::WORLD_PLACEMENT.erase(),
1440 trailer::LOCAL_LINEAR_VELOCITY.erase(),
1441 trailer::LOCAL_ANGULAR_VELOCITY.erase(),
1442 trailer::LOCAL_LINEAR_ACCELERATION.erase(),
1443 trailer::LOCAL_ANGULAR_ACCELERATION.erase(),
1444 trailer::WEAR_BODY.erase(),
1445 trailer::WEAR_CHASSIS.erase(),
1446 trailer::WEAR_WHEELS.erase(),
1447 trailer::WHEEL_SUSP_DEFLECTION.erase(),
1448 trailer::WHEEL_ON_GROUND.erase(),
1449 trailer::WHEEL_SUBSTANCE.erase(),
1450 trailer::WHEEL_VELOCITY.erase(),
1451 trailer::WHEEL_STEERING.erase(),
1452 trailer::WHEEL_ROTATION.erase(),
1453 trailer::WHEEL_LIFT.erase(),
1454 trailer::WHEEL_LIFT_OFFSET.erase(),
1455 job::CARGO_DAMAGE.erase(),
1456 ];
1457
1458 pub use common::{GAME_TIME, LOCAL_SCALE, MULTIPLAYER_TIME_OFFSET, NEXT_REST_STOP};
1459 pub use job::CARGO_DAMAGE as JOB_CARGO_DAMAGE;
1460 pub use truck::{
1461 ENGINE_GEAR as TRUCK_ENGINE_GEAR, ENGINE_RPM as TRUCK_ENGINE_RPM,
1462 NAVIGATION_DISTANCE as TRUCK_NAVIGATION_DISTANCE,
1463 NAVIGATION_SPEED_LIMIT as TRUCK_NAVIGATION_SPEED_LIMIT,
1464 NAVIGATION_TIME as TRUCK_NAVIGATION_TIME, SPEED as TRUCK_SPEED,
1465 WORLD_PLACEMENT as TRUCK_WORLD_PLACEMENT,
1466 };
1467
1468 const _: [(); 107] = [(); COUNT];
1469}
1470
1471#[cfg(test)]
1472mod tests {
1473 use super::*;
1474 use crate::GameSchemaVersion;
1475
1476 fn assert_since<T: ChannelValue>(
1477 channel: Channel<T>,
1478 ets2: Option<GameSchemaVersion>,
1479 ats: Option<GameSchemaVersion>,
1480 ) {
1481 assert_eq!(
1482 channel.availability().available_since_ets2(),
1483 ets2,
1484 "{:?}",
1485 channel.name()
1486 );
1487 assert_eq!(
1488 channel.availability().available_since_ats(),
1489 ats,
1490 "{:?}",
1491 channel.name()
1492 );
1493 }
1494
1495 fn assert_catalog_matches_raw(typed: &[AnyChannel], raw: &[&[u8]]) {
1496 assert_eq!(typed.len(), raw.len());
1497 for (descriptor, raw_name) in typed.iter().zip(raw) {
1498 assert_eq!(descriptor.name().to_bytes_with_nul(), *raw_name);
1499 }
1500 }
1501
1502 #[test]
1503 fn typed_channels_select_the_sdk_value_type() {
1504 assert_eq!(
1505 channels::TRUCK_SPEED.value_type(),
1506 sys::SCS_VALUE_TYPE_FLOAT
1507 );
1508 assert_eq!(
1509 channels::TRUCK_ENGINE_GEAR.value_type(),
1510 sys::SCS_VALUE_TYPE_S32
1511 );
1512 assert_eq!(
1513 channels::TRUCK_WORLD_PLACEMENT.value_type(),
1514 sys::SCS_VALUE_TYPE_DPLACEMENT
1515 );
1516 }
1517
1518 #[test]
1519 fn channel_flags_match_the_header_bits() {
1520 assert_eq!(ChannelFlags::EACH_FRAME.bits(), 1);
1521 assert_eq!(ChannelFlags::NO_VALUE.bits(), 2);
1522 assert_eq!(
1523 (ChannelFlags::EACH_FRAME | ChannelFlags::NO_VALUE).bits(),
1524 3
1525 );
1526 }
1527
1528 #[test]
1529 fn typed_catalog_counts_match_the_raw_sdk_catalog() {
1530 assert_eq!(channels::common::COUNT, sys::channels::common::COUNT);
1531 assert_eq!(channels::truck::COUNT, sys::channels::truck::COUNT);
1532 assert_eq!(channels::trailer::COUNT, sys::channels::trailer::COUNT);
1533 assert_eq!(channels::job::COUNT, sys::channels::job::COUNT);
1534 assert_eq!(channels::COUNT, sys::channels::COUNT);
1535 assert_eq!(channels::COUNT, 107);
1536 }
1537
1538 #[test]
1539 fn every_typed_channel_matches_the_raw_header_catalog() {
1540 assert_catalog_matches_raw(&channels::common::ALL, &sys::channels::common::ALL);
1541 assert_catalog_matches_raw(&channels::truck::ALL, &sys::channels::truck::ALL);
1542 assert_catalog_matches_raw(&channels::trailer::ALL, &sys::channels::trailer::ALL);
1543 assert_catalog_matches_raw(&channels::job::ALL, &sys::channels::job::ALL);
1544
1545 let groups = [
1546 channels::common::ALL.as_slice(),
1547 channels::truck::ALL.as_slice(),
1548 channels::trailer::ALL.as_slice(),
1549 channels::job::ALL.as_slice(),
1550 ];
1551 let mut offset = 0;
1552 for group in groups {
1553 let end = offset + group.len();
1554 assert_eq!(&channels::ALL[offset..end], group);
1555 offset = end;
1556 }
1557 assert_eq!(offset, channels::COUNT);
1558
1559 for (position, descriptor) in channels::ALL.iter().enumerate() {
1560 assert!(
1561 channels::ALL[..position]
1562 .iter()
1563 .all(|earlier| earlier.name() != descriptor.name()),
1564 "duplicate channel descriptor: {:?}",
1565 descriptor.name()
1566 );
1567 }
1568 assert_eq!(
1569 channels::ALL
1570 .iter()
1571 .filter(|channel| channel.is_indexed())
1572 .count(),
1573 17
1574 );
1575 }
1576
1577 #[test]
1578 fn descriptors_preserve_name_type_and_index_mode() {
1579 assert_eq!(channels::common::GAME_TIME.name(), c"game.time");
1580 assert_eq!(
1581 channels::truck::WORLD_PLACEMENT.erase(),
1582 AnyChannel {
1583 name: c"truck.world.placement",
1584 value_type: ValueType::DPlacement,
1585 indexed: false,
1586 availability: GameSchemaAvailability::new(
1587 Some(crate::game::ets2::V1_00),
1588 Some(crate::game::ats::V1_00),
1589 ),
1590 }
1591 );
1592 assert_eq!(
1593 channels::truck::WHEEL_ROTATION.erase(),
1594 AnyChannel {
1595 name: c"truck.wheel.rotation",
1596 value_type: ValueType::F32,
1597 indexed: true,
1598 availability: GameSchemaAvailability::new(
1599 Some(crate::game::ets2::V1_00),
1600 Some(crate::game::ats::V1_00),
1601 ),
1602 }
1603 );
1604 assert_eq!(
1605 channels::trailer::WHEEL_ON_GROUND.erase(),
1606 AnyChannel {
1607 name: c"trailer.wheel.on_ground",
1608 value_type: ValueType::Bool,
1609 indexed: true,
1610 availability: GameSchemaAvailability::new(
1611 Some(crate::game::ets2::V1_00),
1612 Some(crate::game::ats::V1_00),
1613 ),
1614 }
1615 );
1616 assert_eq!(channels::job::CARGO_DAMAGE.name(), c"job.cargo.damage");
1617 }
1618
1619 #[test]
1620 fn channel_availability_follows_early_game_schema_history() {
1621 use channels::{common, truck};
1622
1623 // Early ETS2 additions are preserved even though the oldest archived
1624 // downloadable bundle (SDK 1.0) already reports schema 1.05.
1625 assert_since(
1626 truck::BRAKE_AIR_PRESSURE_EMERGENCY,
1627 Some(crate::game::ets2::V1_01),
1628 Some(crate::game::ats::V1_00),
1629 );
1630 assert_since(
1631 truck::CABIN_OFFSET,
1632 Some(crate::game::ets2::V1_02),
1633 Some(crate::game::ats::V1_00),
1634 );
1635 for channel in [truck::LIGHT_LBLINKER, truck::LIGHT_RBLINKER] {
1636 assert_since(
1637 channel,
1638 Some(crate::game::ets2::V1_04),
1639 Some(crate::game::ats::V1_00),
1640 );
1641 }
1642
1643 for channel in [
1644 common::GAME_TIME.requesting::<i32>(),
1645 common::NEXT_REST_STOP,
1646 ] {
1647 assert_since(
1648 channel,
1649 Some(crate::game::ets2::V1_09),
1650 Some(crate::game::ats::V1_00),
1651 );
1652 }
1653 for channel in [truck::WHEEL_LIFT, truck::WHEEL_LIFT_OFFSET] {
1654 assert_since(
1655 channel,
1656 Some(crate::game::ets2::V1_10),
1657 Some(crate::game::ats::V1_00),
1658 );
1659 }
1660 assert_since(
1661 truck::DISPLAYED_GEAR,
1662 Some(crate::game::ets2::V1_11),
1663 Some(crate::game::ats::V1_00),
1664 );
1665 for channel in [
1666 truck::FUEL_RANGE,
1667 truck::NAVIGATION_DISTANCE,
1668 truck::NAVIGATION_TIME,
1669 truck::NAVIGATION_SPEED_LIMIT,
1670 ] {
1671 assert_since(
1672 channel,
1673 Some(crate::game::ets2::V1_12),
1674 Some(crate::game::ats::V1_00),
1675 );
1676 }
1677 for channel in [
1678 truck::ADBLUE,
1679 truck::ADBLUE_WARNING.requesting::<f32>(),
1680 truck::ADBLUE_AVERAGE_CONSUMPTION,
1681 ] {
1682 assert_since(channel, Some(crate::game::ets2::V1_12), None);
1683 }
1684 }
1685
1686 #[test]
1687 fn channel_availability_follows_later_game_schema_history() {
1688 use channels::{common, job, trailer, truck};
1689
1690 for channel in [
1691 trailer::CARGO_DAMAGE,
1692 trailer::WEAR_WHEELS,
1693 trailer::WHEEL_LIFT,
1694 trailer::WHEEL_LIFT_OFFSET,
1695 job::CARGO_DAMAGE,
1696 ] {
1697 assert_since(
1698 channel,
1699 Some(crate::game::ets2::V1_14),
1700 Some(crate::game::ats::V1_01),
1701 );
1702 }
1703 for channel in [
1704 truck::HAZARD_WARNING,
1705 truck::DIFFERENTIAL_LOCK,
1706 truck::LIFT_AXLE,
1707 truck::LIFT_AXLE_INDICATOR,
1708 truck::TRAILER_LIFT_AXLE,
1709 truck::TRAILER_LIFT_AXLE_INDICATOR,
1710 ] {
1711 assert_since(
1712 channel,
1713 Some(crate::game::ets2::V1_17),
1714 Some(crate::game::ats::V1_04),
1715 );
1716 }
1717 assert_since(
1718 common::MULTIPLAYER_TIME_OFFSET,
1719 Some(crate::game::ets2::V1_18),
1720 Some(crate::game::ats::V1_05),
1721 );
1722 assert_since(
1723 trailer::WEAR_BODY,
1724 Some(crate::game::ets2::V1_18),
1725 Some(crate::game::ats::V1_05),
1726 );
1727
1728 assert_eq!(
1729 channels::MULTI_TRAILER_AVAILABILITY,
1730 GameSchemaAvailability::new(
1731 Some(crate::game::ets2::V1_14),
1732 Some(crate::game::ats::V1_01),
1733 )
1734 );
1735 assert!(
1736 channels::ALL
1737 .iter()
1738 .all(|channel| channel.availability().available_since_ets2().is_some())
1739 );
1740 assert_eq!(
1741 channels::ALL
1742 .iter()
1743 .filter(|channel| channel.availability().available_since_ats().is_none())
1744 .count(),
1745 3,
1746 "only the three AdBlue channels are explicitly unsupported by ATS",
1747 );
1748 }
1749}