linuxcnc_hal/hal_pin/
hal_pin.rs

1use crate::error::{PinRegisterError, StorageError};
2use linuxcnc_hal_sys::hal_malloc;
3use std::{convert::TryInto, mem};
4
5fn is_aligned_to<T: ?Sized>(ptr: *const T, align: usize) -> bool {
6    assert!(align.is_power_of_two());
7    let ptr = ptr as *const u8 as usize;
8    let mask = align.wrapping_sub(1);
9    (ptr & mask) == 0
10}
11
12/// HAL pin trait
13///
14/// Implemented for any HAL pin. Handles allocation of backing storage in LinuxCNC's memory space.
15pub trait HalPin: Sized {
16    /// The underlying storage type for the given pin
17    ///
18    /// This will usually be a scalar value such as `u32` or `bool`
19    type Storage: std::fmt::Debug;
20
21    /// Allocate memory using [`hal_malloc()`] for storing pin value in
22    ///
23    /// # Errors
24    ///
25    /// This method will return an `Err` if [`hal_malloc()`] returns a null pointer.
26    ///
27    /// # Safety
28    ///
29    /// This method attempts to allocate memory in LinuxCNC's shared memory space with the unsafe
30    /// method [`hal_malloc()`].
31    fn allocate_storage() -> Result<*mut *mut Self::Storage, StorageError> {
32        let storage_ptr = unsafe {
33            let size = mem::size_of::<Self::Storage>();
34
35            let ptr_size = mem::size_of::<*mut Self::Storage>().try_into().unwrap();
36
37            debug!("Allocating {} bytes (ptr size {})", size, ptr_size);
38
39            let ptr = hal_malloc(ptr_size) as *mut *mut Self::Storage;
40
41            if ptr.is_null() {
42                return Err(StorageError::Null);
43            }
44
45            if !is_aligned_to(ptr, size) {
46                return Err(StorageError::Alignment);
47            }
48
49            debug!("Allocated value {:?} at {:?}", *ptr, ptr);
50
51            ptr
52        };
53
54        Ok(storage_ptr)
55    }
56
57    /// Get the pin's name
58    fn name(&self) -> &str;
59
60    /// Get a mutable pointer to underlying shared memory storing this pin's value
61    fn storage_mut(&self) -> Result<&mut Self::Storage, StorageError>;
62
63    /// Get a reference to the underlying shared memory storing the pin's value
64    fn storage(&self) -> Result<&Self::Storage, StorageError>;
65
66    /// Register the pin with the LinuxCNC HAL
67    ///
68    /// Returns a raw pointer to the underling HAL shared memory for the pin
69    fn register(full_pin_name: &str, component_id: i32) -> Result<Self, PinRegisterError>;
70}