-
Notifications
You must be signed in to change notification settings - Fork 3
/
hal.rs
167 lines (154 loc) · 5.99 KB
/
hal.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
use core::cell::RefCell;
use core::ffi::{c_char, c_uint, c_void, CStr};
use defmt::trace;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::Mutex;
use embedded_hal::spi::{ErrorKind as SpiErrorKind, SpiDevice};
use crate::rss_bindings::{
acc_hal_a121_t, acc_hal_optimization_t, acc_rss_hal_register, acc_sensor_id_t, c_log_stub,
};
pub type RadarSpi = dyn SpiDevice<u8, Error = SpiErrorKind> + Send;
pub type RefRadarSpi = &'static mut RadarSpi;
/// Global instance of a Mutex, wrapping a RefCell that optionally contains a mutable reference to a `SpiBus`.
///
/// `SPI_INSTANCE` is used to store and provide controlled access to the SPI device required by the radar sensor.
/// The `Mutex` ensures thread-safe access in environments where multi-threading is possible, while the `RefCell`
/// allows for mutable access to the SPI device. This setup is crucial for enabling SPI communications in a safe
/// and controlled manner within the radar sensor's hardware abstraction layer.
///
/// # Safety
///
/// The access to the `SPI_INSTANCE` is controlled via a mutex to prevent concurrent access issues.
/// However, care must be taken to ensure that the SPI device is properly initialized before use
/// and is not accessed after it has been freed or gone out of scope.
static SPI_INSTANCE: Mutex<CriticalSectionRawMutex, RefCell<Option<RefRadarSpi>>> =
Mutex::new(RefCell::new(None));
/// Represents the hardware abstraction layer implementation for the radar sensor.
///
/// This struct encapsulates the necessary functionality to interface with the radar sensor
/// using the SPI communication protocol and provides methods for memory management and logging.
pub struct AccHalImpl {
inner: acc_hal_a121_t,
}
impl AccHalImpl {
/// Constructs a new `AccHalImpl` instance, registering the SPI device and initializing
/// the radar hardware abstraction layer.
///
/// # Arguments
///
/// * `spi` - A reference to an SPI device that implements the `SpiBus` trait.
///
/// # Panics
///
/// Panics if the HAL registration fails.
pub fn new<SPI>(spi: &'static mut SPI) -> Self
where
SPI: SpiDevice<u8, Error = SpiErrorKind> + Send + 'static,
{
let inner = acc_hal_a121_t {
max_spi_transfer_size: u16::MAX,
mem_alloc: Some(mem_alloc),
mem_free: Some(mem_free),
transfer: Some(Self::transfer8_function),
log: Some(c_log_stub),
optimization: acc_hal_optimization_t { transfer16: None },
};
SPI_INSTANCE.lock(|cell| cell.replace(Some(spi)));
Self { inner }
}
/// Transfer function for 16-bit data used by the radar SDK.
///
/// This function is registered as part of the HAL and is called by the radar SDK to
/// perform SPI transfers.
///
/// # Safety
///
/// This function is unsafe as it involves raw pointers and direct hardware access.
#[allow(dead_code)]
extern "C" fn transfer16_function(
_sensor_id: acc_sensor_id_t,
buffer: *mut u16,
buffer_length: usize,
) {
let tmp_buf = unsafe { core::slice::from_raw_parts_mut(buffer, buffer_length) };
trace!(
"Transfer16 function called: buffer={:#X} (size:{})",
tmp_buf,
buffer_length
);
// Borrow a mutable reference to the SpiBus
SPI_INSTANCE.lock(|cell| unsafe {
let mut binding = cell.borrow_mut();
let _spi = binding.as_mut().unwrap_unchecked();
// Perform the SPI transfer
todo!("Perform the SPI 16 transfer");
});
}
extern "C" fn transfer8_function(
_sensor_id: acc_sensor_id_t,
buffer: *mut u8,
buffer_length: usize,
) {
let tmp_buf = unsafe { core::slice::from_raw_parts_mut(buffer, buffer_length) };
trace!(
"Transfer8 function called: buffer={:#X} (size:{})",
tmp_buf,
buffer_length
);
// Borrow a mutable reference to the SpiBus
SPI_INSTANCE.lock(|cell| unsafe {
let mut binding = cell.borrow_mut();
let spi = binding.as_mut().unwrap_unchecked();
// Perform the SPI transfer
spi.transfer_in_place(tmp_buf).unwrap_unchecked();
trace!("Transfer8 function completed, buffer={:#X}", tmp_buf);
});
}
/// Registers the HAL implementation with the radar SDK.
///
/// This method should be called to register the HAL implementation, allowing the
/// radar sensor to communicate using the provided SPI interface.
///
/// # Panics
///
/// Panics if the HAL registration fails.
#[inline(always)]
pub fn register(&self) {
trace!("Registering HAL");
let result = unsafe { acc_rss_hal_register(&self.inner) };
assert!(result, "Failed to register HAL");
}
}
/// Allocates memory for use by the radar SDK.
///
/// # Safety
///
/// This function is unsafe as it performs raw pointer manipulation.
unsafe extern "C" fn mem_alloc(size: usize) -> *mut c_void {
tinyrlibc::malloc(size) as *mut c_void
}
/// Frees memory previously allocated for the radar SDK.
///
/// # Safety
///
/// This function is unsafe as it performs raw pointer manipulation.
unsafe extern "C" fn mem_free(ptr: *mut c_void) {
let ptr = ptr as *mut u8;
tinyrlibc::free(ptr);
}
/// This function is called by the C stub to log messages from the SDK.
/// # Safety
/// This function is unsafe because it takes a raw pointer.
#[no_mangle]
pub unsafe extern "C" fn rust_log(level: c_uint, message: *const c_char) {
let c_str = unsafe { CStr::from_ptr(message) };
let str_slice = c_str.to_str().unwrap_or("");
match level {
0 => defmt::error!("{}", str_slice),
1 => defmt::warn!("{}", str_slice),
2 => defmt::info!("{}", str_slice),
3 => defmt::debug!("{}", str_slice),
4 => defmt::trace!("{}", str_slice),
_ => defmt::error!("Unknown log level: {}", level),
}
}