orbita3d_c_api/
controller.rs

1//! C API for the controller module of the Orbita3D library.
2use std::{ffi::CStr, sync::Mutex};
3
4use motor_toolbox_rs::PID;
5use once_cell::sync::Lazy;
6use orbita3d_controller::Orbita3dController;
7
8use crate::sync_map::SyncMap;
9use env_logger;
10// use log::debug;
11static UID: Lazy<Mutex<u32>> = Lazy::new(|| Mutex::new(0));
12static CONTROLLER: Lazy<SyncMap<u32, Orbita3dController>> = Lazy::new(SyncMap::new);
13
14fn print_error(e: Box<dyn std::error::Error>) {
15    // eprintln!("[ORBITA_3D] {:?}", e);
16    log::debug!("[ORBITA_3D] Error: {:?}", e);
17}
18
19#[no_mangle]
20#[allow(clippy::not_unsafe_ptr_arg_deref)]
21/// Create the Orbita3dController from a config file.
22///
23/// # Arguments
24/// * configfile: *const libc::c_char - The path to the config file.
25/// * uid: *mut u32 - The unique identifier of the controller.
26/// # Returns
27/// * i32 - 0 if the controller was created successfully, 1 otherwise.
28pub extern "C" fn orbita3d_controller_from_config(
29    configfile: *const libc::c_char,
30    uid: &mut u32,
31) -> i32 {
32    let configfile = unsafe { CStr::from_ptr(configfile) }.to_str().unwrap();
33
34    let _ = env_logger::try_init();
35
36    match Orbita3dController::with_config(configfile) {
37        Ok(controller) => {
38            *uid = get_available_uid();
39            CONTROLLER.insert(*uid, controller);
40            0
41        }
42        Err(e) => {
43            print_error(e);
44            1
45        }
46    }
47}
48
49#[no_mangle]
50/// Check if controller is activated (are the motors on)
51///
52/// # Arguments
53/// * uid: u32 - The unique identifier of the controller.
54/// * is_on: *mut bool - The result of the check.
55/// # Returns
56/// * i32 - 0 if the controller is activated, 1 otherwise.
57pub extern "C" fn orbita3d_is_torque_on(uid: u32, is_on: &mut bool) -> i32 {
58    match CONTROLLER.get_mut(&uid).unwrap().is_torque_on() {
59        Ok(torque) => {
60            *is_on = torque;
61            0
62        }
63        Err(e) => {
64            print_error(e);
65            1
66        }
67    }
68}
69
70#[no_mangle]
71/// Enable the controller (turn on the motors)
72///
73/// # Arguments
74/// * uid: u32 - The unique identifier of the controller.
75/// * reset_target: bool - Reset the target orientation to the current orientation.
76/// # Returns
77/// * i32 - 0 if the controller was enabled successfully, 1 otherwise.
78pub extern "C" fn orbita3d_enable_torque(uid: u32, reset_target: bool) -> i32 {
79    match CONTROLLER
80        .get_mut(&uid)
81        .unwrap()
82        .enable_torque(reset_target)
83    {
84        Ok(_) => 0,
85        Err(e) => {
86            print_error(e);
87            1
88        }
89    }
90}
91
92#[no_mangle]
93/// Disable the controller (turn off the motors)
94///
95/// # Arguments
96/// * uid: u32 - The unique identifier of the controller.
97/// # Returns
98/// * i32 - 0 if the controller was disabled successfully, 1 otherwise.
99pub extern "C" fn orbita3d_disable_torque(uid: u32) -> i32 {
100    match CONTROLLER.get_mut(&uid).unwrap().disable_torque() {
101        Ok(_) => 0,
102        Err(e) => {
103            print_error(e);
104            1
105        }
106    }
107}
108
109#[no_mangle]
110/// Get the current orientation of the platform (quaternion)
111///
112/// # Arguments
113/// * uid: u32 - The unique identifier of the controller.
114/// * orientation: *mut [f64; 4] - The current orientation of the platform.
115/// # Returns
116/// * i32 - 0 if the orientation was retrieved successfully, 1 otherwise.
117pub extern "C" fn orbita3d_get_current_orientation(uid: u32, orientation: &mut [f64; 4]) -> i32 {
118    match CONTROLLER.get_mut(&uid).unwrap().get_current_orientation() {
119        Ok(ori) => {
120            *orientation = ori;
121            0
122        }
123        Err(e) => {
124            print_error(e);
125            1
126        }
127    }
128}
129
130#[no_mangle]
131/// Get the current orientation of the platform (roll, pitch, yaw)
132///
133/// # Arguments
134/// * uid: u32 - The unique identifier of the controller.
135/// * rpy: *mut [f64; 3] - The current orientation of the platform.
136/// # Returns
137/// * i32 - 0 if the orientation was retrieved successfully, 1 otherwise.
138pub extern "C" fn orbita3d_get_current_rpy_orientation(uid: u32, rpy: &mut [f64; 3]) -> i32 {
139    match CONTROLLER
140        .get_mut(&uid)
141        .unwrap()
142        .get_current_rpy_orientation()
143    {
144        Ok(ori) => {
145            *rpy = ori;
146            0
147        }
148        Err(e) => {
149            print_error(e);
150            1
151        }
152    }
153}
154
155#[no_mangle]
156/// Get the current velocity of the platform
157///
158/// # Arguments
159/// * uid: u32 - The unique identifier of the controller.
160/// * velocity: *mut [f64; 3] - The current velocity of the platform.
161/// # Returns
162/// * i32 - 0 if the velocity was retrieved successfully, 1 otherwise.
163pub extern "C" fn orbita3d_get_current_velocity(uid: u32, velocity: &mut [f64; 3]) -> i32 {
164    match CONTROLLER.get_mut(&uid).unwrap().get_current_velocity() {
165        Ok(vel) => {
166            *velocity = vel;
167            0
168        }
169        Err(e) => {
170            print_error(e);
171            1
172        }
173    }
174}
175
176#[no_mangle]
177/// Get the current torque applied by the actuator
178///
179/// # Arguments
180/// * uid: u32 - The unique identifier of the controller.
181/// * torque: *mut [f64; 3] - The current torque applied to the platform.
182/// # Returns
183/// * i32 - 0 if the torque was retrieved successfully, 1 otherwise.
184pub extern "C" fn orbita3d_get_current_torque(uid: u32, torque: &mut [f64; 3]) -> i32 {
185    match CONTROLLER.get_mut(&uid).unwrap().get_current_torque() {
186        Ok(tor) => {
187            *torque = tor;
188            0
189        }
190        Err(e) => {
191            print_error(e);
192            1
193        }
194    }
195}
196
197#[no_mangle]
198/// Get the current target orientation of the platform (quaternion)
199///
200/// # Arguments
201/// * uid: u32 - The unique identifier of the controller.
202/// * orientation: *mut [f64; 4] - The current target orientation of the platform.
203/// # Returns
204/// * i32 - 0 if the orientation was retrieved successfully, 1 otherwise.
205pub extern "C" fn orbita3d_get_target_orientation(uid: u32, orientation: &mut [f64; 4]) -> i32 {
206    match CONTROLLER.get_mut(&uid).unwrap().get_target_orientation() {
207        Ok(ori) => {
208            *orientation = ori;
209            0
210        }
211        Err(e) => {
212            print_error(e);
213            1
214        }
215    }
216}
217
218#[no_mangle]
219/// Get the current target orientation of the platform (roll, pitch, yaw)
220///
221/// # Arguments
222/// * uid: u32 - The unique identifier of the controller.
223/// * rpy: *mut [f64; 3] - The current target orientation of the platform.
224/// # Returns
225/// * i32 - 0 if the orientation was retrieved successfully, 1 otherwise.
226pub extern "C" fn orbita3d_get_target_rpy_orientation(uid: u32, rpy: &mut [f64; 3]) -> i32 {
227    match CONTROLLER
228        .get_mut(&uid)
229        .unwrap()
230        .get_target_rpy_orientation()
231    {
232        Ok(ori) => {
233            *rpy = ori;
234            0
235        }
236        Err(e) => {
237            print_error(e);
238            1
239        }
240    }
241}
242
243#[no_mangle]
244/// Set the target orientation of the platform (quaternion)
245///
246/// # Arguments
247/// * uid: u32 - The unique identifier of the controller.
248/// * orientation: *const [f64; 4] - The target orientation of the platform.
249/// # Returns
250/// * i32 - 0 if the orientation was set successfully, 1 otherwise.
251pub extern "C" fn orbita3d_set_target_orientation(uid: u32, orientation: &[f64; 4]) -> i32 {
252    match CONTROLLER
253        .get_mut(&uid)
254        .unwrap()
255        .set_target_orientation(*orientation)
256    {
257        Ok(_) => 0,
258        Err(e) => {
259            print_error(e);
260            1
261        }
262    }
263}
264
265#[no_mangle]
266/// Set the target orientation of the platform (roll, pitch, yaw)
267///
268/// # Arguments
269/// * uid: u32 - The unique identifier of the controller.
270/// * rpy: *const [f64; 3] - The target orientation of the platform.
271/// # Returns
272/// * i32 - 0 if the orientation was set successfully, 1 otherwise.
273pub extern "C" fn orbita3d_set_target_rpy_orientation(uid: u32, rpy: &[f64; 3]) -> i32 {
274    match CONTROLLER
275        .get_mut(&uid)
276        .unwrap()
277        .set_target_rpy_orientation(*rpy)
278    {
279        Ok(_) => 0,
280        Err(e) => {
281            print_error(e);
282            1
283        }
284    }
285}
286
287#[no_mangle]
288/// Set the tatget orientation and return the current orientation (quaternion)
289///
290/// # Arguments
291/// * uid: u32 - The unique identifier of the controller.
292/// * orientation: *const [f64; 4] - The target orientation of the platform.
293/// * feedback: *mut [f64; 10] - The feedback of the controller.
294/// # Returns
295/// * i32 - 0 if the orientation was set successfully, 1 otherwise.
296pub extern "C" fn orbita3d_set_target_orientation_fb(
297    uid: u32,
298    orientation: &[f64; 4],
299    // feedback: &mut [f64; 10],
300    feedback: &mut [f64; 4],
301) -> i32 {
302    match CONTROLLER
303        .get_mut(&uid)
304        .unwrap()
305        .set_target_orientation_fb(*orientation)
306    {
307        Ok(fb) => {
308            feedback[0] = fb.orientation[0]; //FIXME: I don't know how to include the struct definition in the C bindings...
309            feedback[1] = fb.orientation[1];
310            feedback[2] = fb.orientation[2];
311            feedback[3] = fb.orientation[3];
312            // feedback[4] = fb.velocity[0];
313            // feedback[5] = fb.velocity[1];
314            // feedback[6] = fb.velocity[2];
315            // feedback[7] = fb.torque[0];
316            // feedback[8] = fb.torque[1];
317            // feedback[9] = fb.torque[2];
318            0
319        }
320        Err(e) => {
321            print_error(e);
322            1
323        }
324    }
325}
326
327#[no_mangle]
328/// Set the tatget orientation and return the current orientation (roll, pitch, yaw)
329///
330/// # Arguments
331/// * uid: u32 - The unique identifier of the controller.
332/// * rpy: *const [f64; 3] - The target orientation of the platform.
333/// * feedback: *mut [f64; 10] - The feedback of the controller.
334/// # Returns
335/// * i32 - 0 if the orientation was set successfully, 1 otherwise.
336pub extern "C" fn orbita3d_set_target_rpy_orientation_fb(
337    uid: u32,
338    rpy: &[f64; 3],
339    // feedback: &mut [f64; 10],
340    feedback: &mut [f64; 3],
341) -> i32 {
342    match CONTROLLER
343        .get_mut(&uid)
344        .unwrap()
345        .set_target_rpy_orientation_fb(*rpy)
346    {
347        Ok(fb) => {
348            feedback[0] = fb[0];
349            feedback[1] = fb[1];
350            feedback[2] = fb[2];
351            0
352        }
353        Err(e) => {
354            print_error(e);
355            1
356        }
357    }
358}
359
360#[no_mangle]
361/// Get the current velocity of the motors (0 - 1.0)
362///
363/// # Arguments
364/// * uid: u32 - The unique identifier of the controller.
365/// * velocity: *mut [f64; 3] - The current velocity of the motors.
366/// # Returns
367/// * i32 - 0 if the velocity was retrieved successfully, 1 otherwise.
368pub extern "C" fn orbita3d_get_raw_motors_velocity_limit(uid: u32, limit: &mut [f64; 3]) -> i32 {
369    match CONTROLLER
370        .get_mut(&uid)
371        .unwrap()
372        .get_raw_motors_velocity_limit()
373    {
374        Ok(lim) => {
375            *limit = lim;
376            0
377        }
378        Err(e) => {
379            print_error(e);
380            1
381        }
382    }
383}
384
385#[no_mangle]
386/// Set the current velocity of the motors (0 - 1.0)
387///
388/// # Arguments
389/// * uid: u32 - The unique identifier of the controller.
390/// * velocity: *const [f64; 3] - The current velocity of the motors.
391/// # Returns
392/// * i32 - 0 if the velocity was set successfully, 1 otherwise.
393pub extern "C" fn orbita3d_set_raw_motors_velocity_limit(uid: u32, limit: &[f64; 3]) -> i32 {
394    match CONTROLLER
395        .get_mut(&uid)
396        .unwrap()
397        .set_raw_motors_velocity_limit(*limit)
398    {
399        Ok(_) => 0,
400        Err(e) => {
401            print_error(e);
402            1
403        }
404    }
405}
406
407#[no_mangle]
408/// Get the current torque limit of the motors (0 - 1.0)
409///
410/// # Arguments
411/// * uid: u32 - The unique identifier of the controller.
412/// * limit: *mut [f64; 3] - The current torque limit of the motors.
413/// # Returns
414/// * i32 - 0 if the torque limit was retrieved successfully, 1 otherwise.
415pub extern "C" fn orbita3d_get_raw_motors_torque_limit(uid: u32, limit: &mut [f64; 3]) -> i32 {
416    match CONTROLLER
417        .get_mut(&uid)
418        .unwrap()
419        .get_raw_motors_torque_limit()
420    {
421        Ok(lim) => {
422            *limit = lim;
423            0
424        }
425        Err(e) => {
426            print_error(e);
427            1
428        }
429    }
430}
431
432#[no_mangle]
433/// Set the current torque limit of the motors (0 - 1.0)
434///
435/// # Arguments
436/// * uid: u32 - The unique identifier of the controller.
437/// * limit: *const [f64; 3] - The current torque limit of the motors.
438/// # Returns
439/// * i32 - 0 if the torque limit was set successfully, 1 otherwise.
440pub extern "C" fn orbita3d_set_raw_motors_torque_limit(uid: u32, limit: &[f64; 3]) -> i32 {
441    match CONTROLLER
442        .get_mut(&uid)
443        .unwrap()
444        .set_raw_motors_torque_limit(*limit)
445    {
446        Ok(_) => 0,
447        Err(e) => {
448            print_error(e);
449            1
450        }
451    }
452}
453
454#[no_mangle]
455/// Get the current PID gains of the motors
456///
457/// # Arguments
458/// * uid: u32 - The unique identifier of the controller.
459/// * gains: *mut [[f64; 3]; 3] - The current PID gains of the motors.
460/// # Returns
461/// * i32 - 0 if the PID gains were retrieved successfully, 1 otherwise.
462pub extern "C" fn orbita3d_get_raw_motors_pid_gains(uid: u32, gains: &mut [[f64; 3]; 3]) -> i32 {
463    match CONTROLLER.get_mut(&uid).unwrap().get_raw_motors_pid_gains() {
464        Ok([pid_top, pid_middle, pid_bottom]) => {
465            gains[0][0] = pid_top.p;
466            gains[0][1] = pid_top.i;
467            gains[0][2] = pid_top.d;
468            gains[1][0] = pid_middle.p;
469            gains[1][1] = pid_middle.i;
470            gains[1][2] = pid_middle.d;
471            gains[2][0] = pid_bottom.p;
472            gains[2][1] = pid_bottom.i;
473            gains[2][2] = pid_bottom.d;
474
475            0
476        }
477        Err(e) => {
478            print_error(e);
479            1
480        }
481    }
482}
483
484#[no_mangle]
485/// Set the current PID gains of the motors
486///
487/// # Arguments
488/// * uid: u32 - The unique identifier of the controller.
489/// * gains: *const [[f64; 3]; 3] - The current PID gains of the motors.
490/// # Returns
491/// * i32 - 0 if the PID gains were set successfully, 1 otherwise.
492pub extern "C" fn orbita3d_set_raw_motors_pid_gains(uid: u32, gains: &[[f64; 3]; 3]) -> i32 {
493    match CONTROLLER.get_mut(&uid).unwrap().set_raw_motors_pid_gains([
494        PID {
495            p: gains[0][0],
496            i: gains[0][1],
497            d: gains[0][2],
498        },
499        PID {
500            p: gains[1][0],
501            i: gains[1][1],
502            d: gains[1][2],
503        },
504        PID {
505            p: gains[2][0],
506            i: gains[2][1],
507            d: gains[2][2],
508        },
509    ]) {
510        Ok(_) => 0,
511        Err(e) => {
512            print_error(e);
513            1
514        }
515    }
516}
517
518#[no_mangle]
519/// Get the raw motor current of the actuators
520///
521/// # Arguments
522/// * uid: u32 - The unique identifier of the controller.
523/// * current: *mut [f64; 3] - The current of the motors.
524/// # Returns
525/// * i32 - 0 if the current was retrieved successfully, 1 otherwise.
526pub extern "C" fn orbita3d_get_raw_motors_current(
527    uid: u32,
528    raw_motors_current: &mut [f64; 3],
529) -> u32 {
530    match CONTROLLER.get_mut(&uid).unwrap().get_raw_motors_current() {
531        Ok(c) => {
532            *raw_motors_current = c;
533            0
534        }
535        Err(e) => {
536            print_error(e);
537            1
538        }
539    }
540}
541
542#[no_mangle]
543/// Get the raw motor velocity of the actuators
544///
545/// # Arguments
546/// * uid: u32 - The unique identifier of the controller.
547/// * raw_motors_velocity: *mut [f64; 3] - The velocity of the motors.
548/// # Returns
549/// * i32 - 0 if the velocity was retrieved successfully, 1 otherwise.
550pub extern "C" fn orbita3d_get_raw_motors_velocity(
551    uid: u32,
552    raw_motors_velocity: &mut [f64; 3],
553) -> u32 {
554    match CONTROLLER.get_mut(&uid).unwrap().get_raw_motors_velocity() {
555        Ok(v) => {
556            *raw_motors_velocity = v;
557            0
558        }
559        Err(e) => {
560            print_error(e);
561            1
562        }
563    }
564}
565
566#[no_mangle]
567/// Get the raw motor position of the actuators
568///
569/// # Arguments
570/// * uid: u32 - The unique identifier of the controller.
571/// * raw_motors_position: *mut [f64; 3] - The position of the motors.
572/// # Returns
573/// * i32 - 0 if the position was retrieved successfully, 1 otherwise.
574pub extern "C" fn orbita3d_get_raw_motors_position(
575    uid: u32,
576    raw_motors_position: &mut [f64; 3],
577) -> u32 {
578    match CONTROLLER.get_mut(&uid).unwrap().get_raw_motors_positions() {
579        Ok(p) => {
580            *raw_motors_position = p;
581            0
582        }
583        Err(e) => {
584            print_error(e);
585            1
586        }
587    }
588}
589
590#[no_mangle]
591/// Get the state of the board (BoardState - u8)
592/// - See more info [here](../../poulpe_ethercat_controller/register/enum.BoardStatus.html)
593///
594/// # Arguments
595/// * uid: u32 - The unique identifier of the controller.
596/// * state: *mut u8 - The state of the board.
597/// # Returns
598/// * i32 - 0 if the state was retrieved successfully, 1 otherwise.
599pub extern "C" fn orbita3d_get_board_state(uid: u32, state: &mut u8) -> i32 {
600    match CONTROLLER.get_mut(&uid).unwrap().get_board_state() {
601        Ok(s) => {
602            *state = s;
603            0
604        }
605        Err(e) => {
606            print_error(e);
607            1
608        }
609    }
610}
611
612#[no_mangle]
613/// Set the state of the board (BoardState - u8)
614/// - See more info [here](../../poulpe_ethercat_controller/register/enum.BoardStatus.html)
615///
616/// # Arguments
617/// * uid: u32 - The unique identifier of the controller.
618/// * state: *const u8 - The state of the board.
619/// # Returns
620/// * i32 - 0 if the state was set successfully, 1 otherwise.
621pub extern "C" fn orbita3d_set_board_state(uid: u32, state: &u8) -> i32 {
622    match CONTROLLER.get_mut(&uid).unwrap().set_board_state(*state) {
623        Ok(_) => 0,
624        Err(e) => {
625            print_error(e);
626            1
627        }
628    }
629}
630
631#[no_mangle]
632/// Get the raw axis sensors values
633///
634/// # Arguments
635/// * uid: u32 - The unique identifier of the controller.
636/// * axis: *mut [f64; 3] - The axis sensors values.
637/// # Returns
638/// * i32 - 0 if the axis sensors values were retrieved successfully, 1 otherwise.
639pub extern "C" fn orbita3d_get_axis_sensors(uid: u32, axis: &mut [f64; 3]) -> i32 {
640    match CONTROLLER.get_mut(&uid).unwrap().get_axis_sensors() {
641        Ok(a) => {
642            *axis = a;
643            0
644        }
645        Err(e) => {
646            print_error(e);
647            1
648        }
649    }
650}
651
652#[no_mangle]
653/// Get the raw axis sensor zeros
654///
655/// # Arguments
656/// * uid: u32 - The unique identifier of the controller.
657/// * axis: *mut [f64; 3] - The axis sensor zeros.
658/// # Returns
659/// * i32 - 0 if the axis sensor zeros were retrieved successfully, 1 otherwise.
660pub extern "C" fn orbita3d_get_axis_sensor_zeros(uid: u32, axis: &mut [f64; 3]) -> i32 {
661    match CONTROLLER.get_mut(&uid).unwrap().get_axis_sensor_zeros() {
662        Ok(a) => {
663            *axis = a;
664            0
665        }
666        Err(e) => {
667            print_error(e);
668            1
669        }
670    }
671}
672
673#[no_mangle]
674/// Get the raw motor temperatures
675///
676/// # Arguments
677/// * uid: u32 - The unique identifier of the controller.
678/// * temp: *mut [f64; 3] - The motor temperatures.
679/// # Returns
680/// * i32 - 0 if the motor temperatures were retrieved successfully, 1 otherwise.
681pub extern "C" fn orbita3d_get_motor_temperatures(uid: u32, temp: &mut [f64; 3]) -> i32 {
682    match CONTROLLER.get_mut(&uid).unwrap().get_motor_temperatures() {
683        Ok(t) => {
684            *temp = t;
685            0
686        }
687        Err(e) => {
688            print_error(e);
689            1
690        }
691    }
692}
693
694#[no_mangle]
695/// Get the raw board temperatures
696///
697/// # Arguments
698/// * uid: u32 - The unique identifier of the controller.
699/// * temp: *mut [f64; 3] - The board temperatures.
700/// # Returns
701/// * i32 - 0 if the board temperatures were retrieved successfully, 1 otherwise.
702pub extern "C" fn orbita3d_get_board_temperatures(uid: u32, temp: &mut [f64; 3]) -> i32 {
703    match CONTROLLER.get_mut(&uid).unwrap().get_board_temperatures() {
704        Ok(t) => {
705            *temp = t;
706            0
707        }
708        Err(e) => {
709            print_error(e);
710            1
711        }
712    }
713}
714
715#[no_mangle]
716/// Get the error codes
717/// - see more info [here](../../poulpe_ethercat_controller/state_machine/struct.ErrorFlags.html)
718///
719/// # Arguments
720/// * uid: u32 - The unique identifier of the controller.
721/// * error: *mut [i32; 3] - The error codes.
722/// # Returns
723/// * i32 - 0 if the error codes were retrieved successfully, 1 otherwise.
724pub extern "C" fn orbita3d_get_error_codes(uid: u32, error: &mut [i32; 3]) -> i32 {
725    match CONTROLLER.get_mut(&uid).unwrap().get_error_codes() {
726        Ok(c) => {
727            *error = c;
728            0
729        }
730        Err(e) => {
731            print_error(e);
732            1
733        }
734    }
735}
736
737#[no_mangle]
738/// Get the control mode ( CiA402 control mode  - u8) : 1 - Profile Position Mode, 3 - Profile Velocity Mode, 4 - Profile Torque Mode
739/// - See more info [here](../../poulpe_ethercat_controller/state_machine/enum.CiA402ModeOfOperation.html)
740///
741/// # Arguments
742/// * uid: u32 - The unique identifier of the controller.
743/// * mode: *mut u8 - The control mode.
744/// # Returns
745/// * i32 - 0 if the control mode was retrieved successfully, 1 otherwise.
746pub extern "C" fn orbita3d_get_control_mode(uid: u32, mode: &mut u8) -> i32 {
747    match CONTROLLER.get_mut(&uid).unwrap().get_control_mode() {
748        Ok(m) => {
749            *mode = m[0];
750            0
751        }
752        Err(e) => {
753            print_error(e);
754            1
755        }
756    }
757}
758
759#[no_mangle]
760/// Set the control mode ( CiA402 control mode  - u8) : 1 - Profile Position Mode, 3 - Profile Velocity Mode, 4 - Profile Torque Mode
761/// - See more info [here](../../poulpe_ethercat_controller/state_machine/enum.CiA402ModeOfOperation.html)
762///
763/// # Arguments
764/// * uid: u32 - The unique identifier of the controller.
765/// * mode: *const u8 - The control mode.
766/// # Returns
767/// * i32 - 0 if the control mode was set successfully, 1 otherwise.
768pub extern "C" fn orbita3d_set_control_mode(uid: u32, mode: &u8) -> i32 {
769    match CONTROLLER
770        .get_mut(&uid)
771        .unwrap()
772        .set_control_mode([*mode, *mode, *mode])
773    {
774        Ok(_) => 0,
775        Err(e) => {
776            print_error(e);
777            1
778        }
779    }
780}
781
782#[no_mangle]
783/// Send the emergency stop signal to the controller
784///
785/// # Arguments
786/// * uid: u32 - The unique identifier of the controller.
787/// # Returns
788/// * i32 - 0 if the emergency stop signal was sent successfully, 1 otherwise.
789pub extern "C" fn orbita3d_emergency_stop(uid: u32) -> i32 {
790    CONTROLLER.get_mut(&uid).unwrap().emergency_stop();
791    0
792}
793
794/// Get the next available unique identifier
795fn get_available_uid() -> u32 {
796    let mut uid = UID.lock().unwrap();
797    *uid += 1;
798    *uid
799}