use embassy_hal_internal::{into_ref, PeripheralRef};
use crate::rcc::RccPeripheral;
use crate::{pac, Peripheral};
#[derive(Debug)]
pub enum HsemError {
LockFailed,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
#[repr(u8)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CoreId {
#[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
Core0 = 0x3,
#[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
Core1 = 0x1,
#[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))]
Core0 = 0x4,
#[cfg(any(stm32wb, stm32wl))]
Core1 = 0x8,
}
#[inline(always)]
pub fn get_current_coreid() -> CoreId {
let cpuid = unsafe { cortex_m::peripheral::CPUID::PTR.read_volatile().base.read() };
match cpuid & 0x000000F0 {
#[cfg(any(stm32wb, stm32wl))]
0x0 => CoreId::Core1,
#[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))]
0x4 => CoreId::Core0,
#[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
0x4 => CoreId::Core1,
#[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
0x7 => CoreId::Core0,
_ => panic!("Unknown Cortex-M core"),
}
}
#[inline(always)]
fn core_id_to_index(core: CoreId) -> usize {
match core {
CoreId::Core0 => 0,
#[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757, stm32wb, stm32wl))]
CoreId::Core1 => 1,
}
}
pub struct HardwareSemaphore<'d, T: Instance> {
_peri: PeripheralRef<'d, T>,
}
impl<'d, T: Instance> HardwareSemaphore<'d, T> {
pub fn new(peripheral: impl Peripheral<P = T> + 'd) -> Self {
into_ref!(peripheral);
HardwareSemaphore { _peri: peripheral }
}
pub fn two_step_lock(&mut self, sem_id: u8, process_id: u8) -> Result<(), HsemError> {
T::regs().r(sem_id as usize).write(|w| {
w.set_procid(process_id);
w.set_coreid(get_current_coreid() as u8);
w.set_lock(true);
});
let reg = T::regs().r(sem_id as usize).read();
match (
reg.lock(),
reg.coreid() == get_current_coreid() as u8,
reg.procid() == process_id,
) {
(true, true, true) => Ok(()),
_ => Err(HsemError::LockFailed),
}
}
pub fn one_step_lock(&mut self, sem_id: u8) -> Result<(), HsemError> {
let reg = T::regs().rlr(sem_id as usize).read();
match (reg.lock(), reg.coreid() == get_current_coreid() as u8, reg.procid()) {
(false, true, 0) => Ok(()),
_ => Err(HsemError::LockFailed),
}
}
pub fn unlock(&mut self, sem_id: u8, process_id: u8) {
T::regs().r(sem_id as usize).write(|w| {
w.set_procid(process_id);
w.set_coreid(get_current_coreid() as u8);
w.set_lock(false);
});
}
pub fn unlock_all(&mut self, key: u16, core_id: u8) {
T::regs().cr().write(|w| {
w.set_key(key);
w.set_coreid(core_id);
});
}
pub fn is_semaphore_locked(&self, sem_id: u8) -> bool {
T::regs().r(sem_id as usize).read().lock()
}
pub fn set_clear_key(&mut self, key: u16) {
T::regs().keyr().modify(|w| w.set_key(key));
}
pub fn get_clear_key(&mut self) -> u16 {
T::regs().keyr().read().key()
}
pub fn enable_interrupt(&mut self, core_id: CoreId, sem_x: usize, enable: bool) {
T::regs()
.ier(core_id_to_index(core_id))
.modify(|w| w.set_ise(sem_x, enable));
}
pub fn is_interrupt_active(&mut self, core_id: CoreId, sem_x: usize) -> bool {
T::regs().isr(core_id_to_index(core_id)).read().isf(sem_x)
}
pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) {
T::regs()
.icr(core_id_to_index(core_id))
.write(|w| w.set_isc(sem_x, false));
}
}
trait SealedInstance {
fn regs() -> pac::hsem::Hsem;
}
#[allow(private_bounds)]
pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {}
impl SealedInstance for crate::peripherals::HSEM {
fn regs() -> crate::pac::hsem::Hsem {
crate::pac::HSEM
}
}
impl Instance for crate::peripherals::HSEM {}