Please consider becoming a sponsor so I may continue to maintain this crate in my spare time!
A safe, high-level interface to LinuxCNC's HAL (Hardware Abstraction Layer) module.
For lower level, unsafe use, see the linuxcnc-hal-sys
crate.
bindgen
must be set up correctly. Follow the requirements section of its docs.
To run and debug any HAL components, the LinuxCNC simulator can be set up. There's a guide here for Linux Mint (and other Debian derivatives).
This crate depends on the linuxcnc-hal-sys
crate which requires the LINUXCNC_SRC
environment variable toi be set to correctly generate the C bindings. The value must be the absolute path to the root of the LinuxCNC source code.
The version of the LinuxCNC sources must match the LinuxCNC version used in the machine control.
```bash
git clone https://github.com/LinuxCNC/linuxcnc.git
cd linuxcnc && git checkout v2.8.0 && cd ..
cargo new --lib my_comp
cd my_comp
cargo add linuxcnc-hal
LINUXCNC_SRC=/path/to/linuxcnc/source/code cargo build ```
This example creates a component called "pins"
with a single input ("input-1"
) and output
pin ("output-1"
). It enters an infinite loop which updates the value of output-1
every
second. LinuxCNC convention dictates that component and pin names should be dash-cased
.
This example can be loaded into LinuxCNC with a .hal
file that looks similar to this:
loadusr -W /path/to/your/component/target/debug/comp_bin_name
net input-1 spindle.0.speed-out pins.input-1
net output-1 pins.output-1
Pins and other resources are registered using the [Resources
] trait. This example creates a
Pins
struct which holds the two pins. [HalComponent::new()
] handles component creation,
resources (pin, signal, etc) initialisation and UNIX signal handler registration.
```rust use linuxcnchal::{ error::PinRegisterError, halpin::{InputPin, OutputPin}, prelude::*, HalComponent, RegisterResources, Resources, }; use std::{ error::Error, thread, time::{Duration, Instant}, };
struct Pins {
input1: InputPin
impl Resources for Pins { type RegisterError = PinRegisterError;
fn register_resources(comp: &RegisterResources) -> Result<Self, Self::RegisterError> {
Ok(Pins {
input_1: comp.register_pin::<InputPin<f64>>("input-1")?,
output_1: comp.register_pin::<OutputPin<f64>>("output-1")?,
})
}
}
fn main() -> Result<(), Box
// Create a new HAL component called `rust-comp`
let comp: HalComponent<Pins> = HalComponent::new("rust-comp")?;
// Get a reference to the `Pins` struct
let pins = comp.resources();
let start = Instant::now();
// Main control loop
while !comp.should_exit() {
let time = start.elapsed().as_secs() as i32;
// Set output pin to elapsed seconds since component started
pins.output_1.set_value(time.into())?;
// Print the current value of the input pin
println!("Input: {:?}", pins.input_1.value());
// Sleep for 1000ms. This should be a lower time if the component needs to update more
// frequently.
thread::sleep(Duration::from_millis(1000));
}
// The custom implementation of `Drop` for `HalComponent` ensures that `hal_exit()` is called
// at this point. Registered signal handlers are also deregistered.
Ok(())
} ```
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.