1use core::ops::Range;
23use portable_atomic::{AtomicU8, Ordering};
45pub use self::implementation::*;
67#[cfg_attr(esp32, path = "esp32/mod.rs")]
8#[cfg_attr(esp32c2, path = "esp32c2/mod.rs")]
9#[cfg_attr(esp32c3, path = "esp32c3/mod.rs")]
10#[cfg_attr(esp32c6, path = "esp32c6/mod.rs")]
11#[cfg_attr(esp32h2, path = "esp32h2/mod.rs")]
12#[cfg_attr(esp32s2, path = "esp32s2/mod.rs")]
13#[cfg_attr(esp32s3, path = "esp32s3/mod.rs")]
14mod implementation;
1516mod efuse_field;
1718#[cfg(feature = "psram")]
19mod psram_common;
2021// Using static mut should be fine since we are only writing to it once during
22// initialization. As other tasks and interrupts are not running yet, the worst
23// that can happen is, that the user creates a DMA buffer before initializing
24// the HAL. This will access the PSRAM range, returning an empty range - which
25// is, at that point, true. The user has no (safe) means to allocate in PSRAM
26// before initializing the HAL.
27#[cfg(feature = "psram")]
28static mut MAPPED_PSRAM: MappedPsram = MappedPsram { memory_range: 0..0 };
2930pub(crate) fn psram_range() -> Range<usize> {
31cfg_if::cfg_if! {
32if #[cfg(feature = "psram")] {
33#[allow(static_mut_refs)]
34unsafe { MAPPED_PSRAM.memory_range.clone() }
35 } else {
360..0
37}
38 }
39}
4041const DRAM: Range<usize> = self::constants::SOC_DRAM_LOW..self::constants::SOC_DRAM_HIGH;
4243#[cfg(feature = "psram")]
44pub struct MappedPsram {
45 memory_range: Range<usize>,
46}
4748// Indicates the state of setting the mac address
49// 0 -- unset
50// 1 -- in the process of being set
51// 2 -- set
52//
53// Values other than 0 indicate that we cannot attempt setting the mac address
54// again, and values other than 2 indicate that we should read the mac address
55// from eFuse.
56#[cfg_attr(not(feature = "unstable"), allow(unused))]
57static MAC_OVERRIDE_STATE: AtomicU8 = AtomicU8::new(0);
58#[cfg_attr(not(feature = "unstable"), allow(unused))]
59static mut MAC_OVERRIDE: [u8; 6] = [0; 6];
6061/// Error indicating issues with setting the MAC address.
62#[derive(PartialEq, Eq, Copy, Clone, Debug)]
63#[cfg_attr(not(feature = "unstable"), allow(unused))]
64pub enum SetMacError {
65/// The MAC address has already been set and cannot be changed.
66AlreadySet,
67}
6869#[cfg_attr(not(feature = "unstable"), allow(unused))]
70impl self::efuse::Efuse {
71/// Set the base mac address
72 ///
73 /// The new value will be returned by `read_mac_address` instead of the one
74 /// hard-coded in eFuse. This does not persist across device resets.
75 ///
76 /// Can only be called once. Returns `Err(SetMacError::AlreadySet)`
77 /// otherwise.
78pub fn set_mac_address(mac: [u8; 6]) -> Result<(), SetMacError> {
79if MAC_OVERRIDE_STATE
80 .compare_exchange(0, 1, Ordering::Relaxed, Ordering::Relaxed)
81 .is_err()
82 {
83return Err(SetMacError::AlreadySet);
84 }
8586unsafe {
87 MAC_OVERRIDE = mac;
88 }
8990 MAC_OVERRIDE_STATE.store(2, Ordering::Relaxed);
9192Ok(())
93 }
9495/// Get base mac address
96 ///
97 /// By default this reads the base mac address from eFuse, but it can be
98 /// overridden by `set_mac_address`.
99pub fn mac_address() -> [u8; 6] {
100if MAC_OVERRIDE_STATE.load(Ordering::Relaxed) == 2 {
101unsafe { MAC_OVERRIDE }
102 } else {
103Self::read_base_mac_address()
104 }
105 }
106}
107108#[allow(unused)]
109pub(crate) fn is_valid_ram_address(address: usize) -> bool {
110 addr_in_range(address, DRAM)
111}
112113#[allow(unused)]
114pub(crate) fn is_slice_in_dram<T>(slice: &[T]) -> bool {
115 slice_in_range(slice, DRAM)
116}
117118#[allow(unused)]
119pub(crate) fn is_valid_psram_address(address: usize) -> bool {
120 addr_in_range(address, psram_range())
121}
122123#[allow(unused)]
124pub(crate) fn is_slice_in_psram<T>(slice: &[T]) -> bool {
125 slice_in_range(slice, psram_range())
126}
127128#[allow(unused)]
129pub(crate) fn is_valid_memory_address(address: usize) -> bool {
130 is_valid_ram_address(address) || is_valid_psram_address(address)
131}
132133fn slice_in_range<T>(slice: &[T], range: Range<usize>) -> bool {
134let slice = slice.as_ptr_range();
135let start = slice.start as usize;
136let end = slice.end as usize;
137// `end` is >= `start`, so we don't need to check that `end > range.start`
138 // `end` is also one past the last element, so it can be equal to the range's
139 // end which is also one past the memory region's last valid address.
140addr_in_range(start, range.clone()) && end <= range.end
141}
142143pub(crate) fn addr_in_range(addr: usize, range: Range<usize>) -> bool {
144 range.contains(&addr)
145}