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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! # Connectivity Features
//!
//! This module provides functionality for initializing and managing WiFi
//! connections on ESP devices, including MQTT messaging
//! The creation of this functionality is inspired by the documentation and
//! examples provided in `esp-wifi` (https://github.com/esp-rs/esp-wifi/tree/main)

#[cfg(feature = "mqtt")]
pub mod mqtt;
pub mod wifi;
// TO BE FIXED (Blocked by "esp-wifi")
// pub mod tiny_mqtt;

/// Macro to obtain a suitable timer based on the ESP device mod
#[cfg(not(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3")))]
#[macro_export]
macro_rules! get_timer {
    ($peripherals:ident, $clocks:ident) => {
        esp_hal::systimer::SystemTimer::new($peripherals.SYSTIMER).alarm0
    };
}

#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
#[macro_export]
macro_rules! get_timer {
    ($peripherals:ident, $clocks:ident) => {
        esp_hal::timer::TimerGroup::new($peripherals.TIMG1, &$clocks).timer0
    };
}

/// Macro to initialize the WiFi interface with the given SSID and password in
/// `mqtt` (or async) configuration. This macro configures the WiFi controller
/// and initializes the WiFi interface.
/// Example:
/// ```no_run
/// let peripherals = take_periph!();
/// let system = take_system!(peripherals);
/// let (clocks, pins) = init_chip!(peripherals, system);
/// let timer = get_timer(peripherals, clocks);
///
/// let mut socket_set_entries: [smoltcp::iface::SocketStorage; 3] = Default::default();
///
/// embassy::init(&clocks, timer);
///
/// let (mut wifi_interface, controller) =
///     init_wifi!(SSID, PASS, peripherals, system, clocks, socket_set_entries);
/// ```
///
/// # Non-async version of function (`mqtt` feature disabled)
/// Initializes the WiFi interface with the given SSID and password. This macro
/// sets up the WiFi controller, starts the WiFi subsystem, and connects to the
/// specified network. It also initiates a WiFi scan and waits for an IP address
/// to be assigned.
///
/// # Arguments
/// * `$ssid` - The SSID of the WiFi network to connect to.
/// * `$password` - The password of the WiFi network.
/// * `$peripherals` - The ESP peripherals instance, providing access to the
///   device's peripherals.
/// * `$system` - The system peripheral instance, used for system-level
///   configurations.
/// * `$clocks` - The clocks configuration, used for timing and delays.
/// * `$sock_entries` - Mutable reference to the socket entries, used for
///   network socket management.
///
/// # Returns
/// Returns a tuple containing the initialized `WifiStack`, along with two
/// buffers for network operations.
///
/// # Usage
/// This macro is intended to be used for setting up WiFi connectivity in
/// environments where asynchronous operations are NOT used.
///
/// # Example
/// ```no_run
/// let (wifi_stack, rx_buffer, tx_buffer) =
///     init_wifi!(SSID, PASSWORD, peripherals, system, clocks, sock_entries);
/// ```
#[cfg(feature = "mqtt")]
#[macro_export]
macro_rules! init_wifi {
    ($ssid:expr, $password:expr, $peripherals:ident, $system:ident, $clocks:ident) => {{
        let init = esp_wifi::initialize(
            esp_wifi::EspWifiInitFor::Wifi,
            esp_ward::get_timer!($peripherals, $clocks),
            esp_hal::rng::Rng::new($peripherals.RNG),
            $system.radio_clock_control,
            &$clocks,
        )
        .unwrap();

        let wifi = $peripherals.WIFI;
        let (wifi_interface, controller) =
            esp_wifi::wifi::new_with_mode(&init, wifi, esp_wifi::wifi::WifiStaDevice).unwrap();

        (wifi_interface, controller)
    }};
}

#[cfg(all(not(feature = "mqtt"), feature = "wifi"))]
#[macro_export]
macro_rules! init_wifi {
    ($ssid:expr, $password:expr, $peripherals:ident, $system:ident, $clocks:ident, $sock_entries:ident) => {{
        let init = esp_wifi::initialize(
            esp_wifi::EspWifiInitFor::Wifi,
            esp_ward::get_timer!($peripherals, $clocks),
            esp_hal::rng::Rng::new($peripherals.RNG),
            $system.radio_clock_control,
            &$clocks,
        )
        .unwrap();

        let wifi = $peripherals.WIFI;
        let (iface, device, mut controller, sockets) =
            esp_wifi::wifi::utils::create_network_interface(
                &init,
                wifi,
                esp_wifi::wifi::WifiStaDevice,
                &mut $sock_entries,
            )
            .unwrap();
        let wifi_stack = esp_wifi::wifi_interface::WifiStack::new(
            iface,
            device,
            sockets,
            esp_wifi::current_millis,
        );

        let client_config =
            esp_wifi::wifi::Configuration::Client(esp_wifi::wifi::ClientConfiguration {
                ssid: $ssid.try_into().unwrap(),
                password: $password.try_into().unwrap(),
                ..Default::default()
            });
        let res = controller.set_configuration(&client_config);
        esp_println::println!("wifi_set_configuration returned {:?}", res);

        controller.start().unwrap();
        esp_println::println!("is wifi started: {:?}", controller.is_started());

        esp_println::println!("Start Wifi Scan");
        let res: Result<
            (heapless::Vec<esp_wifi::wifi::AccessPointInfo, 10>, usize),
            esp_wifi::wifi::WifiError,
        > = controller.scan_n();
        if let Ok((res, _count)) = res {
            for ap in res {
                esp_println::println!("{:?}", ap);
            }
        }

        esp_println::println!("{:?}", controller.get_capabilities());
        esp_println::println!("wifi_connect {:?}", controller.connect());

        // wait to get connected
        esp_println::println!("Wait to get connected");
        loop {
            let res = controller.is_connected();
            match res {
                Ok(connected) => {
                    if connected {
                        break;
                    }
                }
                Err(err) => {
                    esp_println::println!("{:?}", err);
                    loop {}
                }
            }
        }
        esp_println::println!("{:?}", controller.is_connected());

        // wait for getting an ip address
        esp_println::println!("Wait to get an ip address");
        loop {
            wifi_stack.work();

            if wifi_stack.is_iface_up() {
                esp_println::println!("got ip {:?}", wifi_stack.get_ip_info());
                break;
            }
        }

        (wifi_stack, [0u8; 1536], [0u8; 1536])
    }};
}