ctru/services/
ac.rs

1//! The Automatic Connection (AC) service handles Wi-Fi and network settings.
2//! It can:
3//! - Connect to a network or slot
4//! - Get information about a network, such as its SSID or security settings
5use crate::error::ResultCode;
6use crate::services::ServiceReference;
7use std::sync::Mutex;
8/// Handle to the Automatic Connection (AC) service, that handles Wi-Fi and network settings.
9pub struct Ac {
10    _service_handler: ServiceReference,
11}
12
13static AC_ACTIVE: Mutex<()> = Mutex::new(());
14
15impl Ac {
16    /// Initialize a new service handle.
17    ///
18    /// # Example
19    ///
20    /// ```
21    /// # let _runner = test_runner::GdbRunner::default();
22    /// # use std::error::Error;
23    /// # fn main() -> Result<(), Box<dyn Error>> {
24    /// #
25    /// use ctru::services::ac::Ac;
26    ///
27    /// let ac = Ac::new()?;
28    /// #
29    /// # Ok(())
30    /// # }
31    /// ```
32    #[doc(alias = "acInit")]
33    pub fn new() -> crate::Result<Ac> {
34        Ok(Ac {
35            _service_handler: ServiceReference::new(
36                &AC_ACTIVE,
37                || {
38                    ResultCode(unsafe { ctru_sys::acInit() })?;
39
40                    Ok(())
41                },
42                || unsafe {
43                    ctru_sys::acExit();
44                },
45            )?,
46        })
47    }
48
49    /// Waits for an internet connection.
50    ///
51    /// # Example
52    ///
53    /// ```
54    /// # let _runner = test_runner::GdbRunner::default();
55    /// # use std::error::Error;
56    /// # fn main() -> Result<(), Box<dyn Error>> {
57    /// #
58    /// use ctru::services::ac::Ac;
59    ///
60    /// let ac = Ac::new()?;
61    ///
62    /// println!("Waiting for an internet connection...");
63    /// ac.wait_internet_connection()?;
64    /// println!("Connected.");
65    /// #
66    /// # Ok(())
67    /// # }
68    /// ```
69    #[doc(alias = "acWaitInternetConnection")]
70    pub fn wait_internet_connection(&self) -> crate::Result<()> {
71        unsafe {
72            ResultCode(ctru_sys::acWaitInternetConnection())?;
73
74            Ok(())
75        }
76    }
77
78    /// Returns the current Wi-Fi connection status.
79    ///
80    /// # Example
81    ///
82    /// ```
83    /// # let _runner = test_runner::GdbRunner::default();
84    /// # use std::error::Error;
85    /// # fn main() -> Result<(), Box<dyn Error>> {
86    /// #
87    /// use ctru::services::ac::Ac;
88    ///
89    /// let ac = Ac::new()?;
90    ///
91    /// println!("Wi-Fi status: {:?}", ac.wifi_status()?);
92    /// #
93    /// # Ok(())
94    /// # }
95    /// ```
96    #[doc(alias = "ACU_GetWifiStatus")]
97    pub fn wifi_status(&self) -> crate::Result<NetworkStatus> {
98        unsafe {
99            let mut ret = 0u32;
100            ResultCode(ctru_sys::ACU_GetStatus(&mut ret))?;
101
102            Ok(match ret {
103                0 => NetworkStatus::None,
104                1 => NetworkStatus::Idle,
105                2 => NetworkStatus::LANConnected,
106                3 => NetworkStatus::WANConnected,
107                _ => return Err(crate::Error::Other(format!("Unknown value {ret}"))),
108            })
109        }
110    }
111
112    /// Returns the [`SecurityMode`] of the currently connected network, or error if the console isn't connected to any network.
113    ///
114    /// You can check if the console is connected to a network using [`Ac::wifi_status()`].
115    /// # Example
116    ///
117    /// ```
118    /// # let _runner = test_runner::GdbRunner::default();
119    /// # use std::error::Error;
120    /// # fn main() -> Result<(), Box<dyn Error>> {
121    /// #
122    /// use ctru::services::ac::{Ac, NetworkStatus};
123    ///
124    /// let ac = Ac::new()?;
125    ///
126    /// if ac.wifi_status()? == NetworkStatus::WANConnected {
127    ///     println!("Network security: {:?}", ac.wifi_security()?);
128    /// }
129    ///
130    /// #
131    /// # Ok(())
132    /// # }
133    /// ```
134    #[doc(alias = "ACU_GetWifiSecurityMode")]
135    pub fn wifi_security(&self) -> crate::Result<SecurityMode> {
136        unsafe {
137            let mut ret = 0u8;
138            ResultCode(ctru_sys::ACU_GetSecurityMode(&mut ret))?;
139            // fix this, for some reason the bindings have the type as a struct and not enum
140            // and so i can't impl TryFrom automatically
141            Ok(match ret {
142                0 => SecurityMode::Open,
143
144                1 => SecurityMode::WEP40Bit,
145                2 => SecurityMode::WEP104Bit,
146                3 => SecurityMode::WEP128Bit,
147
148                4 => SecurityMode::WPA_TKIP,
149                5 => SecurityMode::WPA2_TKIP,
150
151                6 => SecurityMode::WPA_AES,
152                7 => SecurityMode::WPA2_AES,
153
154                _ => return Err(crate::Error::Other(format!("Unknown value {ret}"))),
155            })
156        }
157    }
158
159    /// Returns the SSID of the Wi-Fi network the console is connected to, or error if the console isn't connected to any network.
160    ///
161    /// You can check if the console is connected to a network using [`Ac::wifi_status()`].
162    ///
163    /// # Example
164    ///
165    /// ```
166    /// # let _runner = test_runner::GdbRunner::default();
167    /// # use std::error::Error;
168    /// # fn main() -> Result<(), Box<dyn Error>> {
169    /// #
170    /// use ctru::services::ac::Ac;
171    ///
172    /// let ac = Ac::new()?;
173    ///
174    /// println!("The console is connected to the network \"{}\"", String::from_utf8(ac.wifi_ssid()?)?);
175    /// #
176    /// # Ok(())
177    /// # }
178    /// ```
179    #[doc(alias = "ACU_GetSSID")]
180    pub fn wifi_ssid(&self) -> crate::Result<Vec<u8>> {
181        unsafe {
182            let mut len = 0u32;
183            ResultCode(ctru_sys::ACU_GetSSIDLength(&mut len))?;
184            // we don't really need space for the terminator
185            let mut vec = vec![0u8; len as usize];
186            ResultCode(ctru_sys::ACU_GetSSID(vec.as_mut_ptr()))?;
187            Ok(vec)
188        }
189    }
190
191    /// Returns whether the console is connected to a proxy.
192    ///
193    /// # Example
194    ///
195    /// ```
196    /// # let _runner = test_runner::GdbRunner::default();
197    /// # use std::error::Error;
198    /// # fn main() -> Result<(), Box<dyn Error>> {
199    /// #
200    /// use ctru::services::ac::Ac;
201    ///
202    /// let ac = Ac::new()?;
203    ///
204    /// println!("Proxy enabled: {}", ac.proxy_enabled()?);
205    ///
206    /// #
207    /// # Ok(())
208    /// # }
209    /// ```
210    #[doc(alias = "ACU_GetProxyEnable")]
211    pub fn proxy_enabled(&self) -> crate::Result<bool> {
212        unsafe {
213            let mut ret = false;
214            ResultCode(ctru_sys::ACU_GetProxyEnable(&mut ret))?;
215
216            Ok(ret)
217        }
218    }
219
220    /// Returns the connected network's proxy port, if present.
221    ///
222    /// You can check if the console is using a proxy with [`Ac::proxy_enabled()`]
223    ///
224    /// # Example
225    ///
226    /// ```
227    /// # let _runner = test_runner::GdbRunner::default();
228    /// # use std::error::Error;
229    /// # fn main() -> Result<(), Box<dyn Error>> {
230    /// #
231    /// use ctru::services::ac::Ac;
232    ///
233    /// let ac = Ac::new()?;
234    ///
235    /// println!("Proxy port: {}", ac.proxy_port()?);
236    /// #
237    /// # Ok(())
238    /// # }
239    /// ```
240    #[doc(alias = "ACU_GetProxyPort")]
241    pub fn proxy_port(&self) -> crate::Result<u16> {
242        unsafe {
243            let mut ret = 0u16;
244            ResultCode(ctru_sys::ACU_GetProxyPort(&mut ret))?;
245
246            Ok(ret)
247        }
248    }
249
250    /// Returns the connected network's proxy username, if present.
251    ///
252    /// You can check if the console is using a proxy with [`Ac::proxy_enabled()`]
253    ///
254    /// # Example
255    ///
256    /// ```
257    /// # let _runner = test_runner::GdbRunner::default();
258    /// # use std::error::Error;
259    /// # fn main() -> Result<(), Box<dyn Error>> {
260    /// #
261    /// use ctru::services::ac::Ac;
262    ///
263    /// let ac = Ac::new()?;
264    ///
265    /// println!("Proxy username: {}", String::from_utf8(ac.proxy_username()?)?);
266    ///
267    /// #
268    /// # Ok(())
269    /// # }
270    /// ```
271    #[doc(alias = "ACU_GetProxyUserName")]
272    pub fn proxy_username(&self) -> crate::Result<Vec<u8>> {
273        unsafe {
274            let mut vec = vec![0u8; 0x20];
275            ResultCode(ctru_sys::ACU_GetProxyUserName(vec.as_mut_ptr()))?;
276
277            Ok(vec)
278        }
279    }
280
281    /// Returns the connected network's proxy password, if present.
282    ///
283    /// You can check if the console is using a proxy with [`Ac::proxy_enabled()`]
284    ///
285    /// # Example
286    ///
287    /// ```
288    /// # let _runner = test_runner::GdbRunner::default();
289    /// # use std::error::Error;
290    /// # fn main() -> Result<(), Box<dyn Error>> {
291    /// #
292    /// use ctru::services::ac::Ac;
293    ///
294    /// let ac = Ac::new()?;
295    ///
296    /// println!("Proxy password: {}", String::from_utf8(ac.proxy_password()?)?);
297    /// #
298    /// # Ok(())
299    /// # }
300    /// ```
301    #[doc(alias = "ACU_GetProxyPassword")]
302    pub fn proxy_password(&self) -> crate::Result<Vec<u8>> {
303        unsafe {
304            let mut vec = vec![0u8; 0x20];
305            ResultCode(ctru_sys::ACU_GetProxyPassword(vec.as_mut_ptr()))?;
306
307            Ok(vec)
308        }
309    }
310
311    /// Load the selected network slot, if present.
312    ///
313    /// Note: this method requires `ac:i` access
314    /// # Example
315    ///
316    /// ```
317    /// # let _runner = test_runner::GdbRunner::default();
318    /// # use std::error::Error;
319    /// # fn main() -> Result<(), Box<dyn Error>> {
320    /// #
321    /// use ctru::services::ac::{Ac, NetworkSlot};
322    ///
323    /// let mut ac = Ac::new()?;
324    ///
325    /// ac.load_network_slot(NetworkSlot::Second)?;
326    /// #
327    /// # Ok(())
328    /// # }
329    /// ```
330    #[doc(alias = "ACI_LoadNetworkSetting")]
331    pub fn load_network_slot(&mut self, slot: NetworkSlot) -> crate::Result<()> {
332        unsafe {
333            ResultCode(ctru_sys::ACI_LoadNetworkSetting(slot as u32))?;
334            Ok(())
335        }
336    }
337}
338
339#[doc(alias = "acSecurityMode")]
340#[derive(Debug, Clone, Copy, PartialEq, Eq)]
341#[repr(u8)]
342#[non_exhaustive]
343#[allow(non_camel_case_types)]
344/// Represents all the supported Wi-Fi security modes.
345pub enum SecurityMode {
346    /// No authentication
347    Open = ctru_sys::AC_OPEN,
348    /// WEP 40bit authentication
349    WEP40Bit = ctru_sys::AC_WEP_40BIT,
350    /// WEP 104bit authentication
351    WEP104Bit = ctru_sys::AC_WEP_104BIT,
352    /// WEP 128bit authentication
353    WEP128Bit = ctru_sys::AC_WEP_128BIT,
354    /// WPA-TKIP authentication
355    WPA_TKIP = ctru_sys::AC_WPA_TKIP,
356    /// WPA2-TKIP authentication
357    WPA2_TKIP = ctru_sys::AC_WPA2_TKIP,
358    /// WPA-AES authentication
359    WPA_AES = ctru_sys::AC_WPA_AES,
360    /// WPA2-AES authentication
361    WPA2_AES = ctru_sys::AC_WPA2_AES,
362}
363
364#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
365#[repr(u32)]
366/// Represents a network slot, like in the System Settings
367pub enum NetworkSlot {
368    /// The first network slot
369    First = 0,
370    /// The second network slot
371    Second = 1,
372    /// The third network slot
373    Third = 2,
374}
375
376#[derive(Debug, Clone, Copy, PartialEq, Eq)]
377#[repr(u32)]
378#[non_exhaustive]
379/// Represents the current Wi-Fi status
380pub enum NetworkStatus {
381    /// Wi-Fi turned off
382    None = 0,
383    /// Not connected
384    Idle = 1,
385    /// Connected, only LAN.
386    LANConnected = 2,
387    /// Connected to the Internet.
388    WANConnected = 3,
389}
390
391from_impl!(SecurityMode, ctru_sys::acSecurityMode);