This commit is contained in:
2017-06-28 20:40:01 +02:00
parent 76dd61f48b
commit 8d2b664149
41 changed files with 5225 additions and 0 deletions

4
kawaii/kawaii-rs/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
Cargo.lock
target/
**/*.rs.bk
*.iml

View File

@@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.0)
project(kawaii-rs)
include(ExternalProject)
if (MEASURE)
set(CARGO_FEATURES "${CARGO_FEATURES} measure")
endif (MEASURE)
if (CARGO_FEATURES)
set(CARGO_ARGUMENTS --features "${CARGO_FEATURES}")
endif(CARGO_FEATURES)
file(GLOB RUST_SOURCE_FILES "${PROJECT_SOURCE_DIR}/src" *.rs)
add_custom_target(${PROJECT_NAME}
COMMAND cargo build --color=never ${CARGO_ARGUMENTS}
COMMAND cargo build --color=never ${CARGO_ARGUMENTS} --release
DEPENDS ${RUST_SOURCE_FILES}
BYPRODUCTS target/debug/libkawaii.a target/release/libkawaii.a
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
SOURCES ${RUST_SOURCE_FILES})

View File

@@ -0,0 +1,19 @@
[package]
name = "kawaii-rs-api"
version = "0.1.0"
authors = ["Simon Wörner <git@simon-woerner.de>"]
[lib]
name = "kawaii"
crate-type = ["staticlib"]
[features]
measure = [
"kawaii/measure",
"emergency_stop/measure",
"ultrasonic_irq/measure" ]
[dependencies]
emergency_stop = { git = "https://git.brn.li/kawaii-robotto/emergency-stop.git" }
kawaii = { git = "https://git.brn.li/kawaii-robotto/kawaii-rs.git" }
ultrasonic_irq = { git = "https://git.brn.li/kawaii-robotto/ultrasonic-irq.git" }

View File

@@ -0,0 +1,8 @@
CMakeFiles/
Makefile
cmake_install.cmake
emergency-stop-prefix/
emergency-stop.cbp
target/
**/*.rs.bk
*.iml

View File

@@ -0,0 +1,10 @@
[package]
name = "emergency_stop"
version = "0.1.0"
authors = ["Simon Wörner <git@simon-woerner.de>"]
[features]
measure = ["kawaii/measure"]
[dependencies]
kawaii = { git = "https://git.brn.li/kawaii-robotto/kawaii-rs.git" }

View File

@@ -0,0 +1,96 @@
extern crate kawaii;
use std::time::Duration;
use std::thread;
use std::thread::JoinHandle;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use self::kawaii::gpio::{AsyncPort, Edge, Value};
#[cfg(feature = "measure")]
use self::kawaii::Measure;
#[derive(Debug)]
pub struct EmergencyStop {
thread: Option<JoinHandle<()>>,
pub state: Arc<AtomicBool>,
}
impl EmergencyStop {
pub fn new(stop_port: u8) -> std::io::Result<Self> {
let name = format!("EmergencyStop(port = {})", stop_port);
let state = Arc::new(AtomicBool::new(false));
let mut port = AsyncPort::new(stop_port, Edge::Both)?;
let state_clone = state.clone();
let thread = thread::Builder::new()
.name(name)
.spawn(move || EmergencyStop::thread(&mut port, state_clone))?;
Ok(EmergencyStop {
thread: Some(thread),
state: state,
})
}
fn thread(port: &mut AsyncPort, state: Arc<AtomicBool>) {
#[cfg(feature = "measure")]
let mut measure = Measure::new(format!("EmergencyStop(port = {})", port.port.number));
// clear first value
port.poll(Some(Duration::new(0, 0))).is_ok();
while !state.load(Ordering::Relaxed) {
#[cfg(feature = "measure")]
measure.start();
let timeout = Some(Duration::new(1, 0));
#[cfg(not(feature = "measure"))]
let value = port.poll(timeout);
#[cfg(feature = "measure")]
let value = port.poll_measure(timeout, &mut measure);
// continue on timeout
match value {
Ok(value) => {
if let Some(value) = value {
match value {
Value::High => {
#[cfg(debug_assertions)]
println!("EmergencyStop! ({:?})", value);
state.store(true, Ordering::Relaxed);
}
_ => {
#[cfg(debug_assertions)]
println!("EmergencyStop ignored: ({:?})", value);
}
}
}
}
Err(e) => {
#[cfg(debug_assertions)]
println!("EmergencyStop! ({:?})", e);
state.store(true, Ordering::Relaxed);
}
}
#[cfg(feature = "measure")]
measure.stop();
}
}
}
impl Drop for EmergencyStop {
fn drop(&mut self) {
self.state.store(true, Ordering::Relaxed);
if let Some(thread) = self.thread.take() {
thread.join().is_ok();
}
}
}

View File

@@ -0,0 +1,21 @@
extern crate emergency_stop;
use emergency_stop::EmergencyStop;
use std::time::Duration;
use std::thread::sleep;
use std::sync::atomic::Ordering;
static GPIO_PORT_STOP: u8 = 25;
fn main() {
let emergency_stop = EmergencyStop::new(GPIO_PORT_STOP).expect("Create Emergency Stop failed");
println!("{:?}", emergency_stop);
while !emergency_stop.state.load(Ordering::Relaxed) {
sleep(Duration::new(1, 0));
}
println!("Stopped.");
}

View File

@@ -0,0 +1,4 @@
Cargo.lock
target/
**/*.rs.bk
*.iml

View File

@@ -0,0 +1,13 @@
[package]
name = "kawaii"
version = "0.1.0"
authors = ["Simon Wörner <git@simon-woerner.de>"]
[features]
measure = []
[dependencies]
nix = "0.8.1"
regex = "^0.2"
separator = "^0.3.1"
time = "^0.1.36"

View File

@@ -0,0 +1,288 @@
extern crate std;
extern crate nix;
use std::fmt;
use std::time::Duration;
use std::io::prelude::*;
use std::io::{Error, ErrorKind, SeekFrom};
use std::fs::File;
use std::path::Path;
use std::os::unix::io::RawFd;
#[cfg(feature = "measure")]
use measure::Measure;
fn duration_to_ms(duration: Duration) -> u64 {
duration.as_secs() * 1_000u64 + duration.subsec_nanos() as u64 / 1_000_000u64
}
#[derive(Clone, Copy, Debug)]
pub enum Direction {
Out,
In,
}
impl Direction {
pub fn from_str(s: &str) -> Option<Direction> {
match s {
"out" => Some(Direction::Out),
"in" => Some(Direction::In),
_ => None,
}
}
pub fn as_str(&self) -> &'static str {
match *self {
Direction::Out => "out",
Direction::In => "in",
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum Edge {
None,
Rising,
Falling,
Both,
}
impl Edge {
pub fn from_str(s: &str) -> Option<Edge> {
match s {
"none" => Some(Edge::None),
"rising" => Some(Edge::Rising),
"falling" => Some(Edge::Falling),
"both" => Some(Edge::Both),
_ => None,
}
}
pub fn as_str(&self) -> &'static str {
match *self {
Edge::None => "none",
Edge::Rising => "rising",
Edge::Falling => "falling",
Edge::Both => "both",
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum Value {
High,
Low,
}
impl Value {
pub fn from_str(s: &str) -> Option<Value> {
match s {
"1" => Some(Value::High),
"0" => Some(Value::Low),
_ => None,
}
}
pub fn from_buffer(b: &[u8; 1]) -> Option<Self> {
Value::from_char(b[0])
}
pub fn from_char(c: u8) -> Option<Self> {
match c {
48 => Some(Value::Low), // '0'
49 => Some(Value::High), // '1'
_ => None,
}
}
pub fn as_str(&self) -> &'static str {
match *self {
Value::High => "1",
Value::Low => "0",
}
}
}
#[derive(Debug)]
pub struct Port {
pub number: u8,
pub direction: Direction,
}
#[derive(Debug)]
pub struct SyncPort {
pub port: Port,
file: File,
buffer: [u8; 1],
}
pub struct AsyncPort {
pub port: Port,
pub edge: Edge,
file: RawFd,
fds: [nix::poll::PollFd; 1],
buffer: [u8; 1],
}
impl fmt::Debug for AsyncPort {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"AsyncPort {{ port: {:?}, edge: {:?}, file: {:?}, fds: [?], buffer: {:?} }}",
self.port,
self.edge,
self.file,
self.buffer)
}
}
impl Port {
pub fn new(number: u8, direction: Direction) -> std::io::Result<Port> {
let port = Port {
number: number,
direction: direction,
};
port.init()?;
Ok(port)
}
fn init(&self) -> std::io::Result<()> {
self.export().ok();
self.set_direction()?;
Ok(())
}
pub fn drop(&mut self) {
self.unexport().ok();
}
fn write_path(path: &str, value: &str) -> std::io::Result<()> {
File::create(Path::new(path))?
.write_all(value.as_bytes())
}
fn export(&self) -> std::io::Result<()> {
Port::write_path("/sys/class/gpio/export", self.number.to_string().as_str())
}
fn unexport(&self) -> std::io::Result<()> {
Port::write_path("/sys/class/gpio/unexport", self.number.to_string().as_str())
}
fn set_direction(&self) -> std::io::Result<()> {
Port::write_path(format!("/sys/class/gpio/gpio{}/direction", self.number).as_str(),
self.direction.as_str())
}
}
impl SyncPort {
pub fn new(number: u8, direction: Direction) -> std::io::Result<SyncPort> {
Ok(SyncPort {
port: Port::new(number, direction)?,
file: SyncPort::open(number, direction)?,
buffer: [0; 1],
})
}
fn open(number: u8, direction: Direction) -> std::io::Result<File> {
let path = format!("/sys/class/gpio/gpio{}/value", number);
let path = Path::new(path.as_str());
Ok(match direction {
Direction::Out => File::create(path)?,
Direction::In => File::open(path)?,
})
}
pub fn read(&mut self) -> std::io::Result<Value> {
self.file.seek(SeekFrom::Start(0))?;
self.file.read_exact(&mut self.buffer)?;
Value::from_buffer(&self.buffer).ok_or(Error::new(ErrorKind::InvalidData,
"Unrecognized GPIO Value"))
}
pub fn write(&mut self, value: Value) -> std::io::Result<()> {
self.file.write_all(value.as_str().as_bytes())
}
}
impl AsyncPort {
pub fn new(number: u8, edge: Edge) -> std::io::Result<AsyncPort> {
let port = Port::new(number, Direction::In)?;
let file = AsyncPort::open(number)?;
let port = AsyncPort {
port: port,
edge: edge,
file: file,
fds: [nix::poll::PollFd::new(file, nix::poll::POLLPRI, nix::poll::EventFlags::empty())],
buffer: [0; 1],
};
port.init()?;
Ok(port)
}
fn init(&self) -> std::io::Result<()> {
self.set_edge()?;
Ok(())
}
fn open(number: u8) -> std::io::Result<RawFd> {
nix::fcntl::open(format!("/sys/class/gpio/gpio{}/value", number).as_str(),
nix::fcntl::O_RDONLY,
nix::sys::stat::Mode::empty())
.or(Err(Error::new(ErrorKind::Other, "open failed")))
}
fn get_timeout(timeout: Option<Duration>) -> i32 {
match timeout {
None => -1,
Some(t) => duration_to_ms(t) as i32,
}
}
fn nix_poll(&mut self, timeout: i32) -> nix::Result<i32> {
nix::poll::poll(&mut self.fds, timeout)
}
fn poll_read(&mut self, poll: nix::Result<i32>) -> std::io::Result<Option<Value>> {
let poll = poll.or(Err(Error::new(ErrorKind::Other, "poll failed")))?;
if poll == 0 {
return Ok(None);
}
nix::unistd::lseek(self.file, 0, nix::unistd::Whence::SeekSet)
.or(Err(Error::new(ErrorKind::Other, "lseek failed")))?;
nix::unistd::read(self.file, &mut self.buffer)
.or(Err(Error::new(ErrorKind::Other, "read failed")))?;
Value::from_buffer(&self.buffer).map_or(Err(Error::new(ErrorKind::InvalidData,
"Unrecognized GPIO Value")),
|v| Ok(Some(v)))
}
pub fn poll(&mut self, timeout: Option<Duration>) -> std::io::Result<Option<Value>> {
let poll = self.nix_poll(Self::get_timeout(timeout));
self.poll_read(poll)
}
#[cfg(feature = "measure")]
pub fn poll_measure(&mut self,
timeout: Option<Duration>,
measure: &mut Measure)
-> std::io::Result<Option<Value>> {
let timeout = Self::get_timeout(timeout);
measure.pause();
let poll = self.nix_poll(timeout);
measure.start();
self.poll_read(poll)
}
fn set_edge(&self) -> std::io::Result<()> {
Port::write_path(format!("/sys/class/gpio/gpio{}/edge", self.port.number).as_str(),
self.edge.as_str())
}
}

View File

@@ -0,0 +1,7 @@
pub mod gpio;
#[cfg(feature = "measure")]
mod measure;
#[cfg(feature = "measure")]
pub use measure::Measure;

View File

@@ -0,0 +1,35 @@
extern crate kawaii;
use std::time::Duration;
use kawaii::gpio::{SyncPort, AsyncPort, Direction, Edge, Value};
#[cfg(feature = "measure")]
use kawaii::measure::Measure;
fn main() {
println!("Hello, world!");
#[cfg(feature = "measure")]
{
let mut measure = Measure::new(String::from("main({test: 1})"));
for _ in 0..5 {
measure.start();
std::thread::sleep(Duration::new(0, 1_000_000));
measure.stop();
}
println!("{:?}", measure);
}
let mut trigger = SyncPort::new(27, Direction::Out).expect("Create Trigger GPIO failed");
let mut echo = AsyncPort::new(28, Edge::Both).expect("Create Echo GPIO failed");
println!("trigger = {:?}", trigger.read());
trigger.write(Value::High).expect("write failed");
println!("trigger = {:?}", trigger.read());
trigger.write(Value::Low).expect("write failed");
println!("trigger = {:?}", trigger.read());
println!("echo = {:?}", echo.poll(Some(Duration::new(1, 0))));
}

View File

@@ -0,0 +1,111 @@
extern crate regex;
extern crate separator;
extern crate time;
use std;
use std::fs::File;
use std::io::prelude::*;
use std::io::{Error, ErrorKind};
use self::regex::Regex;
use self::separator::Separatable;
use self::time::precise_time_ns;
#[derive(Debug)]
pub struct Measure {
pub min: u64,
pub max: u64,
time: u64,
last: u64,
data: Vec<u64>,
pub name: String,
}
impl Measure {
pub fn new(name: String) -> Self {
Measure {
min: u64::max_value(),
max: 0u64,
time: 0u64,
last: 0u64,
data: Vec::with_capacity(1_000_000),
name: name,
}
}
pub fn start(&mut self) {
self.last = precise_time_ns();
}
pub fn pause(&mut self) {
if self.last == 0 {
#[cfg(debug_assertions)]
println!("WARNING: {:?} pause called without start!", self);
return;
}
self.time += self.time_diff();
}
pub fn stop(&mut self) {
if self.last == 0 {
#[cfg(debug_assertions)]
println!("WARNING: {:?} stop called without start!", self);
return;
}
self.time += self.time_diff();
self.data.push(self.time);
if self.time < self.min {
self.min = self.time;
}
if self.time > self.max {
self.max = self.time;
}
self.time = 0u64;
self.last = 0u64;
}
fn time_diff(&mut self) -> u64 {
let current_time = precise_time_ns();
let time_diff = current_time - self.last;
self.last = current_time;
time_diff
}
fn write_data(&self) -> std::io::Result<()> {
let re = Regex::new(r"[^\w\-.]")
.or(Err(Error::new(ErrorKind::Other, "Create filename regex failed.")))?;
let file_name = format!("measure_{}.txt", self.name);
let file_name = re.replace_all(file_name.as_str(), "_").to_string();
println!("{}: Write data to {}", self.name, file_name);
let mut file = File::create(file_name)?;
for value in &self.data {
file.write_fmt(format_args!("{}\n", value))?;
}
Ok(())
}
}
impl Drop for Measure {
fn drop(&mut self) {
println!("{}:\n\tmin: {} ns\n\tmax: {} ns",
self.name,
self.min.separated_string(),
self.max.separated_string());
if let Err(e) = self.write_data() {
println!("{}: Write measure data failed: {}", self.name, e);
}
}
}

View File

@@ -0,0 +1,7 @@
CMakeFiles/
Makefile
cmake_install.cmake
ultrasonic-irq-prefix/
ultrasonic-irq.cbp
target/
**/*.rs.bk

View File

@@ -0,0 +1,12 @@
[package]
name = "ultrasonic_irq"
version = "0.1.0"
authors = ["kawaii <root@kawaii.home.lost-in-space.net>"]
[features]
measure = ["kawaii/measure"]
[dependencies]
time = "^0.1.36"
shuteye = "^0.3.2"
kawaii = { git = "https://git.brn.li/kawaii-robotto/kawaii-rs.git" }

View File

@@ -0,0 +1,194 @@
#![feature(integer_atomics)]
extern crate time;
extern crate shuteye;
extern crate kawaii;
use std::time::Duration;
use std::thread;
use std::thread::JoinHandle;
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
use self::kawaii::gpio::{SyncPort, AsyncPort, Direction, Edge, Value};
#[cfg(feature = "measure")]
use self::kawaii::Measure;
use self::time::precise_time_ns;
use self::shuteye::sleep;
#[derive(Debug)]
struct ThreadData<T> {
thread: JoinHandle<T>,
tx: Sender<()>,
}
#[derive(Debug)]
pub struct UltrasonicEcho {
echo: AsyncPort,
temperature: u8,
timestamp: u64,
distance: Arc<AtomicU32>,
}
#[derive(Debug)]
pub struct UltrasonicTrigger {
trigger: SyncPort,
}
#[derive(Debug)]
pub struct Ultrasonic {
trigger: Option<ThreadData<()>>,
echo: Option<ThreadData<()>>,
pub distance: Arc<AtomicU32>,
}
impl Ultrasonic {
pub fn new(trigger_port: u8, echo_port: u8, temperature: u8) -> std::io::Result<Ultrasonic> {
let distance = Arc::new(AtomicU32::new(u32::max_value()));
let echo = UltrasonicEcho {
echo: AsyncPort::new(echo_port, Edge::Both)?,
temperature: temperature,
timestamp: 0,
distance: distance.clone(),
};
let (tx, rx): (Sender<()>, Receiver<()>) = mpsc::channel();
let name = format!("Ultrasonic::echo(port = {})", echo_port);
let echo = ThreadData::<()> {
thread: thread::Builder::new()
.name(name)
.spawn(move || echo.thread(rx))?,
tx: tx,
};
let trigger = UltrasonicTrigger { trigger: SyncPort::new(trigger_port, Direction::Out)? };
let (tx, rx): (Sender<()>, Receiver<()>) = mpsc::channel();
let name = format!("Ultrasonic::trigger(port = {})", trigger_port);
let trigger = ThreadData::<()> {
thread: thread::Builder::new()
.name(name)
.spawn(move || trigger.thread(rx))?,
tx: tx,
};
Ok(Ultrasonic {
trigger: Some(trigger),
echo: Some(echo),
distance: distance,
})
}
}
impl Drop for Ultrasonic {
fn drop(&mut self) {
if let Some(echo) = self.echo.take() {
echo.tx.send(()).is_ok();
echo.thread.join().is_ok();
}
if let Some(trigger) = self.trigger.take() {
trigger.tx.send(()).is_ok();
trigger.thread.join().is_ok();
}
}
}
impl UltrasonicTrigger {
fn thread(mut self, stop_rx: Receiver<()>) {
#[cfg(feature = "measure")]
let mut measure = Measure::new(format!("Ultrasonic::trigger(port = {})", self.trigger.port.number));
while stop_rx.try_recv().is_err() {
#[cfg(feature = "measure")]
measure.start();
self.trigger.write(Value::Low).is_ok();
#[cfg(feature = "measure")]
measure.pause();
// sleep 10us (min length to trigger)
sleep(Duration::new(0, 10_000));
#[cfg(feature = "measure")]
measure.start();
self.trigger.write(Value::High).is_ok();
#[cfg(feature = "measure")]
measure.stop();
// sleep 20ms (max trigger frequency)
sleep(Duration::new(0, 20_000_000));
}
}
}
impl UltrasonicEcho {
fn thread(mut self, stop_rx: Receiver<()>) {
#[cfg(feature = "measure")]
let mut measure = Measure::new(format!("Ultrasonic::echo(port = {})", self.echo.port.number));
while stop_rx.try_recv().is_err() {
#[cfg(feature = "measure")]
measure.start();
#[cfg(not(feature = "measure"))]
let value = self.echo.poll(Some(Duration::new(1, 0)));
#[cfg(feature = "measure")]
let value = self.echo.poll_measure(Some(Duration::new(1, 0)), &mut measure);
match value {
Ok(value) => {
if let Some(value) = value {
self.on_value_changed(value);
}
}
Err(_e) => {
#[cfg(debug_assertions)]
println!("POLL failed: e = {:?}", _e);
}
}
#[cfg(feature = "measure")]
measure.stop();
}
}
fn on_value_changed(&mut self, value: Value) {
match value {
Value::High => {
// Switched from Value::High to Value::High
// possibly because of trigger after timeout and slow reading
if self.timestamp > 0 {
#[cfg(debug_assertions)]
println!("{:?}", self);
self.calc_distance();
}
self.timestamp = precise_time_ns()
}
Value::Low => {
// Switched from Value::Low to Value::Low
if self.timestamp == 0 {
#[cfg(debug_assertions)]
println!("{:?}", self);
}
self.calc_distance();
}
}
}
fn calc_distance(&mut self) {
let time_diff = precise_time_ns() - self.timestamp;
let distance = (3315 + self.temperature as u64 * 6) * time_diff / 20_000_000;
self.distance.store(distance as u32, Ordering::Relaxed);
#[cfg(debug_assertions)]
println!("time diff: {}\tdistance: {}mm", time_diff, distance);
self.timestamp = 0u64;
}
}

View File

@@ -0,0 +1,21 @@
extern crate shuteye;
extern crate ultrasonic_irq;
use std::time::Duration;
use std::thread::sleep;
use ultrasonic_irq::Ultrasonic;
static GPIO_PORT_TRIG: u8 = 23;
static GPIO_PORT_ECHO: u8 = 24;
static TEMPERATURE: u8 = 20;
fn main() {
let ultrasonic = Ultrasonic::new(GPIO_PORT_TRIG, GPIO_PORT_ECHO, TEMPERATURE)
.expect("Create Ultrasonic failed");
println!("{:?}", ultrasonic);
sleep(Duration::new(10, 0));
}

View File

@@ -0,0 +1,27 @@
extern crate emergency_stop;
use self::emergency_stop::EmergencyStop;
use std::mem::transmute;
use std::ptr::null_mut;
use std::sync::atomic::Ordering;
#[no_mangle]
pub extern "C" fn emergency_stop_init(stop: u8) -> *mut EmergencyStop {
match EmergencyStop::new(stop) {
Err(_) => null_mut(),
Ok(emergency_stop) => unsafe { transmute(Box::new(emergency_stop)) },
}
}
#[no_mangle]
pub extern "C" fn emergency_stop_clean(emergency_stop: *mut EmergencyStop) {
let _emergency_stop: Box<EmergencyStop> = unsafe { transmute(emergency_stop) };
}
#[no_mangle]
pub extern "C" fn emergency_stop_get_state(emergency_stop: *mut EmergencyStop) -> bool {
let emergency_stop = unsafe { &mut *emergency_stop };
emergency_stop.state.load(Ordering::Relaxed)
}

View File

@@ -0,0 +1,13 @@
#![feature(integer_atomics)]
mod emergency_stop;
mod ultrasonic_irq;
#[cfg(feature = "measure")]
mod measure;
pub use emergency_stop::*;
pub use ultrasonic_irq::*;
#[cfg(feature = "measure")]
pub use measure::*;

View File

@@ -0,0 +1,48 @@
extern crate kawaii;
use self::kawaii::Measure;
use std::ffi::CStr;
use std::ptr::null_mut;
use std::mem::transmute;
use std::os::raw::c_char;
#[no_mangle]
pub extern "C" fn measure_init(name: *const c_char) -> *mut Measure {
if name.is_null() {
return null_mut();
}
unsafe {
match CStr::from_ptr(name).to_str() {
Err(_) => null_mut(),
Ok(name) => transmute(Box::new(Measure::new(String::from(name)))),
}
}
}
#[no_mangle]
pub extern "C" fn measure_clean(measure: *mut Measure) {
let _measure: Box<Measure> = unsafe { transmute(measure) };
}
#[no_mangle]
pub extern "C" fn measure_start(measure: *mut Measure) {
let measure = unsafe { &mut *measure };
measure.start();
}
#[no_mangle]
pub extern "C" fn measure_pause(measure: *mut Measure) {
let measure = unsafe { &mut *measure };
measure.pause();
}
#[no_mangle]
pub extern "C" fn measure_stop(measure: *mut Measure) {
let measure = unsafe { &mut *measure };
measure.stop();
}

View File

@@ -0,0 +1,27 @@
extern crate ultrasonic_irq;
use std::mem::transmute;
use std::ptr::null_mut;
use std::sync::atomic::Ordering;
use self::ultrasonic_irq::Ultrasonic;
#[no_mangle]
pub extern "C" fn ultrasonic_init(trigger: u8, echo: u8, temperature: u8) -> *mut Ultrasonic {
match Ultrasonic::new(trigger, echo, temperature) {
Err(_) => null_mut(),
Ok(ultrasonic) => unsafe { transmute(Box::new(ultrasonic)) },
}
}
#[no_mangle]
pub extern "C" fn ultrasonic_clean(ultrasonic: *mut Ultrasonic) {
let _ultrasonic: Box<Ultrasonic> = unsafe { transmute(ultrasonic) };
}
#[no_mangle]
pub extern "C" fn ultrasonic_get_distance(ultrasonic: *mut Ultrasonic) -> u32 {
let ultrasonic = unsafe { &mut *ultrasonic };
ultrasonic.distance.load(Ordering::Relaxed)
}