psp_net/
utils.rs

1use alloc::{borrow::ToOwned, string::String};
2use thiserror::Error;
3
4/// Error type for net functions
5#[derive(Debug, Clone, PartialEq, Eq, Error)]
6#[must_use]
7pub enum NetError {
8    /// Failed to load a net module
9    #[error("Failed to load module {}: {}", 0, 1)]
10    LoadModuleFailed(String, i32),
11    /// Failed to initialize
12    #[error("Failed to initialize {}: {}", 0, 1)]
13    InitFailed(String, i32),
14    /// An error occurred when using a net function
15    #[error("{}: {}", 0, 1)]
16    Error(String, i32),
17    /// Net config Do not exist
18    #[error("Net config does not exist")]
19    NetConfigNotExist,
20    /// Timeout
21    #[error("Timeout")]
22    Timeout,
23}
24
25impl NetError {
26    pub fn load_module_failed(module: &str, error: i32) -> Self {
27        NetError::LoadModuleFailed(module.to_owned(), error)
28    }
29
30    pub fn init_failed(fn_name: &str, error: i32) -> Self {
31        NetError::InitFailed(fn_name.to_owned(), error)
32    }
33
34    pub fn error(fn_name: &str, error: i32) -> Self {
35        NetError::Error(fn_name.to_owned(), error)
36    }
37}
38
39/// Load net modules
40///
41/// # Errors
42/// - [`NetError::LoadModuleFailed`] if the net module could not be loaded
43#[allow(unused)]
44#[inline]
45pub fn load_net_modules() -> Result<(), NetError> {
46    unsafe {
47        let res = psp::sys::sceUtilityLoadNetModule(psp::sys::NetModule::NetCommon);
48        if res != 0 {
49            return Err(NetError::load_module_failed("", res));
50        }
51
52        let res = psp::sys::sceUtilityLoadNetModule(psp::sys::NetModule::NetInet);
53        if res != 0 {
54            return Err(NetError::load_module_failed("", res));
55        }
56
57        let res = psp::sys::sceUtilityLoadNetModule(psp::sys::NetModule::NetParseUri);
58        if res != 0 {
59            return Err(NetError::load_module_failed("", res));
60        }
61
62        let res = psp::sys::sceUtilityLoadNetModule(psp::sys::NetModule::NetHttp);
63        if res != 0 {
64            return Err(NetError::load_module_failed("", res));
65        }
66
67        Ok(())
68    }
69}
70
71/// Initialize network
72///
73/// # Errors
74/// - [`NetError::InitFailed`] if the net could not be initialized
75#[allow(unused)]
76#[inline]
77pub fn net_init() -> Result<(), NetError> {
78    unsafe {
79        let res = psp::sys::sceNetInit(0x20000, 0x20, 0x1000, 0x20, 0x1000);
80        if res != 0 {
81            return Err(NetError::init_failed("sceNetInit", res));
82        }
83
84        let res = psp::sys::sceNetInetInit();
85        if res != 0 {
86            return Err(NetError::init_failed("sceNetInetInit", res));
87        }
88
89        let res = psp::sys::sceNetResolverInit();
90        if res != 0 {
91            return Err(NetError::init_failed("sceNetResolverInit", res));
92        }
93
94        let res = psp::sys::sceNetApctlInit(0x1600, 42);
95        if res != 0 {
96            return Err(NetError::init_failed("sceNetApctlInit", res));
97        }
98    }
99
100    Ok(())
101}
102
103/// Check existence of net config
104///
105/// # Errors
106/// - [`NetError::NetConfigNotExist`] if the net config does not exist
107///
108/// # Notes
109/// The netconfigs start from 1.
110///
111/// Remember that this function requires the [net modules](crate::utils::load_net_modules) to be loaded, and
112/// [initialised](crate::utils::net_init) first.
113#[allow(unused)]
114#[inline]
115pub fn check_netconfig_existence(id: i32) -> Result<(), NetError> {
116    unsafe {
117        let res = psp::sys::sceUtilityCheckNetParam(id);
118        if res != 0 {
119            return Err(NetError::NetConfigNotExist);
120        }
121    }
122
123    Ok(())
124}
125
126/// Check existence of first net config
127///
128/// # Errors
129/// Same as [`check_netconfig_existence`]
130#[allow(unused)]
131#[inline]
132pub fn check_first_netconfig_existence() -> Result<(), NetError> {
133    check_netconfig_existence(1)
134}
135
136/// Initialise a connection to an access point
137///
138/// # Parameters
139/// - `connection_id`: The ID of the access point to connect to
140///
141/// # Errors
142/// [`NetError::Error`] if the connection initialisation failed
143///
144/// # Notes
145/// The access point ID is a number greater or equal to 1. It is the index of the
146/// access point in the netconfig.
147///
148/// This function does not block until the connection is established.
149/// Use [`block_until_connected`] right after
150/// this function to block until the connection is established.
151pub fn init_connection_to_access_point(connection_id: i32) -> Result<(), NetError> {
152    unsafe {
153        let res = psp::sys::sceNetApctlConnect(connection_id);
154        if res != 0 {
155            return Err(NetError::error("sceNetApctlConnect", res));
156        }
157    }
158
159    Ok(())
160}
161
162/// Block until connected
163///
164/// Polls the access point state until connection is established, `desist_after` times
165/// is reached, or an error occurs.
166/// The polling is done at 50ms intervals using [`sceKernelDelayThread`](psp::sys::sceKernelDelayThread).
167///
168/// # Parameters
169/// - `desist_after`: The number of times to poll the state before desisting
170///
171/// # Errors
172/// Same as [`init_connection_to_access_point`]
173#[inline]
174pub fn block_until_connected(desist_after: usize) -> Result<(), NetError> {
175    let mut state: psp::sys::ApctlState = unsafe { core::mem::zeroed() };
176    for _ in 0..desist_after {
177        unsafe {
178            let err = psp::sys::sceNetApctlGetState(&mut state);
179            if err != 0 {
180                return Err(NetError::error("sceNetApctlGetState", err));
181            }
182        }
183        if let psp::sys::ApctlState::GotIp = state {
184            return Ok(());
185        }
186        unsafe { psp::sys::sceKernelDelayThread(50_000) };
187    }
188
189    Err(NetError::Timeout)
190}