1use super::{TargetArch, TargetCapabilities};
6use core::sync::atomic::{Ordering, fence};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum Esp32Variant {
11 Esp32,
13 Esp32S2,
15 Esp32S3,
17 Esp32C3,
19 Esp32C6,
21 Esp32H2,
23}
24
25pub struct Esp32Target {
27 variant: Esp32Variant,
28}
29
30impl Esp32Target {
31 pub const fn new(variant: Esp32Variant) -> Self {
33 Self { variant }
34 }
35
36 pub const fn variant(&self) -> Esp32Variant {
38 self.variant
39 }
40
41 pub const fn is_xtensa(&self) -> bool {
43 matches!(
44 self.variant,
45 Esp32Variant::Esp32 | Esp32Variant::Esp32S2 | Esp32Variant::Esp32S3
46 )
47 }
48
49 pub const fn is_riscv(&self) -> bool {
51 matches!(
52 self.variant,
53 Esp32Variant::Esp32C3 | Esp32Variant::Esp32C6 | Esp32Variant::Esp32H2
54 )
55 }
56}
57
58impl TargetArch for Esp32Target {
59 fn name(&self) -> &'static str {
60 match self.variant {
61 Esp32Variant::Esp32 => "ESP32",
62 Esp32Variant::Esp32S2 => "ESP32-S2",
63 Esp32Variant::Esp32S3 => "ESP32-S3",
64 Esp32Variant::Esp32C3 => "ESP32-C3",
65 Esp32Variant::Esp32C6 => "ESP32-C6",
66 Esp32Variant::Esp32H2 => "ESP32-H2",
67 }
68 }
69
70 fn pointer_size(&self) -> usize {
71 4 }
73
74 fn native_alignment(&self) -> usize {
75 4 }
77
78 fn supports_unaligned_access(&self) -> bool {
79 self.is_xtensa()
82 }
83
84 fn memory_barrier(&self) {
85 memory_barrier();
86 }
87
88 fn cycle_count(&self) -> Option<u64> {
89 cycle_count(self.variant)
90 }
91}
92
93pub fn get_capabilities() -> TargetCapabilities {
95 let variant = detect_variant();
96
97 TargetCapabilities {
98 has_fpu: true, has_simd: false,
100 has_aes: matches!(
101 variant,
102 Esp32Variant::Esp32 | Esp32Variant::Esp32S3 | Esp32Variant::Esp32C6
103 ),
104 has_crc: false,
105 cache_line_size: 32, num_cores: match variant {
107 Esp32Variant::Esp32 | Esp32Variant::Esp32S3 => 2,
108 _ => 1,
109 },
110 }
111}
112
113pub const fn detect_variant() -> Esp32Variant {
115 #[cfg(all(target_arch = "xtensa", esp32))]
116 {
117 Esp32Variant::Esp32
118 }
119
120 #[cfg(all(target_arch = "xtensa", esp32s2))]
121 {
122 Esp32Variant::Esp32S2
123 }
124
125 #[cfg(all(target_arch = "xtensa", esp32s3))]
126 {
127 Esp32Variant::Esp32S3
128 }
129
130 #[cfg(all(target_arch = "riscv32", esp32c3))]
131 {
132 Esp32Variant::Esp32C3
133 }
134
135 #[cfg(all(target_arch = "riscv32", esp32c6))]
136 {
137 Esp32Variant::Esp32C6
138 }
139
140 #[cfg(all(target_arch = "riscv32", esp32h2))]
141 {
142 Esp32Variant::Esp32H2
143 }
144
145 #[cfg(not(any(esp32, esp32s2, esp32s3, esp32c3, esp32c6, esp32h2)))]
146 {
147 Esp32Variant::Esp32 }
149}
150
151#[inline]
153pub fn memory_barrier() {
154 fence(Ordering::SeqCst);
155
156 #[cfg(target_arch = "xtensa")]
157 {
158 unsafe {
159 core::arch::asm!("memw", options(nostack, nomem));
161 }
162 }
163
164 #[cfg(all(target_arch = "riscv32", any(esp32c3, esp32c6, esp32h2)))]
165 {
166 unsafe {
167 core::arch::asm!("fence rw, rw", options(nostack, nomem));
168 }
169 }
170}
171
172#[inline]
174pub fn cycle_count(variant: Esp32Variant) -> Option<u64> {
175 match variant {
176 Esp32Variant::Esp32 | Esp32Variant::Esp32S2 | Esp32Variant::Esp32S3 => {
177 #[cfg(target_arch = "xtensa")]
178 {
179 let count: u32;
180 unsafe {
181 core::arch::asm!(
183 "rsr.ccount {0}",
184 out(reg) count,
185 options(nostack, nomem, preserves_flags)
186 );
187 }
188 Some(count as u64)
189 }
190
191 #[cfg(not(target_arch = "xtensa"))]
192 {
193 None
194 }
195 }
196 Esp32Variant::Esp32C3 | Esp32Variant::Esp32C6 | Esp32Variant::Esp32H2 => {
197 #[cfg(target_arch = "riscv32")]
199 {
200 let low: u32;
201 let high1: u32;
202 let high2: u32;
203
204 unsafe {
205 loop {
206 core::arch::asm!(
207 "rdcycleh {high}",
208 "rdcycle {low}",
209 "rdcycleh {high2}",
210 high = out(reg) high1,
211 low = out(reg) low,
212 high2 = out(reg) high2,
213 options(nostack, nomem, preserves_flags)
214 );
215
216 if high1 == high2 {
217 break;
218 }
219 }
220 }
221
222 Some(((high1 as u64) << 32) | (low as u64))
223 }
224
225 #[cfg(not(target_arch = "riscv32"))]
226 {
227 None
228 }
229 }
230 }
231}
232
233pub mod wireless {
235 use crate::error::Result;
236
237 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
239 pub enum WifiPowerMode {
240 Active,
242 ModemSleep,
244 LightSleep,
246 }
247
248 pub fn set_wifi_power_mode(_mode: WifiPowerMode) -> Result<()> {
250 Ok(())
252 }
253}
254
255pub mod sleep {
257 use crate::error::Result;
258
259 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
261 pub enum WakeupSource {
262 Timer,
264 Gpio,
266 Touchpad,
268 Ulp,
270 }
271
272 pub fn deep_sleep(_duration_us: u64, _sources: &[WakeupSource]) -> Result<()> {
274 Ok(())
276 }
277
278 pub fn light_sleep(_duration_us: u64) -> Result<()> {
280 Ok(())
282 }
283}
284
285pub mod flash {
287 use crate::error::{EmbeddedError, Result};
288
289 pub unsafe fn read(_addr: u32, _buffer: &mut [u8]) -> Result<usize> {
295 Err(EmbeddedError::UnsupportedOperation)
297 }
298
299 pub unsafe fn write(_addr: u32, _data: &[u8]) -> Result<usize> {
305 Err(EmbeddedError::UnsupportedOperation)
307 }
308
309 pub unsafe fn erase_sector(_addr: u32) -> Result<()> {
315 Err(EmbeddedError::UnsupportedOperation)
317 }
318}
319
320#[cfg(any(esp32, esp32s3, esp32c6))]
322pub mod crypto {
323 use crate::error::{EmbeddedError, Result};
324
325 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
327 pub enum AesMode {
328 Ecb,
330 Cbc,
332 Ctr,
334 }
335
336 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
338 pub enum AesKeySize {
339 Aes128,
341 Aes192,
343 Aes256,
345 }
346
347 pub fn aes_encrypt(
349 _mode: AesMode,
350 _key_size: AesKeySize,
351 _key: &[u8],
352 _iv: Option<&[u8]>,
353 _input: &[u8],
354 _output: &mut [u8],
355 ) -> Result<()> {
356 Err(EmbeddedError::UnsupportedOperation)
358 }
359
360 pub fn aes_decrypt(
362 _mode: AesMode,
363 _key_size: AesKeySize,
364 _key: &[u8],
365 _iv: Option<&[u8]>,
366 _input: &[u8],
367 _output: &mut [u8],
368 ) -> Result<()> {
369 Err(EmbeddedError::UnsupportedOperation)
371 }
372}
373
374#[cfg(test)]
375mod tests {
376 use super::*;
377
378 #[test]
379 fn test_esp32_target() {
380 let target = Esp32Target::new(Esp32Variant::Esp32);
381 assert_eq!(target.name(), "ESP32");
382 assert_eq!(target.pointer_size(), 4);
383 assert_eq!(target.native_alignment(), 4);
384 }
385
386 #[test]
387 fn test_variant_detection() {
388 let variant = detect_variant();
389 let _ = variant;
391 }
392
393 #[test]
394 fn test_capabilities() {
395 let caps = get_capabilities();
396 assert!(caps.cache_line_size > 0);
397 assert!(caps.num_cores > 0);
398 }
399}