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
use core::marker::PhantomData;

use crate::peripheral::{sealed, Peripheral};

#[cfg(not(esp32s2))]
pub use split::*;

#[cfg(not(esp32h2))]
pub trait WifiModemPeripheral: Peripheral<P = Self> {}

#[cfg(esp32h2)]
pub trait ThreadModemPeripheral: Peripheral<P = Self> {}

#[cfg(not(esp32s2))]
pub trait BluetoothModemPeripheral: Peripheral<P = Self> {}

#[cfg(not(any(esp32s2, esp32h2)))]
pub struct Modem(PhantomData<*const ()>, WifiModem, BluetoothModem);

#[cfg(esp32h2)]
pub struct Modem(PhantomData<*const ()>, ThreadModem, BluetoothModem);

#[cfg(esp32s2)]
pub struct Modem(PhantomData<*const ()>);

impl Modem {
    /// # Safety
    ///
    /// Care should be taken not to instantiate this Mac instance, if it is already instantiated and used elsewhere
    pub unsafe fn new() -> Self {
        #[cfg(not(any(esp32s2, esp32h2)))]
        let this = Modem(PhantomData, WifiModem::new(), BluetoothModem::new());

        #[cfg(esp32h2)]
        let this = Modem(PhantomData, ThreadModem::new(), BluetoothModem::new());

        #[cfg(esp32s2)]
        let this = Modem(PhantomData);

        this
    }

    #[cfg(all(
        not(any(esp32s2, esp32h2)),
        any(
            esp_idf_esp32_wifi_sw_coexist_enable,
            esp_idf_esp_coex_sw_coexist_enable
        )
    ))]
    pub fn split(self) -> (WifiModem, BluetoothModem) {
        unsafe { (WifiModem::new(), BluetoothModem::new()) }
    }

    #[cfg(all(
        not(any(esp32s2, esp32h2)),
        any(
            esp_idf_esp32_wifi_sw_coexist_enable,
            esp_idf_esp_coex_sw_coexist_enable
        )
    ))]
    pub fn split_ref(&mut self) -> (&mut WifiModem, &mut BluetoothModem) {
        (&mut self.1, &mut self.2)
    }

    #[cfg(all(
        esp32h2,
        any(
            esp_idf_esp32_wifi_sw_coexist_enable,
            esp_idf_esp_coex_sw_coexist_enable
        )
    ))]
    pub fn split(self) -> (ThreadModem, BluetoothModem) {
        unsafe { (ThreadModem::new(), BluetoothModem::new()) }
    }

    #[cfg(all(
        esp32h2,
        any(
            esp_idf_esp32_wifi_sw_coexist_enable,
            esp_idf_esp_coex_sw_coexist_enable
        )
    ))]
    pub fn split_ref(&mut self) -> (&mut ThreadModem, &mut BluetoothModem) {
        (&mut self.1, &mut self.2)
    }
}

unsafe impl Send for Modem {}

impl sealed::Sealed for Modem {}

impl Peripheral for Modem {
    type P = Self;

    unsafe fn clone_unchecked(&mut self) -> Self::P {
        Self::new()
    }
}

#[cfg(not(esp32h2))]
impl WifiModemPeripheral for Modem {}

#[cfg(esp32h2)]
impl ThreadModemPeripheral for Modem {}

#[cfg(not(esp32s2))]
impl BluetoothModemPeripheral for Modem {}

#[cfg(not(esp32s2))]
mod split {
    #[cfg(not(esp32h2))]
    crate::impl_peripheral!(WifiModem);

    #[cfg(not(esp32h2))]
    impl super::WifiModemPeripheral for WifiModem {}

    #[cfg(esp32h2)]
    crate::impl_peripheral!(ThreadModem);

    #[cfg(esp32h2)]
    impl super::ThreadModemPeripheral for ThreadModem {}

    crate::impl_peripheral!(BluetoothModem);

    impl super::BluetoothModemPeripheral for BluetoothModem {}
}