10个版本
0.3.0 | 2022年11月15日 |
---|---|
0.2.0 | 2021年1月6日 |
0.1.7 | 2020年1月29日 |
在 机器人 类别中排名 109
每月下载量 48
用于 2 crates
170KB
4K SLoC
生成LinuxCNC HAL Rust绑定
请考虑 成为赞助者,这样我可以在业余时间继续维护这个crate!
文档
此crate为LinuxCNC的HAL提供了使用 bindgen
生成的绑定。
建议用户代码使用 linuxcnc-hal
中的高级、安全接口。
开发设置
要运行和调试任何HAL组件,可以设置LinuxCNC模拟器。有关Linux Mint(以及其他Debian衍生版)的指南 在此。
项目设置
构建此crate需要设置 LINUXCNC_SRC
环境变量。其值必须是LinuxCNC源代码根目录的绝对路径。
LinuxCNC源代码的版本必须与机器控制中使用的LinuxCNC版本相匹配。
# Clone LinuxCNC source code into linuxcnc/
git clone https://github.com/LinuxCNC/linuxcnc.git
# Check out a specific version tag. This may also be a commit, but must match the version in use by the machine control.
cd linuxcnc && git checkout v2.8.0 && cd ..
# Create your component lib
cargo new --lib my_comp
cd my_comp
# Add LinuxCNC HAL bindings as a Cargo dependency with cargo-edit
cargo add linuxcnc-hal-sys
LINUXCNC_SRC=/path/to/linuxcnc/source/code cargo build
示例
在LinuxCNC模拟器中运行示例
确保您已克隆了 LinuxCNC源代码仓库,检出到所需的版本,并按照 构建说明 进行构建。
请注意,LinuxCNC源代码位于以下示例路径中 linuxcnc-hal-rs
的相同父目录中。
LINUXCNC_SRC=$(realpath ../linuxcnc) cargo build --examples
# Define the correct path to the LinuxCNC source
. ../linuxcnc/scripts/rip-environment
linuxcnc ./linuxcnc-hal-sys/examples/<example>.ini
此crate导出的所有函数都是 unsafe
,因此每个示例都包含在一个大的 unsafe
块中,以保持清晰。
LinuxCNC HAL需要一定的设置程序才能正确运行。基本程序结构应大致如下
- 调用
hal_init
创建新的HAL组件 - 注册
SIGTERM
和SIGINT
信号,可能使用signal_hook
crate。如果这些信号未注册,LinuxCNC 将挂起。 - 使用
hal_pin_float_new
、hal_pin_u32_new
等注册引脚 - 调用
hal_ready
通知 LinuxCNC 组件已准备好 - 进入无限循环以持续更新输入/输出引脚值并执行组件逻辑
这些示例可以通过类似此处的 HAL 文件加载到 LinuxCNC 中
loadusr -W /path/to/your/component/target/debug/comp_bin_name
net input-1 spindle.0.speed-out pins.input-1
如果 LinuxCNC 配置为就地运行,则启动时可能找不到 liblinuxcnchal.so.0
。要修复,请尝试使用例如 export LD_LIBRARY_PATH=~/Repositories/linuxcnc/lib
创建输入引脚
此示例创建了一个名为 pins
的组件,并使用 hal_pin_float_new
向其注册了一个接受浮点值的输入引脚。每个 HAL 引脚都需要一些内存来存储其值,这通过 hal_malloc
完成。
可以使用类似此处的 HAL 文件将示例加载到 LinuxCNC 中
请注意,出于简洁起见,此示例中没有错误处理。
use linuxcnc_hal_sys::*;
use signal_hook::iterator::Signals;
use std::ffi::CString;
use std::mem;
use std::thread;
use std::time::Duration;
unsafe {
let id = hal_init(CString::new("pins").unwrap().as_ptr() as *const i8);
println!("ID {}", id);
let signals = Signals::new(&[signal_hook::SIGTERM, signal_hook::SIGINT]).unwrap();
let storage = hal_malloc(mem::size_of::<*mut f64>() as i64) as *mut *mut f64;
println!("Storage {:?}", storage);
let pin_name = CString::new("pins.input-1").unwrap();
let ret = hal_pin_float_new(
pin_name.as_ptr() as *const i8,
hal_pin_dir_t_HAL_IN,
storage,
id,
);
println!("Pin init {}", ret);
let ret = hal_ready(id);
println!("Ready {}", ret);
while !signals.pending().any(|signal| match signal {
signal_hook::SIGTERM | signal_hook::SIGINT | signal_hook::SIGKILL => true,
_ => false,
}) {
println!("Input {:?}", **storage);
thread::sleep(Duration::from_millis(500));
}
}
错误处理
此 crate 中的错误处理方式与 C 代码中的方式相同。导出了一些常量,如 EINVAL
和 EPERM
,以便匹配返回的错误代码。
use linuxcnc_hal_sys::*;
use signal_hook::iterator::Signals;
use std::ffi::CString;
use std::mem;
use std::thread;
use std::time::Duration;
unsafe {
let ret = hal_init(CString::new("pins").unwrap().as_ptr() as *const i8);
// Check that component was created successfully
let component_id = match ret {
x if x == -(EINVAL as i32) => panic!("Failed to initialise component"),
x if x == -(ENOMEM as i32) => panic!("Not enough memory to initialise component"),
id if id > 0 => id,
code => unreachable!("Hit unreachable error code {}", code),
};
println!("Component registered with ID {}", component_id);
let signals = Signals::new(&[signal_hook::SIGTERM, signal_hook::SIGINT]).unwrap();
let storage = hal_malloc(mem::size_of::<*mut f64>() as i64) as *mut *mut f64;
if storage.is_null() {
panic!("Failed to allocate storage");
}
let pin_name = CString::new("pins.input-1").unwrap();
let ret = hal_pin_float_new(
pin_name.as_ptr() as *const i8,
hal_pin_dir_t_HAL_IN,
storage,
component_id,
);
// Check that pin was registered successfully
match ret {
0 => println!("Pin registered successfully"),
x if x == -(EINVAL as i32) => panic!("Failed to register pin"),
x if x == -(EPERM as i32) => {
panic!("HAL is locked. Register pins before calling hal_ready()`")
}
x if x == -(ENOMEM as i32) => panic!("Failed to register pin"),
code => unreachable!("Hit unreachable error code {}", code),
}
let ret = hal_ready(component_id);
// Check that component is ready
match ret {
0 => println!("Component is ready"),
x if x == -(EINVAL as i32) => panic!("HAL component was not found or is already ready"),
code => unreachable!("Hit unreachable error code {}", code),
}
while !signals.pending().any(|signal| match signal {
signal_hook::SIGTERM | signal_hook::SIGINT | signal_hook::SIGKILL => true,
_ => false,
}) {
println!("Input {:?}", **storage);
thread::sleep(Duration::from_millis(500));
}
}
许可证
根据您的要求,许可为以下之一
- Apache License,版本 2.0 (LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
任选。
贡献
除非您明确声明,否则任何有意提交以包含在您的工作中的贡献,根据 Apache-2.0 许可证定义,将按上述方式双重许可,不附加任何额外条款或条件。
依赖关系
~0–2MB
~39K SLoC