Introduction
諸事情によりRustでシリアル通信をしようと思い、
serialportクレートを使ってみた記録です。
Environment
今回試した環境は以下のとおりです。
- MacBook Pro (13-inch, M1, 2020)
- OS : MacOS 12.4
- Rust : 1.70.0
Setup
私のつかっているPCにはシリアルポートがないので、
仮想的なシリアルポートを用意する必要があります。
socatを使えば用意できるので、Homebrewでインストールします。
% brew install socat
socatコマンドで仮想シリアルポートを作成します。
% socat -d -d pty,raw,echo=0 pty,raw,echo=0
2023/06/09 12:39:00 socat[18488] N PTY is /dev/ttys006
2023/06/09 12:39:00 socat[18488] N PTY is /dev/ttys007
2023/06/09 12:39:00 socat[18488] N starting data transfer loop with FDs [5,5] and [7,7]
「-d -d」でデバッグ出力用オプションを指定して2つの仮想シリアルポートを作成します。
ここでは/dev/ttys006と/dev/ttys007の2つのポートが作成されました。
Create Rust Program
ではCargoでRustプロジェクトを作成します。
% cargo new rust-serial
Cargo.tomlにserialportクレートを追記します。
(cargo add serialportでもOK)
[dependencies]
serialport = "4.2.1"
main.rsに、さきほど作成した仮想シリアルポートにするコードを記述します。
作成したポートのうち、1つを読み取り側、もう1つを書き込み側として使います。
use std::error::Error;
use std::io::prelude::*;
use std::time::Duration;
fn main() -> Result<(), Box<dyn Error>> {
let port_name_read = "/dev/ttys006";//socatで作成したポート
let port_name_read2 = "/dev/ttys007";//socatで作成したポート
let mut port1 = serialport::new(port_name_read, 0)
.timeout(Duration::from_millis(100))
.open()?;
let mut port2 = serialport::new(port_name_read2, 0)
.timeout(Duration::from_millis(10))
.open().expect("Failed to open port");
let mut buf: Vec<u8> = vec![0; 1000];
let output = "hello".as_bytes();
loop {
println!("Write Buffer.");
match port1.write(output) {
Ok(_) => std::io::stdout().flush()?,
Err(e) => eprintln!("{:?}", e),
}
println!("Read Buffer.");
match port2.read(buf.as_mut_slice()) {
Ok(t) => {
let bytes = &buf[..t];
let string = String::from_utf8(bytes.to_vec())?;
//println!("bytes: {:?}", bytes);
println!("string: {:?}", string);
}
Err(e) => eprintln!("{:?}", e),
}
std::thread::sleep(Duration::from_millis(1000));
}
}
実行してみます。
シリアルポートへの送受信ができていることがわかります。
% cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.08s
Running `target/debug/serial`
Write Buffer.
Read Buffer.
string: "hello"
Write Buffer.
Read Buffer.
string: "hello"
・
・
Summary
Rustでシリアルポート通信ができました。
しかし今回、通信時にbaud_rate(シリアル通信時に送受信速度を表すパラメータ)を
指定するとエラーになってしまいました。(なので0を指定している)
※serialport::newの第2引数
これが環境の問題なのかsocatで作成したからなのか不明なので
実際にシリアルポートがあるPCで試してみたいところです。