1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5use std::{thread, time::Duration};
6
7use crate::{HasViconHardware, Vector3D, ViconError, ViconSdkStatus, ViconSubject};
8
9include!(concat!(env!("OUT_DIR"), "/libvicon.rs"));
10
11pub const MAX_CONNECT_RETRIES: usize = 3;
14
15pub const MAX_CONNECT_TIMEOUT: u32 = 1000;
18
19pub struct ViconSystem {
22 vicon_handle: *mut std::ffi::c_void,
23}
24
25impl ViconSystem {
26 pub fn new(hostname: &str) -> Result<Self, ViconError> {
32 let vicon_handle = unsafe { Client_Create() };
33
34 let host_and_port = std::ffi::CString::new(hostname).unwrap();
36 let mut attempts = 0;
37 loop {
38 let status: ViconSdkStatus = unsafe {
39 Client_SetConnectionTimeout(vicon_handle, MAX_CONNECT_TIMEOUT);
40 Client_Connect(vicon_handle, host_and_port.as_ptr()).into()
41 };
42
43 if status.is_success() {
44 break;
45 }
46
47 if attempts > MAX_CONNECT_RETRIES {
48 return Err(ViconError::SdkError { source: status });
49 }
50
51 attempts += 1;
52 }
53
54 unsafe {
56 Client_SetStreamMode(vicon_handle, CStreamMode_ClientPull.try_into().unwrap());
57 Client_SetAxisMapping(
58 vicon_handle,
59 CDirection_Forward.try_into().unwrap(),
60 CDirection_Left.try_into().unwrap(),
61 CDirection_Up.try_into().unwrap(),
62 );
63 }
64
65 unsafe {
69 Client_EnableSegmentData(vicon_handle);
70 Client_EnableMarkerData(vicon_handle);
71 }
72 thread::sleep(Duration::from_millis(1000));
73
74 Ok(Self { vicon_handle })
75 }
76}
77
78impl HasViconHardware for ViconSystem {
79 fn read_frame_subjects(&mut self) -> Result<Vec<crate::ViconSubject>, ViconError> {
80 let _: ViconError = unsafe { Client_GetFrame(self.vicon_handle).try_into()? };
82
83 let mut subject_count = COutput_GetSubjectCount {
85 Result: CResult_UnknownResult as i32,
86 SubjectCount: 0,
87 };
88 unsafe {
89 Client_GetSubjectCount(self.vicon_handle, &mut subject_count);
90 }
91 let _: ViconError = subject_count.Result.try_into()?;
92 let subject_count = subject_count.SubjectCount;
93
94 let mut subjects = Vec::with_capacity(subject_count.try_into().unwrap());
96 for i in 0..subject_count {
97 let mut buffer = vec![0; 1024];
99 let subject_name = unsafe {
100 let _: ViconError = Client_GetSubjectName(
101 self.vicon_handle,
102 i,
103 buffer.capacity() as i32,
104 buffer.as_mut_ptr(),
105 )
106 .try_into()?;
107 buffer_to_cstring(buffer)
108 };
109
110 let mut segment_count = COutput_GetSegmentCount {
112 Result: CResult_UnknownResult as i32,
113 SegmentCount: 0,
114 };
115 unsafe {
116 Client_GetSegmentCount(
117 self.vicon_handle,
118 subject_name.as_ptr(),
119 &mut segment_count,
120 );
121 }
122 let _: ViconError = segment_count.Result.try_into()?;
123 let segment_count = segment_count.SegmentCount;
124
125 if segment_count == 0 {
127 continue;
128 }
129
130 let mut buffer = vec![0; 1024];
132 let segment_name = unsafe {
133 let _: ViconError = Client_GetSegmentName(
134 self.vicon_handle,
135 subject_name.as_ptr(),
136 0,
137 buffer.capacity() as i32,
138 buffer.as_mut_ptr(),
139 )
140 .try_into()?;
141 buffer_to_cstring(buffer)
142 };
143
144 let mut segment_translation = COutput_GetSegmentGlobalTranslation {
146 Result: CResult_UnknownResult as i32,
147 Translation: [0.0f64; 3],
148 Occluded: -1,
149 };
150 unsafe {
151 Client_GetSegmentGlobalTranslation(
152 self.vicon_handle,
153 subject_name.as_ptr(),
154 segment_name.as_ptr(),
155 &mut segment_translation,
156 );
157 }
158 let _: ViconError = segment_translation.Result.try_into()?;
159
160 if segment_translation.Occluded != 0 {
162 continue;
163 }
164
165 let mut segment_rotation = COutput_GetSegmentGlobalRotationEulerXYZ {
167 Result: CResult_UnknownResult as i32,
168 Rotation: [0.0f64; 3],
169 Occluded: -1,
170 };
171 unsafe {
172 Client_GetSegmentGlobalRotationEulerXYZ(
173 self.vicon_handle,
174 subject_name.as_ptr(),
175 segment_name.as_ptr(),
176 &mut segment_rotation,
177 );
178 }
179 let _: ViconError = segment_rotation.Result.try_into()?;
180
181 if segment_rotation.Occluded != 0 {
183 continue;
184 }
185
186 subjects.push(ViconSubject::from_vicon_frame(
187 subject_name.to_str().unwrap().to_owned(),
188 segment_translation,
189 segment_rotation,
190 ));
191 }
192
193 Ok(subjects)
194 }
195}
196
197unsafe impl Send for ViconSystem {}
198
199impl ViconSubject {
200 fn from_vicon_frame(
203 name: String,
204 translation: COutput_GetSegmentGlobalTranslation,
205 rotation: COutput_GetSegmentGlobalRotationEulerXYZ,
206 ) -> Self {
207 let origin_x = translation.Translation[0] / 1000.0;
210 let origin_y = translation.Translation[1] / 1000.0;
211 let origin_z = translation.Translation[2] / 1000.0;
212
213 Self {
214 name,
215 origin: Vector3D {
216 x: origin_x,
217 y: origin_y,
218 z: origin_z,
219 },
220 rotation: Vector3D {
221 x: rotation.Rotation[0],
222 y: rotation.Rotation[1],
223 z: rotation.Rotation[2],
224 },
225 }
226 }
227}
228
229unsafe fn buffer_to_cstring(buffer: Vec<std::os::raw::c_char>) -> std::ffi::CString {
234 let buffer = buffer
238 .into_iter()
239 .filter(|b| b != &0)
240 .map(|b| b as u8)
241 .collect::<Vec<u8>>();
242
243 std::ffi::CString::new(buffer).unwrap()
244}