extern crate libc;
use std::sync::{Mutex, Condvar};
pub struct Linkbot {
inner: Box<Inner>
}
pub enum Button {
Power,
A,
B
}
pub enum ButtonState {
Up,
Down
}
pub type ButtonCallback = FnMut(Button, ButtonState, u32);
#[repr(C)]
struct MoveWaitMask {
lock: Mutex<u8>,
cond: Condvar
}
#[repr(C)]
#[doc(hidden)]
pub struct Inner {
c_impl: *mut libc::c_void,
movewait_mask: MoveWaitMask,
motor_mask: u8,
button_callback: Option<Box<ButtonCallback>>
}
extern "C" fn linkbot_joint_event_callback(joint_no: i32, event: i32, _: i32, linkbot: *mut Inner)
{
unsafe {
let &ref lock = &((*linkbot).movewait_mask.lock);
let &ref cond = &((*linkbot).movewait_mask.cond);
let mut mask = lock.lock().unwrap();
if (event == 0) || (event == 1) {
*mask &= !(1<<joint_no);
cond.notify_all();
}
}
}
extern "C" fn linkbot_button_event_callback(button: i32, state: i32, timestamp: i32, linkbot: *mut Inner)
{
unsafe {
match (*linkbot).button_callback {
None => { return; }
Some(ref mut callback) => {
let _button = match button {
0 => Button::Power,
1 => Button::A,
_ => Button::B
};
let _state = match state {
0 => ButtonState::Up,
_ => ButtonState::Down
};
callback(_button, _state, timestamp as u32);
}
}
} }
impl Linkbot {
pub fn new(serial_id: &str) -> Option<Linkbot> {
let _serial_id = serial_id.to_string();
let _serial_id = _serial_id + "\0";
unsafe {
let inner = linkbotFromSerialId((&_serial_id).as_ptr());
if inner.is_null() {
None
} else {
let linkbot = Inner{c_impl: inner,
movewait_mask: MoveWaitMask{lock: Mutex::new(0), cond: Condvar::new()},
motor_mask: 0,
button_callback: None
};
let mut linkbot_boxed = Box::new(linkbot);
linkbotSetJointEventCallback(linkbot_boxed.c_impl,
linkbot_joint_event_callback,
&mut *linkbot_boxed);
let mut form:u32 = 0;
linkbotGetFormFactor(linkbot_boxed.c_impl, &mut form);
match form {
0 => linkbot_boxed.motor_mask = 0x05,
1 => linkbot_boxed.motor_mask = 0x03,
3 => linkbot_boxed.motor_mask = 0x07,
_ => linkbot_boxed.motor_mask = 0,
}
Some(Linkbot{ inner: linkbot_boxed })
}
}
}
pub fn get_joint_angles(&mut self) -> Result<(f64, f64, f64, u32), i32> {
let mut j1:f64 = 0.0;
let mut j2:f64 = 0.0;
let mut j3:f64 = 0.0;
let mut timestamp:i32 = 0;
let rc = unsafe {
linkbotGetJointAngles( self.inner.c_impl,
&mut timestamp,
&mut j1,
&mut j2,
&mut j3 )
};
if rc == 0 {
Ok((j1, j2, j3, timestamp as u32))
} else {
Err(rc)
}
}
pub fn move_motors(&mut self, mask: u8, j1: f64, j2: f64, j3: f64) -> Result<(), i32> {
let &ref lock = &(self.inner.movewait_mask.lock);
{
let mut _mask = lock.lock().unwrap();
*_mask |= mask & self.inner.motor_mask;
}
let rc = unsafe{
linkbotMove(self.inner.c_impl, mask as u32, j1, j2, j3)
};
if rc == 0 {
Ok(())
} else {
Err(rc)
}
}
pub fn move_motors_to(&mut self, mask: u8, j1: f64, j2: f64, j3: f64) -> Result<(), i32> {
let &ref lock = &(self.inner.movewait_mask.lock);
{
let mut _mask = lock.lock().unwrap();
*_mask |= mask & self.inner.motor_mask;
}
let rc = unsafe{
linkbotMoveTo(self.inner.c_impl, mask as u32, j1, j2, j3)
};
if rc == 0 {
Ok(())
} else {
Err(rc)
}
}
pub fn move_wait(&mut self, mask: u8) -> Result<(), i32> {
let &ref lock = &(self.inner.movewait_mask.lock);
let &ref cond = &(self.inner.movewait_mask.cond);
let mut _mask = lock.lock().unwrap();
while (mask & *_mask) != 0 {
_mask = cond.wait(_mask).unwrap();
}
Ok(())
}
pub fn set_button_handler<F>(&mut self, callback: F) -> Result<(), i32>
where F: FnMut(Button, ButtonState, u32) + 'static
{
self.inner.button_callback = Some(Box::new(callback));
let rc = unsafe {
linkbotSetButtonEventCallback(
self.inner.c_impl,
Some(linkbot_button_event_callback),
&mut *self.inner)
};
if rc == 0 {
Ok(())
} else {
Err(rc)
}
}
pub fn unset_button_handler(&mut self) -> Result<(), i32>
{
let rc = unsafe {
linkbotSetButtonEventCallback(
self.inner.c_impl,
None,
&mut *self.inner)
};
if rc == 0 {
Ok(())
} else {
Err(rc)
}
}
pub fn set_buzzer_frequency(&mut self, frequency: f32) -> Result<(), i32> {
let rc = unsafe {
linkbotSetBuzzerFrequency(
self.inner.c_impl,
frequency)
};
if rc == 0 {
Ok(())
} else {
Err(rc)
}
}
}
#[link(name = "linkbot")]
extern {
fn linkbotFromSerialId(serial_id: *const u8) -> *mut libc::c_void;
fn linkbotGetFormFactor(linkbot_inner: *mut libc::c_void,
form: *mut libc::c_uint) -> i32;
fn linkbotGetJointAngles(linkbot_inner: *mut libc::c_void,
timestamp: *mut libc::c_int,
j1: *mut libc::c_double,
j2: *mut libc::c_double,
j3: *mut libc::c_double) -> i32;
fn linkbotMove(linkbot_inner: *mut libc::c_void,
mask: libc::c_uint,
j1: libc::c_double,
j2: libc::c_double,
j3: libc::c_double) -> i32;
fn linkbotMoveTo(linkbot_inner: *mut libc::c_void,
mask: libc::c_uint,
j1: libc::c_double,
j2: libc::c_double,
j3: libc::c_double) -> i32;
fn linkbotSetJointEventCallback(linkbot_inner: *mut libc::c_void,
cb: extern fn(i32, i32, i32, *mut Inner),
userdata: *mut Inner) -> i32;
fn linkbotSetButtonEventCallback(linkbot_inner: *mut libc::c_void,
cb: Option<extern fn(i32, i32, i32, *mut Inner)>,
userdata: *mut Inner) -> i32;
fn linkbotSetBuzzerFrequency(linkbot_inner: *mut libc::c_void,
frequency: libc::c_float) -> i32;
}
#[cfg(test)]
mod tests {
use super::Linkbot;
use std;
#[test]
fn it_works() {
let mut l = Linkbot::new("ZRG6").unwrap();
l.set_button_handler( |button, state, timestamp| {
println!("Button press!");
});
let (j1, j2, j3, _) = l.get_joint_angles().unwrap();
println!("Joint angles: {}, {}, {}", j1, j2, j3);
l.move_motors(7, 90.0, 90.0, 90.0);
l.move_wait(7);
l.move_motors(7, -90.0, -90.0, -90.0);
l.move_wait(7);
l.unset_button_handler();
l.set_buzzer_frequency(440.0);
std::thread::sleep( std::time::Duration::from_secs( 1 ) );
l.set_buzzer_frequency(0.0);
}
}