Skip to main content

nv_view/
ptz.rs

1//! PTZ telemetry types and discrete control events.
2
3use nv_core::MonotonicTs;
4
5/// Raw PTZ (Pan-Tilt-Zoom) telemetry from the camera.
6///
7/// Provided by `ViewStateProvider` implementations that have access
8/// to PTZ control systems (ONVIF, serial protocols, etc.).
9#[derive(Clone, Debug, PartialEq)]
10pub struct PtzTelemetry {
11    /// Pan angle in degrees.
12    pub pan: f32,
13    /// Tilt angle in degrees.
14    pub tilt: f32,
15    /// Zoom level, normalized to `[0, 1]` where `1` = maximum zoom.
16    pub zoom: f32,
17    /// Timestamp of this telemetry reading.
18    pub ts: MonotonicTs,
19}
20
21/// A discrete PTZ control event.
22///
23/// Models push-based PTZ control commands that the camera may receive
24/// externally (from an operator, a tour scheduler, or an API call).
25/// These supplement the polling-based [`PtzTelemetry`] with explicit
26/// causal information about **why** the camera moved.
27///
28/// Providers include these in [`MotionReport::ptz_events`](crate::MotionReport::ptz_events)
29/// when they have access to a PTZ command stream (e.g., ONVIF Events).
30#[derive(Clone, Debug, PartialEq)]
31pub enum PtzEvent {
32    /// A continuous move started (pan/tilt/zoom speeds set).
33    MoveStart {
34        /// Timestamp of the command.
35        ts: MonotonicTs,
36    },
37    /// A continuous move stopped.
38    MoveStop {
39        /// Timestamp of the command.
40        ts: MonotonicTs,
41    },
42    /// Camera moved to a preset position.
43    PresetRecall {
44        /// Numeric preset identifier.
45        preset_id: u32,
46        /// Timestamp of the command.
47        ts: MonotonicTs,
48    },
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn ptz_telemetry_clone_eq() {
57        let t = PtzTelemetry {
58            pan: 45.0,
59            tilt: -10.0,
60            zoom: 0.5,
61            ts: MonotonicTs::from_nanos(1_000_000),
62        };
63        let t2 = t.clone();
64        assert_eq!(t, t2);
65    }
66
67    #[test]
68    fn ptz_event_variants() {
69        let ts = MonotonicTs::from_nanos(100);
70
71        let start = PtzEvent::MoveStart { ts };
72        let stop = PtzEvent::MoveStop { ts };
73        let preset = PtzEvent::PresetRecall { preset_id: 3, ts };
74
75        // Each variant is distinct.
76        assert_ne!(start, stop);
77        assert_ne!(stop, preset.clone());
78
79        // Clone round-trips.
80        assert_eq!(preset.clone(), preset);
81    }
82}