https://github.com/pragmatic-elixir-meetup/port_exs
https://github.com/pragmatic-elixir-meetup/port_exs
elixir nerves-project rfid
Last synced: about 1 month ago
JSON representation
- Host: GitHub
- URL: https://github.com/pragmatic-elixir-meetup/port_exs
- Owner: Pragmatic-Elixir-Meetup
- Created: 2019-07-28T12:57:10.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2019-08-03T16:03:19.000Z (almost 7 years ago)
- Last Synced: 2025-12-01T00:48:57.024Z (7 months ago)
- Topics: elixir, nerves-project, rfid
- Language: HTML
- Size: 439 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
###
Elixir 通过 Port 调用 Rust 进程
Steven Gu
steven.gu@letote.cn
###
自我介绍
1. Letote 的 Rails Coder
2. 参与过 Letote 的 Elixir 项目开发
3. 学习 Rust 的嵌入式应用
###
NIF 和 Port
1. NIF - https://github.com/rusterlium/rustler
2. Port - http://erlang.org/doc/man/erlang.html#open_port-2
###
Letote 应用
1. RFID 设备标识衣服或者首饰
2. 通过 RFID 识别码跟踪状态
3. 使用 RFID 设备提供商的 SDK
###
选择 Port 的原因
1. Letote 的相关服务构建在 Elixir/Phoenix 基础上
2. RFID 设备提供商的 SDK 是 C lib,内部包含线程(pthread)
3. RFID 设备提供商的 SDK 使用 Callback Function 通知识别码
###
选择 Rust 的原因
1. 实验尝试
2. C 的结构化封装有难度(glibc,ffmpeg),C++ 成本高
3. Rust 友好安全的编译期内存检测
4. Cargo 工具链针对多平台 Targets 的支持,省去了 C Makefile 的复杂度
###
Rust 相关库
1. rust-bindgen - https://github.com/rust-lang/rust-bindgen(C binding)
2. libc - https://github.com/rust-lang/libc (pipe, select, epoll 等)
3. nix - https://github.com/nix-rust/nix (u8, i8, c_char, errno 等)
###
Simple Example
```
mix new simple_ex
cd simple_ex
cargo init
```
###
Mix Task
```
cargo build --bin simple_ex --release --target-dir \
_build/dev/lib/simple_ex/priv
```
```
defmodule Mix.Tasks.Compile.Cargo do
use Mix.Task
defp build do
System.cmd("cargo", build_cmd_args, [
stderr_to_stdout: true,
into: IO.stream(:stdio, :line)
])
end
end
```
###
Elixir Part(1)
```
defmodule SimpleEx do
use GenServer
def init(nil) do
executable = :code.priv_dir(:simple_ex) ++ '/release/simple_ex'
port = Port.open({:spawn_executable, executable}, [
{:packet, 2},
:binary,
:exit_status,
:use_stdio
])
end
end
```
###
Elixir Part(2)
```
def handle_info({_port, {:data, << data :: binary >>}}, state) do
code = :erlang.binary_to_term(data)
IO.puts "elixir_SimpleEx: Receives - #{code}"
{:noreply, state}
end
```
###
Rust Part
```
let mut sender = io::stdout();
sender.
write_u16::(encoded_data.len() as u16).
expect("failed to write data size");
sender.write_all(&encoded_data).expect("failed to write data");
sender.flush().expect("failed to flush stdout");
```
###
Simple Example
https://github.com/silathdiir/port_exs