Skip to content

Instantly share code, notes, and snippets.

@ifukazoo
Created February 24, 2020 08:30
Show Gist options
  • Save ifukazoo/2162f7f1054c6a884ecccface377ded2 to your computer and use it in GitHub Desktop.
Save ifukazoo/2162f7f1054c6a884ecccface377ded2 to your computer and use it in GitHub Desktop.
rust example
[package]
name = "serialapi"
version = "0.1.0"
authors = ["ifukazoo <ifukazoo@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc = "*"
serialport = "*"
lazy_static = "*"
[lib]
crate-type = ["cdylib"]
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate serialport;
use std::string::FromUtf8Error;
use std::sync::mpsc::channel;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;
use std::sync::mpsc::TryRecvError;
use std::sync::Mutex;
use std::thread;
use std::time;
enum Cmd {
Quit,
Start,
End,
}
struct Channels {
tx: Mutex<Sender<Cmd>>,
rx: Mutex<Receiver<Cmd>>,
}
lazy_static! {
static ref CHANNELS: Channels = {
let (tx, rx) = channel();
let tx = Mutex::new(tx);
let rx = Mutex::new(rx);
Channels { tx, rx }
};
static ref RECEIVED: Mutex<Vec<u8>> = Mutex::new(Vec::new());
}
#[no_mangle]
pub fn finish() -> bool {
let tx = CHANNELS.tx.lock().unwrap();
match tx.send(Cmd::Quit) {
Ok(()) => true,
Err(e) => {
eprintln!("{}", e);
false
}
}
}
#[no_mangle]
pub fn start() -> bool {
let tx = CHANNELS.tx.lock().unwrap();
match tx.send(Cmd::Start) {
Ok(()) => true,
Err(e) => {
eprintln!("{}", e);
false
}
}
}
#[no_mangle]
pub fn end() -> bool {
let tx = CHANNELS.tx.lock().unwrap();
match tx.send(Cmd::End) {
Ok(()) => true,
Err(e) => {
eprintln!("{}", e);
false
}
}
}
#[no_mangle]
pub fn get_data(buf: *mut libc::c_void, buflen: usize, get_len: *mut usize) {
let mut received = RECEIVED.lock().unwrap();
let min = std::cmp::min(buflen, received.len());
let dst = received.as_ptr();
let dst = dst as *const libc::c_void;
unsafe {
libc::memcpy(buf, dst, min);
*get_len = min;
}
received.truncate(0);
}
#[no_mangle]
pub fn initialize(portname: *const libc::c_char) -> bool {
let port_name = match get_str(portname) {
Ok(p) => p,
Err(e) => {
eprintln!("{}", e);
return false;
}
};
let port_name = std::ffi::OsString::from(port_name);
let settings = serialport_settings();
let mut port = match serialport::open_with_settings(&port_name, &settings) {
Ok(p) => p,
Err(e) => {
eprintln!("{}", e);
return false;
}
};
thread::spawn(move || loop {
// 開始 or 終了 を待つ
let rx = CHANNELS.rx.lock().unwrap();
let from_api = rx.recv().unwrap();
match from_api {
Cmd::End => continue,
Cmd::Quit => return,
// 開始コマンド送信
Cmd::Start => {
let sendcmd = String::from("start");
let sendcmd = sendcmd.as_bytes();
port.write_all(sendcmd).unwrap();
// 受信のループ
loop {
// APIコマンドのチェック
let from_api = rx.try_recv();
match from_api {
// APIコマンド受信
Ok(cmd) => match cmd {
Cmd::Start => continue,
Cmd::Quit => return,
// 終了コマンド送信
Cmd::End => {
let sendcmd = String::from("end");
let sendcmd = sendcmd.as_bytes();
port.write_all(sendcmd).unwrap();
// 受信のループを抜ける
break;
}
},
// APIコマンド受信していない
Err(e) => match e {
TryRecvError::Disconnected => return,
TryRecvError::Empty => {
// シリアルポート受信
let mut arr: [u8; 1024] = [0; 1024];
match port.read(&mut arr) {
// 受信した
Ok(size) => {
let slice = &arr[0..size];
let mut buf = slice.to_vec();
// 受信バッファへ追加
let mut gbuf = RECEIVED.lock().unwrap();
gbuf.append(&mut buf);
}
// 受信してない
Err(_) => continue,
};
}
},
}
}
}
};
});
true
}
fn serialport_settings() -> serialport::SerialPortSettings {
serialport::SerialPortSettings {
baud_rate: 115200,
data_bits: serialport::DataBits::Eight,
flow_control: serialport::FlowControl::None,
parity: serialport::Parity::None,
stop_bits: serialport::StopBits::One,
timeout: time::Duration::from_millis(1),
}
}
fn get_str(p: *const libc::c_char) -> Result<String, FromUtf8Error> {
let mut buf: Vec<u8> = Vec::new();
unsafe {
let len = libc::strlen(p);
buf.reserve(len);
let src = p as *const libc::c_void;
let dst = buf.as_mut_ptr() as *mut libc::c_void;
libc::memcpy(dst, src, len);
buf.set_len(len);
}
let s = String::from_utf8(buf)?;
Ok(s)
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment