Abgabe
This commit is contained in:
4
kawaii/kawaii-rs/.gitignore
vendored
Normal file
4
kawaii/kawaii-rs/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
Cargo.lock
|
||||
target/
|
||||
**/*.rs.bk
|
||||
*.iml
|
||||
21
kawaii/kawaii-rs/CMakeLists.txt
Normal file
21
kawaii/kawaii-rs/CMakeLists.txt
Normal 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})
|
||||
19
kawaii/kawaii-rs/Cargo.toml
Normal file
19
kawaii/kawaii-rs/Cargo.toml
Normal 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" }
|
||||
8
kawaii/kawaii-rs/dependencies/emergency-stop/.gitignore
vendored
Normal file
8
kawaii/kawaii-rs/dependencies/emergency-stop/.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
CMakeFiles/
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
emergency-stop-prefix/
|
||||
emergency-stop.cbp
|
||||
target/
|
||||
**/*.rs.bk
|
||||
*.iml
|
||||
10
kawaii/kawaii-rs/dependencies/emergency-stop/Cargo.toml
Normal file
10
kawaii/kawaii-rs/dependencies/emergency-stop/Cargo.toml
Normal 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" }
|
||||
96
kawaii/kawaii-rs/dependencies/emergency-stop/src/lib.rs
Normal file
96
kawaii/kawaii-rs/dependencies/emergency-stop/src/lib.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
21
kawaii/kawaii-rs/dependencies/emergency-stop/src/main.rs
Normal file
21
kawaii/kawaii-rs/dependencies/emergency-stop/src/main.rs
Normal 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.");
|
||||
}
|
||||
4
kawaii/kawaii-rs/dependencies/kawaii-rs/.gitignore
vendored
Normal file
4
kawaii/kawaii-rs/dependencies/kawaii-rs/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
Cargo.lock
|
||||
target/
|
||||
**/*.rs.bk
|
||||
*.iml
|
||||
13
kawaii/kawaii-rs/dependencies/kawaii-rs/Cargo.toml
Normal file
13
kawaii/kawaii-rs/dependencies/kawaii-rs/Cargo.toml
Normal 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"
|
||||
288
kawaii/kawaii-rs/dependencies/kawaii-rs/src/gpio.rs
Normal file
288
kawaii/kawaii-rs/dependencies/kawaii-rs/src/gpio.rs
Normal 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())
|
||||
}
|
||||
}
|
||||
7
kawaii/kawaii-rs/dependencies/kawaii-rs/src/lib.rs
Normal file
7
kawaii/kawaii-rs/dependencies/kawaii-rs/src/lib.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
pub mod gpio;
|
||||
|
||||
#[cfg(feature = "measure")]
|
||||
mod measure;
|
||||
|
||||
#[cfg(feature = "measure")]
|
||||
pub use measure::Measure;
|
||||
35
kawaii/kawaii-rs/dependencies/kawaii-rs/src/main.rs
Normal file
35
kawaii/kawaii-rs/dependencies/kawaii-rs/src/main.rs
Normal 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))));
|
||||
}
|
||||
111
kawaii/kawaii-rs/dependencies/kawaii-rs/src/measure.rs
Normal file
111
kawaii/kawaii-rs/dependencies/kawaii-rs/src/measure.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
7
kawaii/kawaii-rs/dependencies/ultrasonic-irq/.gitignore
vendored
Normal file
7
kawaii/kawaii-rs/dependencies/ultrasonic-irq/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
CMakeFiles/
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
ultrasonic-irq-prefix/
|
||||
ultrasonic-irq.cbp
|
||||
target/
|
||||
**/*.rs.bk
|
||||
12
kawaii/kawaii-rs/dependencies/ultrasonic-irq/Cargo.toml
Normal file
12
kawaii/kawaii-rs/dependencies/ultrasonic-irq/Cargo.toml
Normal 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" }
|
||||
194
kawaii/kawaii-rs/dependencies/ultrasonic-irq/src/lib.rs
Normal file
194
kawaii/kawaii-rs/dependencies/ultrasonic-irq/src/lib.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
21
kawaii/kawaii-rs/dependencies/ultrasonic-irq/src/main.rs
Normal file
21
kawaii/kawaii-rs/dependencies/ultrasonic-irq/src/main.rs
Normal 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));
|
||||
}
|
||||
27
kawaii/kawaii-rs/src/emergency_stop.rs
Normal file
27
kawaii/kawaii-rs/src/emergency_stop.rs
Normal 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)
|
||||
}
|
||||
13
kawaii/kawaii-rs/src/lib.rs
Normal file
13
kawaii/kawaii-rs/src/lib.rs
Normal 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::*;
|
||||
48
kawaii/kawaii-rs/src/measure.rs
Normal file
48
kawaii/kawaii-rs/src/measure.rs
Normal 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();
|
||||
}
|
||||
27
kawaii/kawaii-rs/src/ultrasonic_irq.rs
Normal file
27
kawaii/kawaii-rs/src/ultrasonic_irq.rs
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user