diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 6ce3b82c5..31901a6eb 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -489,6 +489,7 @@ void GMainWindow::ConnectMenuEvents() { connect(ui.action_Install_CIA, &QAction::triggered, this, &GMainWindow::OnMenuInstallCIA); connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); connect(ui.action_Load_Amiibo, &QAction::triggered, this, &GMainWindow::OnLoadAmiibo); + connect(ui.action_Remove_Amiibo, &QAction::triggered, this, &GMainWindow::OnRemoveAmiibo); // Emulation connect(ui.action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame); @@ -825,6 +826,7 @@ void GMainWindow::ShutdownGame() { ui.action_Stop->setEnabled(false); ui.action_Restart->setEnabled(false); ui.action_Load_Amiibo->setEnabled(false); + ui.action_Remove_Amiibo->setEnabled(false); ui.action_Report_Compatibility->setEnabled(false); render_window->hide(); if (game_list->isEmpty()) @@ -1270,9 +1272,9 @@ void GMainWindow::OnLoadAmiibo() { const QString file_filter = tr("Amiibo File") + " (" + extensions + ");;" + tr("All Files (*.*)"); const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), "", file_filter); + if (!filename.isEmpty()) { Core::System& system{Core::System::GetInstance()}; - Service::SM::ServiceManager& sm = system.ServiceManager(); auto nfc = sm.GetService("nfc:u"); if (nfc != nullptr) { @@ -1281,11 +1283,27 @@ void GMainWindow::OnLoadAmiibo() { nfc_module->nfc_filename = filename.toStdString(); nfc_module->nfc_tag_state = Service::NFC::TagState::TagInRange; nfc_module->tag_in_range_event->Signal(); + ui.action_Remove_Amiibo->setEnabled(true); } } } } +void GMainWindow::OnRemoveAmiibo() { + Core::System& system{Core::System::GetInstance()}; + Service::SM::ServiceManager& sm = system.ServiceManager(); + auto nfc = sm.GetService("nfc:u"); + if (nfc != nullptr) { + auto nfc_module = nfc->GetModule(); + if (nfc_module != nullptr) { + nfc_module->nfc_filename = ""; + nfc_module->nfc_tag_state = Service::NFC::TagState::TagOutOfRange; + nfc_module->tag_out_of_range_event->Signal(); + ui.action_Remove_Amiibo->setEnabled(false); + } + } +} + void GMainWindow::OnToggleFilterBar() { game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked()); if (ui.action_Show_Filter_Bar->isChecked()) { diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 562a5ff79..df5ee3346 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -167,6 +167,7 @@ private slots: void OnMenuRecentFile(); void OnConfigure(); void OnLoadAmiibo(); + void OnRemoveAmiibo(); void OnToggleFilterBar(); void OnDisplayTitleBars(bool); void ToggleFullscreen(); diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index 47eb7f395..7a628e877 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -62,7 +62,14 @@ + + + Amiibo + + + + @@ -400,7 +407,15 @@ false - Load Amiibo... + Load... + + + + + false + + + Remove diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index c38ca3c5f..57a53ba6f 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp @@ -12,28 +12,49 @@ namespace Service::NFC { struct TagInfo { - u16 id_offset_size; + u16_le id_offset_size; u8 unk1; u8 unk2; std::array uuid; - INSERT_PADDING_BYTES(0x1D + 3); + INSERT_PADDING_BYTES(0x20); }; static_assert(sizeof(TagInfo) == 0x2C, "TagInfo is an invalid size"); struct AmiiboConfig { - u16 lastwritedate_year; + u16_le lastwritedate_year; u8 lastwritedate_month; u8 lastwritedate_day; - u16 write_counter; + u16_le write_counter; std::array characterID; - u16 amiiboID; + u16_le amiiboID; u8 type; u8 pagex4_byte3; - u16 appdata_size; + u16_le appdata_size; INSERT_PADDING_BYTES(0x30); }; static_assert(sizeof(AmiiboConfig) == 0x40, "AmiiboConfig is an invalid size"); +struct IdentificationBlockRaw { + u16_le char_id; + u8 char_variant; + u8 figure_type; + u16_be model_number; + u8 series; + INSERT_PADDING_BYTES(0x2F); +}; +static_assert(sizeof(IdentificationBlockRaw) == 0x36, "IdentificationBlockRaw is an invalid size"); + +struct IdentificationBlockReply { + u16_le char_id; + u8 char_variant; + u8 series; + u16_le model_number; + u8 figure_type; + INSERT_PADDING_BYTES(0x2F); +}; +static_assert(sizeof(IdentificationBlockReply) == 0x36, + "IdentificationBlockReply is an invalid size"); + void Module::Interface::Initialize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x01, 1, 0); u8 param = rp.Pop(); @@ -96,7 +117,7 @@ void Module::Interface::GetTagInfo(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(12, 0); rb.Push(RESULT_SUCCESS); rb.PushRaw(tag_info); - LOG_CRITICAL(Service_NFC, "called"); + LOG_WARNING(Service_NFC, "(STUBBED) called"); } void Module::Interface::GetAmiiboConfig(Kernel::HLERequestContext& ctx) { @@ -111,7 +132,7 @@ void Module::Interface::GetAmiiboConfig(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(17, 0); rb.Push(RESULT_SUCCESS); rb.PushRaw(amiibo_config); - LOG_CRITICAL(Service_NFC, "called"); + LOG_WARNING(Service_NFC, "(STUBBED) called"); } void Module::Interface::StopTagScanning(Kernel::HLERequestContext& ctx) { @@ -180,6 +201,38 @@ void Module::Interface::CommunicationGetStatus(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NFC, "(STUBBED) called"); } +void Module::Interface::Unknown0x1A(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1A, 0, 0); + + nfc->nfc_tag_state = TagState::Unknown6; + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + LOG_DEBUG(Service_NFC, "called"); +} + +void Module::Interface::Unknown0x1B(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1B, 0, 0); + + IdentificationBlockRaw identification_block_raw{}; + auto nfc_file = FileUtil::IOFile(nfc->nfc_filename, "rb"); + // go to offset of the Amiibo identification block + nfc_file.Seek(0x54, SEEK_SET); + nfc_file.ReadBytes(&identification_block_raw, 0x7); + + IdentificationBlockReply identification_block_reply{}; + identification_block_reply.char_id = identification_block_raw.char_id; + identification_block_reply.char_variant = identification_block_raw.char_variant; + identification_block_reply.series = identification_block_raw.series; + identification_block_reply.model_number = identification_block_raw.model_number; + identification_block_reply.figure_type = identification_block_raw.figure_type; + + IPC::RequestBuilder rb = rp.MakeBuilder(0x1F, 0); + rb.Push(RESULT_SUCCESS); + rb.PushRaw(identification_block_reply); + LOG_DEBUG(Service_NFC, "called"); +} + Module::Interface::Interface(std::shared_ptr nfc, const char* name, u32 max_session) : ServiceFramework(name, max_session), nfc(std::move(nfc)) {} diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h index a443ac08c..7af04431b 100644 --- a/src/core/hle/service/nfc/nfc.h +++ b/src/core/hle/service/nfc/nfc.h @@ -32,6 +32,7 @@ enum class TagState : u8 { TagInRange = 3, TagOutOfRange = 4, TagDataLoaded = 5, + Unknown6 = 6, }; enum class CommunicationStatus : u8 { @@ -189,6 +190,25 @@ public: */ void GetAmiiboConfig(Kernel::HLERequestContext& ctx); + /** + * NFC::Unknown0x1A service function + * Inputs: + * 0 : Header code [0x001A0000] + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void Unknown0x1A(Kernel::HLERequestContext& ctx); + + /** + * NFC::Unknown0x1B service function + * Inputs: + * 0 : Header code [0x001B0000] + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2-31 : 0x36-byte struct + */ + void Unknown0x1B(Kernel::HLERequestContext& ctx); + private: std::shared_ptr nfc; }; diff --git a/src/core/hle/service/nfc/nfc_m.cpp b/src/core/hle/service/nfc/nfc_m.cpp index 9711d95c0..c36ad2ec1 100644 --- a/src/core/hle/service/nfc/nfc_m.cpp +++ b/src/core/hle/service/nfc/nfc_m.cpp @@ -33,6 +33,8 @@ NFC_M::NFC_M(std::shared_ptr nfc) : Module::Interface(std::move(nfc), "n {0x00170000, nullptr, "GetAmiiboSettings"}, {0x00180000, &NFC_M::GetAmiiboConfig, "GetAmiiboConfig"}, {0x00190000, nullptr, "GetAppDataInitStruct"}, + {0x001A0000, &NFC_M::Unknown0x1A, "Unknown0x1A"}, + {0x001B0000, &NFC_M::Unknown0x1B, "Unknown0x1B"}, // nfc:m {0x04040A40, nullptr, "SetAmiiboSettings"} // clang-format on diff --git a/src/core/hle/service/nfc/nfc_u.cpp b/src/core/hle/service/nfc/nfc_u.cpp index 2860e7b27..2363549e5 100644 --- a/src/core/hle/service/nfc/nfc_u.cpp +++ b/src/core/hle/service/nfc/nfc_u.cpp @@ -32,6 +32,8 @@ NFC_U::NFC_U(std::shared_ptr nfc) : Module::Interface(std::move(nfc), "n {0x00170000, nullptr, "GetAmiiboSettings"}, {0x00180000, &NFC_U::GetAmiiboConfig, "GetAmiiboConfig"}, {0x00190000, nullptr, "GetAppDataInitStruct"}, + {0x001A0000, &NFC_U::Unknown0x1A, "Unknown0x1A"}, + {0x001B0000, &NFC_U::Unknown0x1B, "Unknown0x1B"}, // clang-format on }; RegisterHandlers(functions);