Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions core/libs/prx/libSceNetCtlApDialog/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
add_library(libSceNetCtlApDialog SHARED EXCLUDE_FROM_ALL Export.cpp)
target_include_directories(libSceNetCtlApDialog PRIVATE ${LIBS_INCLUDE_DIR})
configure_windows_unwind(libSceNetCtlApDialog)

if(BUILD_TESTING)
add_test_executable(guest_netctl_ap_dialog_tests ${LIBS_INCLUDE_DIR}/tests/GuestNetCtlApDialog.cpp)
target_include_directories(guest_netctl_ap_dialog_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_netctl_ap_dialog_tests PRIVATE libSceNetCtlApDialog)
add_test(NAME guest_netctl_ap_dialog COMMAND guest_netctl_ap_dialog_tests)
if(WIN32)
set_tests_properties(guest_netctl_ap_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNetCtlApDialog>")
endif()
endif()
56 changes: 40 additions & 16 deletions core/libs/prx/libSceNetCtlApDialog/Export.cpp
Original file line number Diff line number Diff line change
@@ -1,38 +1,62 @@
#include <atomic>
#include <cstdint>
#include <cstddef>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"

extern "C" {
namespace {

constexpr int STATUS_NONE = 0;
constexpr int STATUS_INITIALIZED = 1;
constexpr int STATUS_RUNNING = 2;
constexpr int STATUS_FINISHED = 3;

constexpr int ERROR_NOT_INITIALIZED = static_cast<int>(0x80412101u);
constexpr int ERROR_BUSY = static_cast<int>(0x8041210Cu);
constexpr int ERROR_INVALID_STATE = static_cast<int>(0x8041210Eu);
constexpr int ERROR_USER_CANCELED = static_cast<int>(0x80412110u);

std::atomic<int> g_status{STATUS_NONE};

int APS5_VABI sceNetCtlApDialogInitialize(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceNetCtlApDialogTerminate(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
extern "C" {

int APS5_VABI sceNetCtlApDialogInitialize(void) {
int expected = STATUS_NONE;
if (!g_status.compare_exchange_strong(expected, STATUS_INITIALIZED)) return ERROR_INVALID_STATE;
return 0;
}

int APS5_VABI sceNetCtlApDialogOpen(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
const int status = g_status.load();
if (status == STATUS_NONE) return ERROR_NOT_INITIALIZED;
if (status == STATUS_RUNNING) return ERROR_BUSY;
g_status = STATUS_FINISHED;
return 0;
}

int APS5_VABI sceNetCtlApDialogClose(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
int APS5_VABI sceNetCtlApDialogGetStatus(void) {
return g_status.load();
}

int APS5_VABI sceNetCtlApDialogUpdateStatus(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
if (g_status.load() == STATUS_NONE) return ERROR_NOT_INITIALIZED;
return g_status.load();
}

int APS5_VABI sceNetCtlApDialogGetResult(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
return ERROR_USER_CANCELED;
}

int APS5_VABI sceNetCtlApDialogClose(void) {
if (g_status.load() == STATUS_NONE) return ERROR_NOT_INITIALIZED;
return 0;
}

int APS5_VABI sceNetCtlApDialogTerminate(void) {
if (g_status.exchange(STATUS_NONE) == STATUS_NONE) return ERROR_NOT_INITIALIZED;
return 0;
}

}
48 changes: 48 additions & 0 deletions core/libs/tests/GuestNetCtlApDialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdlib>

extern "C" {
int APS5_VABI sceNetCtlApDialogInitialize(void);
int APS5_VABI sceNetCtlApDialogOpen(void);
int APS5_VABI sceNetCtlApDialogGetStatus(void);
int APS5_VABI sceNetCtlApDialogUpdateStatus(void);
int APS5_VABI sceNetCtlApDialogGetResult(void);
int APS5_VABI sceNetCtlApDialogClose(void);
int APS5_VABI sceNetCtlApDialogTerminate(void);
}

namespace {

void Require(bool value) { if (!value) std::abort(); }

constexpr int kStatusFinished = 3;
constexpr int kErrNotInitialized = static_cast<int>(0x80412101);
constexpr int kErrInvalidState = static_cast<int>(0x8041210E);
constexpr int kErrUserCanceled = static_cast<int>(0x80412110);

}

int main() {
Require(sceNetCtlApDialogTerminate() == kErrNotInitialized);
Require(sceNetCtlApDialogOpen() == kErrNotInitialized);
Require(sceNetCtlApDialogUpdateStatus() == kErrNotInitialized);

Require(sceNetCtlApDialogInitialize() == 0);
Require(sceNetCtlApDialogInitialize() == kErrInvalidState);

Require(sceNetCtlApDialogGetStatus() == 1);
Require(sceNetCtlApDialogGetResult() == kErrUserCanceled);

Require(sceNetCtlApDialogOpen() == 0);
Require(sceNetCtlApDialogGetStatus() == kStatusFinished);
Require(sceNetCtlApDialogUpdateStatus() == kStatusFinished);

Require(sceNetCtlApDialogOpen() == 0);
Require(sceNetCtlApDialogGetStatus() == kStatusFinished);

Require(sceNetCtlApDialogClose() == 0);
Require(sceNetCtlApDialogTerminate() == 0);
Require(sceNetCtlApDialogTerminate() == kErrNotInitialized);
return 0;
}
1 change: 1 addition & 0 deletions docs/dev/TechnicalDebt.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Throughout the project, every function at every stage either **does exactly what
- [libSceCommonDialog](../../core/libs/prx/libSceCommonDialog/Export.cpp)
- [libSceErrorDialog](../../core/libs/prx/libSceErrorDialog/Export.cpp) - the error dialog runs the state machine but shows nothing; the error code passed to `sceErrorDialogOpen` is only logged
- [libSceLoginDialog](../../core/libs/prx/libSceLoginDialog/Export.cpp) - the login dialog runs the common-dialog state machine but shows nothing and reports the user as having cancelled
- [libSceNetCtlApDialog](../../core/libs/prx/libSceNetCtlApDialog/Export.cpp) - the access-point dialog runs the common-dialog state machine but shows nothing and reports the user as having cancelled: `sceNetCtlApDialogGetResult` returns the user-canceled error (0x80412110) without any result out-argument, whose existence on the console is unknown. All seven NIDs of the library are known from [shadPS4's aerolib](https://github.com/shadps4-emu/shadPS4/blob/main/scripts/aerolib.inl); the signatures (every function takes no argument) and the error codes (from libSceNetCtl's measured 0x804121xx range: NOT_INITIALIZED 0x80412101, BUSY 0x8041210C, INVALID_STATE 0x8041210E) are assumed, not verified on a PS5 title or hardware
- [libSceCdlgG2P](../../core/libs/prx/libSceCdlgG2P/Export.cpp) - the G2P dialog runs the common-dialog state machine but shows nothing and reports the user as having cancelled. The signatures (`Open` and `GetResult` take a pointer, the others none) and the leading `int32` result are assumed from the other common dialogs, not verified for G2P; PPSA01289 imports it
- [libSceVrSetupDialog](../../core/libs/prx/libSceVrSetupDialog/Export.cpp) - the VR setup dialog runs the common-dialog state machine but shows nothing and reports the user as having cancelled, as no headset is supported (see libSceHmd2). The signatures are assumed from the other common dialogs; PPSA12544 imports it
- [libSceHmd](../../core/libs/prx/libSceHmd/Export.cpp) implements only the disconnected-headset path: initialization succeeds, device queries report `NotDetected`, and opening a device returns `DeviceDisconnected`. Headset support, tracking, rendering and additional HMD exports are not implemented; SDK-level ABI compatibility and in-game behaviour remain unverified.
Expand Down
Loading