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);