diff --git a/rpcs3/Emu/Cell/Modules/cellCrossController.cpp b/rpcs3/Emu/Cell/Modules/cellCrossController.cpp index 273c8dec76..58ecd8ad31 100644 --- a/rpcs3/Emu/Cell/Modules/cellCrossController.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCrossController.cpp @@ -1,7 +1,11 @@ #include "stdafx.h" +#include "Emu/System.h" #include "Emu/Cell/PPUModule.h" +#include "Emu/IdManager.h" +#include "Emu/localized_string.h" #include "cellSysutil.h" #include "cellCrossController.h" +#include "cellMsgDialog.h" LOG_CHANNEL(cellCrossController); @@ -33,15 +37,117 @@ void fmt_class_string::format(std::string& out, u64 ar }); } +void finish_callback(ppu_thread& ppu, s32 button_type, vm::ptr userdata); // Forward declaration + +struct cross_controller +{ + atomic_t status{0}; + std::unique_ptr>> connection_thread; + vm::ptr callback = vm::null; + vm::ptr userdata = vm::null; + + void on_connection_established(s32 status) + { + ensure(!!callback); + + close_msg_dialog(); + + sysutil_register_cb([=](ppu_thread& ppu) -> s32 + { + callback(ppu, CELL_CROSS_CONTROLLER_STATUS_FINALIZED, status, vm::null, userdata); + return CELL_OK; + }); + } + + void run_thread(vm::cptr pPkgInfo) + { + ensure(!!pPkgInfo); + ensure(!!callback); + + const std::string msg = fmt::format("%s\n\n%s", + get_localized_string(localized_string_id::CELL_CROSS_CONTROLLER_MSG, pPkgInfo->pTitle.get_ptr()), + get_localized_string(localized_string_id::CELL_CROSS_CONTROLLER_FW_MSG)); + + vm::bptr msg_dialog_callback = vm::null; + msg_dialog_callback.set(g_fxo->get().func_addr(FIND_FUNC(finish_callback))); + + // TODO: Show icons from comboplay_plugin.rco in dialog. Maybe use a new dialog or add an optional icon to this one. + error_code res = open_msg_dialog(false, CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_OFF, vm::make_str(msg), msg_dialog_callback, userdata); + + sysutil_register_cb([=](ppu_thread& ppu) -> s32 + { + callback(ppu, CELL_CROSS_CONTROLLER_STATUS_INITIALIZED, res == CELL_OK ? CELL_OK : CELL_CROSS_CONTROLLER_ERROR_INTERNAL, vm::null, userdata); + return CELL_OK; + }); + + status = CELL_CROSS_CONTROLLER_STATUS_INITIALIZED; + + connection_thread = std::make_unique>>(fmt::format("Cross-Controller Thread"), [this]() + { + while (thread_ctrl::state() != thread_state::aborting) + { + if (Emu.IsPaused()) + { + thread_ctrl::wait_for(10'000); + continue; + } + + // TODO: establish connection to PS Vita + if (false) + { + on_connection_established(CELL_OK); + } + + thread_ctrl::wait_for(1000); + } + + status = CELL_CROSS_CONTROLLER_STATUS_FINALIZED; + }); + } + + void stop_thread() + { + if (connection_thread) + { + auto& thread = *connection_thread; + thread = thread_state::aborting; + thread(); + connection_thread.reset(); + } + }; +}; + +void finish_callback(ppu_thread& ppu, s32 button_type, vm::ptr userdata) +{ + cross_controller& cc = g_fxo->get(); + + // This function should only be called when the user canceled the dialog + ensure(cc.callback && button_type == CELL_MSGDIALOG_BUTTON_ESCAPE); + + cc.callback(ppu, CELL_CROSS_CONTROLLER_STATUS_FINALIZED, CELL_CROSS_CONTROLLER_ERROR_CANCEL, vm::null, userdata); + cc.stop_thread(); +} + error_code cellCrossControllerInitialize(vm::cptr pParam, vm::cptr pPkgInfo, vm::ptr cb, vm::ptr userdata) // LittleBigPlanet 2 and 3 { cellCrossController.todo("cellCrossControllerInitialize(pParam=*0x%x, pPkgInfo=*0x%x, cb=*0x%x, userdata=*0x%x)", pParam, pPkgInfo, cb, userdata); - // TODO - //if (something) - //{ - // return CELL_CROSS_CONTROLLER_ERROR_INVALID_STATE; - //} + if (pParam) + { + cellCrossController.notice("cellCrossControllerInitialize: pParam: pPackageFileName=%s, pSignatureFileName=%s, pIconFileName=%s", pParam->pPackageFileName, pParam->pSignatureFileName, pParam->pIconFileName); + } + + if (pPkgInfo) + { + cellCrossController.notice("cellCrossControllerInitialize: pPkgInfo: pTitle=%s, pTitleId=%s, pAppVer=%s", pPkgInfo->pTitle, pPkgInfo->pTitleId, pPkgInfo->pAppVer); + } + + cross_controller& cc = g_fxo->get(); + + if (cc.status == CELL_CROSS_CONTROLLER_STATUS_INITIALIZED) // TODO: confirm this logic + { + return CELL_CROSS_CONTROLLER_ERROR_INVALID_STATE; + } if (!pParam || !pPkgInfo) { @@ -73,13 +179,9 @@ error_code cellCrossControllerInitialize(vm::cptr pPar return CELL_CROSS_CONTROLLER_ERROR_INVALID_VALUE; } - sysutil_register_cb([=](ppu_thread& ppu) -> s32 - { - cb(ppu, CELL_CROSS_CONTROLLER_STATUS_INITIALIZED, CELL_OK, vm::null, userdata); - cb(ppu, CELL_CROSS_CONTROLLER_STATUS_FINALIZED, CELL_OK, vm::null, userdata); - - return CELL_OK; - }); + cc.callback = cb; + cc.userdata = userdata; + cc.run_thread(pPkgInfo); return CELL_OK; } @@ -88,4 +190,7 @@ error_code cellCrossControllerInitialize(vm::cptr pPar DECLARE(ppu_module_manager::cellCrossController)("cellCrossController", []() { REG_FUNC(cellCrossController, cellCrossControllerInitialize); + + // Helper Function + REG_HIDDEN_FUNC(finish_callback); }); diff --git a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp index 30954f189e..a06f4fc75d 100644 --- a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp @@ -144,7 +144,7 @@ error_code cellMsgDialogOpen2(u32 type, vm::cptr msgString, vm::ptr msgString, vm::ptr callback, vm::ptr userData, vm::ptr extParam) { - cellSysutil.warning("open_msg_dialog(is_blocking=%d, type=0x%x, msgString=%s, callback=*0x%x, userData=*0x%x, extParam=*0x%x)", is_blocking, type, msgString, callback, userData, extParam); + cellSysutil.notice("open_msg_dialog(is_blocking=%d, type=0x%x, msgString=%s, callback=*0x%x, userData=*0x%x, extParam=*0x%x)", is_blocking, type, msgString, callback, userData, extParam); const MsgDialogType _type{ type }; @@ -263,6 +263,31 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr msgString, return CELL_OK; } +void close_msg_dialog() +{ + cellSysutil.notice("close_msg_dialog()"); + + if (auto manager = g_fxo->try_get()) + { + if (auto dlg = manager->get()) + { + g_fxo->get().wait_until = 0; + dlg->close(false, true); // this doesn't call on_close + sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0); + return; + } + } + + if (const auto dlg = g_fxo->get().get()) + { + dlg->state = MsgDialogState::Close; + g_fxo->get().wait_until = 0; + g_fxo->get().remove(); // this shouldn't call on_close + input::SetIntercepted(false); // so we need to reenable the pads here + sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0); + } +} + void exit_game(s32/* buttonType*/, vm::ptr/* userData*/) { sysutil_send_system_cmd(CELL_SYSUTIL_REQUEST_EXITGAME, 0); @@ -270,7 +295,7 @@ void exit_game(s32/* buttonType*/, vm::ptr/* userData*/) error_code open_exit_dialog(const std::string& message, bool is_exit_requested) { - cellSysutil.warning("open_exit_dialog(message=%s, is_exit_requested=%d)", message, is_exit_requested); + cellSysutil.notice("open_exit_dialog(message=%s, is_exit_requested=%d)", message, is_exit_requested); vm::bptr callback = vm::null; @@ -342,11 +367,6 @@ error_code cellMsgDialogOpen2(u32 type, vm::cptr msgString, vm::ptr g_last_user_response; +void close_msg_dialog(); error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr msgString, vm::ptr callback = vm::null, vm::ptr userData = vm::null, vm::ptr extParam = vm::null); error_code open_exit_dialog(const std::string& message, bool is_exit_requested); diff --git a/rpcs3/Emu/Cell/timers.hpp b/rpcs3/Emu/Cell/timers.hpp index eb0ab767d7..345bb14ceb 100644 --- a/rpcs3/Emu/Cell/timers.hpp +++ b/rpcs3/Emu/Cell/timers.hpp @@ -4,5 +4,9 @@ u64 convert_to_timebased_time(u64 time); u64 get_timebased_time(); + +// Returns some relative time in microseconds, don't change this fact u64 get_system_time(); + +// As get_system_time but obeys Clocks scaling setting. Microseconds. u64 get_guest_system_time(u64 time = umax); diff --git a/rpcs3/Emu/localized_string_id.h b/rpcs3/Emu/localized_string_id.h index b523705905..6542f1542d 100644 --- a/rpcs3/Emu/localized_string_id.h +++ b/rpcs3/Emu/localized_string_id.h @@ -129,6 +129,9 @@ enum class localized_string_id CELL_SAVEDATA_LOAD, CELL_SAVEDATA_OVERWRITE, + CELL_CROSS_CONTROLLER_MSG, + CELL_CROSS_CONTROLLER_FW_MSG, + RPCN_NO_ERROR, RPCN_ERROR_INVALID_INPUT, RPCN_ERROR_WOLFSSL, diff --git a/rpcs3/rpcs3qt/localized_emu.h b/rpcs3/rpcs3qt/localized_emu.h index 03aa2fa767..d66c4880c0 100644 --- a/rpcs3/rpcs3qt/localized_emu.h +++ b/rpcs3/rpcs3qt/localized_emu.h @@ -151,6 +151,8 @@ private: case localized_string_id::CELL_SAVEDATA_DELETE: return tr("Delete this data?\n\n%0", "Savedata entry info").arg(std::forward(args)...); case localized_string_id::CELL_SAVEDATA_LOAD: return tr("Load this data?\n\n%0", "Savedata entry info").arg(std::forward(args)...); case localized_string_id::CELL_SAVEDATA_OVERWRITE: return tr("Do you want to overwrite the saved data?\n\n%0", "Savedata entry info").arg(std::forward(args)...); + case localized_string_id::CELL_CROSS_CONTROLLER_MSG: return tr("Start [%0] on the PS Vita system.\nIf you have not installed [%0], go to [Remote Play] on the PS Vita system and start [Cross-Controller] from the LiveArea™ screen.", "Cross-Controller message").arg(std::forward(args)...); + case localized_string_id::CELL_CROSS_CONTROLLER_FW_MSG: return tr("If your system software version on the PS Vita system is earlier than 1.80, you must update the system software to the latest version.", "Cross-Controller firmware message"); case localized_string_id::RPCN_NO_ERROR: return tr("RPCN: No Error"); case localized_string_id::RPCN_ERROR_INVALID_INPUT: return tr("RPCN: Invalid Input (Wrong Host/Port)"); case localized_string_id::RPCN_ERROR_WOLFSSL: return tr("RPCN Connection Error: WolfSSL Error");