1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};

use rust_cam_bui_types::RecordingPath;
use serde::{Deserialize, Serialize};

use http_video_streaming_types::FirehoseCallbackInner;
use http_video_streaming_types::{CircleParams, Shape};

use ci2_remote_control::{BitrateSelection, CodecSelection, RecordingFrameRate, TagFamily};
use flydra_feature_detector_types::ImPtDetectCfg;

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RangedValue {
    pub name: String,
    pub unit: String,
    pub current: f64,
    pub min: f64,
    pub max: f64,
}

use led_box_comms::DeviceState;

pub use led_box_comms::ToDevice as ToLedBoxDevice;

// Note: this does not start with a slash because we do not want an absolute
// root path in case we are in a case where we are proxied by braid. I.e. it
// should work at `http://braid/cam-proxy/cam-name/strand-cam-events` as well as
// `http://strand-cam/strand-cam-events`.
pub const STRAND_CAM_EVENTS_URL_PATH: &str = "strand-cam-events";
pub const STRAND_CAM_EVENT_NAME: &str = "strand-cam";

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct StoreType {
    /// Whether we are running inside Braid.
    pub is_braid: bool,
    /// Whether we have Nvidia NvEnc encoder available.
    pub is_nvenc_functioning: bool,
    /// is saving MP4 file
    pub is_recording_mp4: Option<RecordingPath>,
    /// is saving FMF file
    pub is_recording_fmf: Option<RecordingPath>,
    /// is saving UFMF file
    pub is_recording_ufmf: Option<RecordingPath>,
    pub format_str_mp4: String,
    pub format_str: String,
    pub format_str_ufmf: String,
    pub camera_name: String,
    pub camera_gamma: Option<f32>,
    pub recording_filename: Option<String>,
    pub mp4_max_framerate: RecordingFrameRate,
    // pub mp4_recording_config: Mp4RecordingConfig,
    pub mp4_bitrate: BitrateSelection,
    pub mp4_codec: CodecSelection,
    /// CUDA device number (only used if using nvidia encoder)
    pub mp4_cuda_device: String,
    pub gain_auto: Option<ci2_types::AutoMode>,
    pub gain: RangedValue,
    pub exposure_auto: Option<ci2_types::AutoMode>,
    pub exposure_time: RangedValue,
    pub frame_rate_limit_enabled: bool,
    /// None when frame_rate_limit is not supported
    pub frame_rate_limit: Option<RangedValue>,
    pub trigger_mode: ci2_types::TriggerMode,
    pub trigger_selector: ci2_types::TriggerSelector,
    pub image_width: u32,
    pub image_height: u32,
    /// Whether object detection with image-tracker crate is compiled.
    // We could have made this a cargo feature, but this
    // adds complication to the builds. Here, the cost
    // is some extra unused code paths in the compiled
    // code, as well as larger serialized objects.
    pub has_image_tracker_compiled: bool,
    // used only with image-tracker crate
    /// Whether object detection is currently used.
    pub is_doing_object_detection: bool,
    pub measured_fps: f32,
    /// is saving object detection CSV file
    pub is_saving_im_pt_detect_csv: Option<RecordingPath>,
    // used only with image-tracker crate
    pub im_pt_detect_cfg: ImPtDetectCfg,
    /// Whether flydratrax (2D kalman tracking and LED triggering) is compiled.
    pub has_flydratrax_compiled: bool,
    pub kalman_tracking_config: KalmanTrackingConfig,
    pub led_program_config: LedProgramConfig,
    pub led_box_device_lost: bool,
    pub led_box_device_state: Option<DeviceState>,
    pub led_box_device_path: Option<String>,
    /// Whether checkerboard calibration is compiled.
    pub has_checkercal_compiled: bool,
    pub checkerboard_data: CheckerboardCalState,
    /// Path where debug data is being saved.
    pub checkerboard_save_debug: Option<String>,
    pub post_trigger_buffer_size: usize,
    pub cuda_devices: Vec<String>,
    /// This is None if no apriltag support is compiled in. Otherwise Some(_).
    pub apriltag_state: Option<ApriltagState>,
    pub im_ops_state: ImOpsState,
    pub format_str_apriltag_csv: String,
    pub had_frame_processing_error: bool,
    /// The camera calibration (does not contain potential information about water)
    pub camera_calibration: Option<mvg::Camera<f64>>,
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Default)]
#[serde(deny_unknown_fields)]
pub struct ApriltagState {
    pub do_detection: bool,
    pub april_family: TagFamily,
    pub is_recording_csv: Option<RecordingPath>,
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ImOpsState {
    pub do_detection: bool,
    pub destination: SocketAddr,
    /// The IP address of the socket interface from which the data is sent.
    pub source: IpAddr,
    pub center_x: u32,
    pub center_y: u32,
    pub threshold: u8,
}

impl Default for ImOpsState {
    fn default() -> Self {
        Self {
            do_detection: false,
            destination: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080)),
            source: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
            center_x: 0,
            center_y: 0,
            threshold: 0,
        }
    }
}

pub const APRILTAG_CSV_TEMPLATE_DEFAULT: &str = "apriltags%Y%m%d_%H%M%S.%f_{CAMNAME}.csv.gz";

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum LEDTriggerMode {
    Off, // could probably be better named "Unchanging" or "Constant"
    PositionTriggered,
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct KalmanTrackingConfig {
    pub enabled: bool,
    pub arena_diameter_meters: f32,
    pub min_central_moment: f32,
}

impl std::default::Default for KalmanTrackingConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            arena_diameter_meters: 0.2,
            min_central_moment: 0.0,
        }
    }
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LedProgramConfig {
    pub led_trigger_mode: LEDTriggerMode,
    pub led_on_shape_pixels: Shape,
    pub led_channel_num: u8,
    pub led_second_stage_radius: u16,
    pub led_hysteresis_pixels: f32,
}

impl std::default::Default for LedProgramConfig {
    fn default() -> Self {
        Self {
            led_trigger_mode: LEDTriggerMode::Off,
            led_channel_num: 1,
            led_on_shape_pixels: Shape::Circle(CircleParams {
                center_x: 640,
                center_y: 512,
                radius: 50,
            }),
            led_second_stage_radius: 50,
            led_hysteresis_pixels: 3.0,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CheckerboardCalState {
    pub enabled: bool,
    pub num_checkerboards_collected: u32,
    pub width: u32,
    pub height: u32,
}

impl Default for CheckerboardCalState {
    fn default() -> Self {
        Self {
            enabled: false,
            num_checkerboards_collected: 0,
            width: 8,
            height: 6,
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub enum CallbackType {
    ToCamera(ci2_remote_control::CamArg),
    FirehoseNotify(FirehoseCallbackInner),
    // used only with image-tracker crate
    TakeCurrentImageAsBackground,
    // used only with image-tracker crate
    ClearBackground(f32),
    ToLedBox(ToLedBoxDevice),
}