Created
February 24, 2020 08:30
-
-
Save ifukazoo/2162f7f1054c6a884ecccface377ded2 to your computer and use it in GitHub Desktop.
rust example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "serialapi" | |
version = "0.1.0" | |
authors = ["ifukazoo <[email protected]>"] | |
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"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[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