diff options
Diffstat (limited to '')
25 files changed, 1165 insertions, 193 deletions
diff --git a/src/common/input.h b/src/common/input.h index 66fb15f0a..ea30770ae 100644 --- a/src/common/input.h +++ b/src/common/input.h | |||
| @@ -86,7 +86,7 @@ enum class NfcState { | |||
| 86 | NewAmiibo, | 86 | NewAmiibo, |
| 87 | WaitingForAmiibo, | 87 | WaitingForAmiibo, |
| 88 | AmiiboRemoved, | 88 | AmiiboRemoved, |
| 89 | NotAnAmiibo, | 89 | InvalidTagType, |
| 90 | NotSupported, | 90 | NotSupported, |
| 91 | WrongDeviceState, | 91 | WrongDeviceState, |
| 92 | WriteFailed, | 92 | WriteFailed, |
| @@ -218,8 +218,22 @@ struct CameraStatus { | |||
| 218 | }; | 218 | }; |
| 219 | 219 | ||
| 220 | struct NfcStatus { | 220 | struct NfcStatus { |
| 221 | NfcState state{}; | 221 | NfcState state{NfcState::Unknown}; |
| 222 | std::vector<u8> data{}; | 222 | u8 uuid_length; |
| 223 | u8 protocol; | ||
| 224 | u8 tag_type; | ||
| 225 | std::array<u8, 10> uuid; | ||
| 226 | }; | ||
| 227 | |||
| 228 | struct MifareData { | ||
| 229 | u8 command; | ||
| 230 | u8 sector; | ||
| 231 | std::array<u8, 0x6> key; | ||
| 232 | std::array<u8, 0x10> data; | ||
| 233 | }; | ||
| 234 | |||
| 235 | struct MifareRequest { | ||
| 236 | std::array<MifareData, 0x10> data; | ||
| 223 | }; | 237 | }; |
| 224 | 238 | ||
| 225 | // List of buttons to be passed to Qt that can be translated | 239 | // List of buttons to be passed to Qt that can be translated |
| @@ -294,7 +308,7 @@ struct CallbackStatus { | |||
| 294 | BatteryStatus battery_status{}; | 308 | BatteryStatus battery_status{}; |
| 295 | VibrationStatus vibration_status{}; | 309 | VibrationStatus vibration_status{}; |
| 296 | CameraFormat camera_status{CameraFormat::None}; | 310 | CameraFormat camera_status{CameraFormat::None}; |
| 297 | NfcState nfc_status{NfcState::Unknown}; | 311 | NfcStatus nfc_status{}; |
| 298 | std::vector<u8> raw_data{}; | 312 | std::vector<u8> raw_data{}; |
| 299 | }; | 313 | }; |
| 300 | 314 | ||
| @@ -356,9 +370,30 @@ public: | |||
| 356 | return NfcState::NotSupported; | 370 | return NfcState::NotSupported; |
| 357 | } | 371 | } |
| 358 | 372 | ||
| 373 | virtual NfcState StartNfcPolling() { | ||
| 374 | return NfcState::NotSupported; | ||
| 375 | } | ||
| 376 | |||
| 377 | virtual NfcState StopNfcPolling() { | ||
| 378 | return NfcState::NotSupported; | ||
| 379 | } | ||
| 380 | |||
| 381 | virtual NfcState ReadAmiiboData([[maybe_unused]] std::vector<u8>& out_data) { | ||
| 382 | return NfcState::NotSupported; | ||
| 383 | } | ||
| 384 | |||
| 359 | virtual NfcState WriteNfcData([[maybe_unused]] const std::vector<u8>& data) { | 385 | virtual NfcState WriteNfcData([[maybe_unused]] const std::vector<u8>& data) { |
| 360 | return NfcState::NotSupported; | 386 | return NfcState::NotSupported; |
| 361 | } | 387 | } |
| 388 | |||
| 389 | virtual NfcState ReadMifareData([[maybe_unused]] const MifareRequest& request, | ||
| 390 | [[maybe_unused]] MifareRequest& out_data) { | ||
| 391 | return NfcState::NotSupported; | ||
| 392 | } | ||
| 393 | |||
| 394 | virtual NfcState WriteMifareData([[maybe_unused]] const MifareRequest& request) { | ||
| 395 | return NfcState::NotSupported; | ||
| 396 | } | ||
| 362 | }; | 397 | }; |
| 363 | 398 | ||
| 364 | /// An abstract class template for a factory that can create input devices. | 399 | /// An abstract class template for a factory that can create input devices. |
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 0a7777732..c937495f9 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -149,12 +149,16 @@ void EmulatedController::LoadDevices() { | |||
| 149 | 149 | ||
| 150 | camera_params[0] = right_joycon; | 150 | camera_params[0] = right_joycon; |
| 151 | camera_params[0].Set("camera", true); | 151 | camera_params[0].Set("camera", true); |
| 152 | camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"}; | ||
| 153 | ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; | ||
| 154 | nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; | ||
| 155 | nfc_params[1] = right_joycon; | 152 | nfc_params[1] = right_joycon; |
| 156 | nfc_params[1].Set("nfc", true); | 153 | nfc_params[1].Set("nfc", true); |
| 157 | 154 | ||
| 155 | // Only map virtual devices to the first controller | ||
| 156 | if (npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld) { | ||
| 157 | camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"}; | ||
| 158 | ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; | ||
| 159 | nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; | ||
| 160 | } | ||
| 161 | |||
| 158 | output_params[LeftIndex] = left_joycon; | 162 | output_params[LeftIndex] = left_joycon; |
| 159 | output_params[RightIndex] = right_joycon; | 163 | output_params[RightIndex] = right_joycon; |
| 160 | output_params[2] = camera_params[1]; | 164 | output_params[2] = camera_params[1]; |
| @@ -1176,10 +1180,7 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { | |||
| 1176 | return; | 1180 | return; |
| 1177 | } | 1181 | } |
| 1178 | 1182 | ||
| 1179 | controller.nfc_state = { | 1183 | controller.nfc_state = controller.nfc_values; |
| 1180 | controller.nfc_values.state, | ||
| 1181 | controller.nfc_values.data, | ||
| 1182 | }; | ||
| 1183 | } | 1184 | } |
| 1184 | 1185 | ||
| 1185 | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { | 1186 | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { |
| @@ -1308,6 +1309,73 @@ bool EmulatedController::HasNfc() const { | |||
| 1308 | return is_connected && (has_virtual_nfc && is_virtual_nfc_supported); | 1309 | return is_connected && (has_virtual_nfc && is_virtual_nfc_supported); |
| 1309 | } | 1310 | } |
| 1310 | 1311 | ||
| 1312 | bool EmulatedController::AddNfcHandle() { | ||
| 1313 | nfc_handles++; | ||
| 1314 | return SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::NFC) == | ||
| 1315 | Common::Input::DriverResult::Success; | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | bool EmulatedController::RemoveNfcHandle() { | ||
| 1319 | nfc_handles--; | ||
| 1320 | if (nfc_handles <= 0) { | ||
| 1321 | return SetPollingMode(EmulatedDeviceIndex::RightIndex, | ||
| 1322 | Common::Input::PollingMode::Active) == | ||
| 1323 | Common::Input::DriverResult::Success; | ||
| 1324 | } | ||
| 1325 | return true; | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | bool EmulatedController::StartNfcPolling() { | ||
| 1329 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1330 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1331 | |||
| 1332 | return nfc_output_device->StartNfcPolling() == Common::Input::NfcState::Success || | ||
| 1333 | nfc_virtual_output_device->StartNfcPolling() == Common::Input::NfcState::Success; | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | bool EmulatedController::StopNfcPolling() { | ||
| 1337 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1338 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1339 | |||
| 1340 | return nfc_output_device->StopNfcPolling() == Common::Input::NfcState::Success || | ||
| 1341 | nfc_virtual_output_device->StopNfcPolling() == Common::Input::NfcState::Success; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) { | ||
| 1345 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1346 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1347 | |||
| 1348 | if (nfc_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success) { | ||
| 1349 | return true; | ||
| 1350 | } | ||
| 1351 | |||
| 1352 | return nfc_virtual_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success; | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request, | ||
| 1356 | Common::Input::MifareRequest& out_data) { | ||
| 1357 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1358 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1359 | |||
| 1360 | if (nfc_output_device->ReadMifareData(request, out_data) == Common::Input::NfcState::Success) { | ||
| 1361 | return true; | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | return nfc_virtual_output_device->ReadMifareData(request, out_data) == | ||
| 1365 | Common::Input::NfcState::Success; | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) { | ||
| 1369 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | ||
| 1370 | auto& nfc_virtual_output_device = output_devices[3]; | ||
| 1371 | |||
| 1372 | if (nfc_output_device->WriteMifareData(request) == Common::Input::NfcState::Success) { | ||
| 1373 | return true; | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | return nfc_virtual_output_device->WriteMifareData(request) == Common::Input::NfcState::Success; | ||
| 1377 | } | ||
| 1378 | |||
| 1311 | bool EmulatedController::WriteNfc(const std::vector<u8>& data) { | 1379 | bool EmulatedController::WriteNfc(const std::vector<u8>& data) { |
| 1312 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; | 1380 | auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; |
| 1313 | auto& nfc_virtual_output_device = output_devices[3]; | 1381 | auto& nfc_virtual_output_device = output_devices[3]; |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 09fe1a0ab..d511e5fac 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -97,10 +97,7 @@ struct RingSensorForce { | |||
| 97 | f32 force; | 97 | f32 force; |
| 98 | }; | 98 | }; |
| 99 | 99 | ||
| 100 | struct NfcState { | 100 | using NfcState = Common::Input::NfcStatus; |
| 101 | Common::Input::NfcState state{}; | ||
| 102 | std::vector<u8> data{}; | ||
| 103 | }; | ||
| 104 | 101 | ||
| 105 | struct ControllerMotion { | 102 | struct ControllerMotion { |
| 106 | Common::Vec3f accel{}; | 103 | Common::Vec3f accel{}; |
| @@ -393,9 +390,31 @@ public: | |||
| 393 | /// Returns true if the device has nfc support | 390 | /// Returns true if the device has nfc support |
| 394 | bool HasNfc() const; | 391 | bool HasNfc() const; |
| 395 | 392 | ||
| 393 | /// Sets the joycon in nfc mode and increments the handle count | ||
| 394 | bool AddNfcHandle(); | ||
| 395 | |||
| 396 | /// Decrements the handle count if zero sets the joycon in active mode | ||
| 397 | bool RemoveNfcHandle(); | ||
| 398 | |||
| 399 | /// Start searching for nfc tags | ||
| 400 | bool StartNfcPolling(); | ||
| 401 | |||
| 402 | /// Stop searching for nfc tags | ||
| 403 | bool StopNfcPolling(); | ||
| 404 | |||
| 405 | /// Returns true if the nfc tag was readable | ||
| 406 | bool ReadAmiiboData(std::vector<u8>& data); | ||
| 407 | |||
| 396 | /// Returns true if the nfc tag was written | 408 | /// Returns true if the nfc tag was written |
| 397 | bool WriteNfc(const std::vector<u8>& data); | 409 | bool WriteNfc(const std::vector<u8>& data); |
| 398 | 410 | ||
| 411 | /// Returns true if the nfc tag was readable | ||
| 412 | bool ReadMifareData(const Common::Input::MifareRequest& request, | ||
| 413 | Common::Input::MifareRequest& out_data); | ||
| 414 | |||
| 415 | /// Returns true if the nfc tag was written | ||
| 416 | bool WriteMifareData(const Common::Input::MifareRequest& request); | ||
| 417 | |||
| 399 | /// Returns the led pattern corresponding to this emulated controller | 418 | /// Returns the led pattern corresponding to this emulated controller |
| 400 | LedPattern GetLedPattern() const; | 419 | LedPattern GetLedPattern() const; |
| 401 | 420 | ||
| @@ -532,6 +551,7 @@ private: | |||
| 532 | bool system_buttons_enabled{true}; | 551 | bool system_buttons_enabled{true}; |
| 533 | f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; | 552 | f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; |
| 534 | u32 turbo_button_state{0}; | 553 | u32 turbo_button_state{0}; |
| 554 | std::size_t nfc_handles{0}; | ||
| 535 | 555 | ||
| 536 | // Temporary values to avoid doing changes while the controller is in configuring mode | 556 | // Temporary values to avoid doing changes while the controller is in configuring mode |
| 537 | NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; | 557 | NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; |
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 4ccb1c596..a05716fd8 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp | |||
| @@ -299,11 +299,7 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal | |||
| 299 | Common::Input::NfcStatus nfc{}; | 299 | Common::Input::NfcStatus nfc{}; |
| 300 | switch (callback.type) { | 300 | switch (callback.type) { |
| 301 | case Common::Input::InputType::Nfc: | 301 | case Common::Input::InputType::Nfc: |
| 302 | nfc = { | 302 | return callback.nfc_status; |
| 303 | .state = callback.nfc_status, | ||
| 304 | .data = callback.raw_data, | ||
| 305 | }; | ||
| 306 | break; | ||
| 307 | default: | 303 | default: |
| 308 | LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type); | 304 | LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type); |
| 309 | break; | 305 | break; |
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 8b754e9d4..19ed184e8 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp | |||
| @@ -141,7 +141,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) | |||
| 141 | applet_output.device_handle = applet_input_common.device_handle; | 141 | applet_output.device_handle = applet_input_common.device_handle; |
| 142 | applet_output.result = CabinetResult::Cancel; | 142 | applet_output.result = CabinetResult::Cancel; |
| 143 | const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); | 143 | const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); |
| 144 | const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info, false); | 144 | const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); |
| 145 | nfp_device->Finalize(); | 145 | nfp_device->Finalize(); |
| 146 | 146 | ||
| 147 | if (reg_result.IsSuccess()) { | 147 | if (reg_result.IsSuccess()) { |
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index f4b180b06..5bf289818 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp | |||
| @@ -93,7 +93,8 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { | |||
| 93 | const auto nfc_status = npad_device->GetNfc(); | 93 | const auto nfc_status = npad_device->GetNfc(); |
| 94 | switch (nfc_status.state) { | 94 | switch (nfc_status.state) { |
| 95 | case Common::Input::NfcState::NewAmiibo: | 95 | case Common::Input::NfcState::NewAmiibo: |
| 96 | LoadNfcTag(nfc_status.data); | 96 | LoadNfcTag(nfc_status.protocol, nfc_status.tag_type, nfc_status.uuid_length, |
| 97 | nfc_status.uuid); | ||
| 97 | break; | 98 | break; |
| 98 | case Common::Input::NfcState::AmiiboRemoved: | 99 | case Common::Input::NfcState::AmiiboRemoved: |
| 99 | if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { | 100 | if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { |
| @@ -108,28 +109,46 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { | |||
| 108 | } | 109 | } |
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | bool NfcDevice::LoadNfcTag(std::span<const u8> data) { | 112 | bool NfcDevice::LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid) { |
| 112 | if (device_state != DeviceState::SearchingForTag) { | 113 | if (device_state != DeviceState::SearchingForTag) { |
| 113 | LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state); | 114 | LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state); |
| 114 | return false; | 115 | return false; |
| 115 | } | 116 | } |
| 116 | 117 | ||
| 118 | if ((protocol & static_cast<u8>(allowed_protocols)) == 0) { | ||
| 119 | LOG_ERROR(Service_NFC, "Protocol not supported {}", protocol); | ||
| 120 | return false; | ||
| 121 | } | ||
| 122 | |||
| 123 | real_tag_info = { | ||
| 124 | .uuid = uuid, | ||
| 125 | .uuid_length = uuid_length, | ||
| 126 | .protocol = static_cast<NfcProtocol>(protocol), | ||
| 127 | .tag_type = static_cast<TagType>(tag_type), | ||
| 128 | }; | ||
| 129 | |||
| 130 | device_state = DeviceState::TagFound; | ||
| 131 | deactivate_event->GetReadableEvent().Clear(); | ||
| 132 | activate_event->Signal(); | ||
| 133 | return true; | ||
| 134 | } | ||
| 135 | |||
| 136 | bool NfcDevice::LoadAmiiboData() { | ||
| 137 | std::vector<u8> data{}; | ||
| 138 | |||
| 139 | if (!npad_device->ReadAmiiboData(data)) { | ||
| 140 | return false; | ||
| 141 | } | ||
| 142 | |||
| 117 | if (data.size() < sizeof(NFP::EncryptedNTAG215File)) { | 143 | if (data.size() < sizeof(NFP::EncryptedNTAG215File)) { |
| 118 | LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); | 144 | LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); |
| 119 | return false; | 145 | return false; |
| 120 | } | 146 | } |
| 121 | 147 | ||
| 122 | mifare_data.resize(data.size()); | ||
| 123 | memcpy(mifare_data.data(), data.data(), data.size()); | ||
| 124 | |||
| 125 | memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); | 148 | memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); |
| 126 | is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data); | 149 | is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data); |
| 127 | is_write_protected = false; | 150 | is_write_protected = false; |
| 128 | 151 | ||
| 129 | device_state = DeviceState::TagFound; | ||
| 130 | deactivate_event->GetReadableEvent().Clear(); | ||
| 131 | activate_event->Signal(); | ||
| 132 | |||
| 133 | // Fallback for plain amiibos | 152 | // Fallback for plain amiibos |
| 134 | if (is_plain_amiibo) { | 153 | if (is_plain_amiibo) { |
| 135 | LOG_INFO(Service_NFP, "Using plain amiibo"); | 154 | LOG_INFO(Service_NFP, "Using plain amiibo"); |
| @@ -147,6 +166,7 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) { | |||
| 147 | return true; | 166 | return true; |
| 148 | } | 167 | } |
| 149 | 168 | ||
| 169 | LOG_INFO(Service_NFP, "Using encrypted amiibo"); | ||
| 150 | tag_data = {}; | 170 | tag_data = {}; |
| 151 | memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); | 171 | memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); |
| 152 | return true; | 172 | return true; |
| @@ -162,7 +182,6 @@ void NfcDevice::CloseNfcTag() { | |||
| 162 | device_state = DeviceState::TagRemoved; | 182 | device_state = DeviceState::TagRemoved; |
| 163 | encrypted_tag_data = {}; | 183 | encrypted_tag_data = {}; |
| 164 | tag_data = {}; | 184 | tag_data = {}; |
| 165 | mifare_data = {}; | ||
| 166 | activate_event->GetReadableEvent().Clear(); | 185 | activate_event->GetReadableEvent().Clear(); |
| 167 | deactivate_event->Signal(); | 186 | deactivate_event->Signal(); |
| 168 | } | 187 | } |
| @@ -179,8 +198,12 @@ void NfcDevice::Initialize() { | |||
| 179 | device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable; | 198 | device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable; |
| 180 | encrypted_tag_data = {}; | 199 | encrypted_tag_data = {}; |
| 181 | tag_data = {}; | 200 | tag_data = {}; |
| 182 | mifare_data = {}; | 201 | |
| 183 | is_initalized = true; | 202 | if (device_state != DeviceState::Initialized) { |
| 203 | return; | ||
| 204 | } | ||
| 205 | |||
| 206 | is_initalized = npad_device->AddNfcHandle(); | ||
| 184 | } | 207 | } |
| 185 | 208 | ||
| 186 | void NfcDevice::Finalize() { | 209 | void NfcDevice::Finalize() { |
| @@ -190,6 +213,11 @@ void NfcDevice::Finalize() { | |||
| 190 | if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { | 213 | if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { |
| 191 | StopDetection(); | 214 | StopDetection(); |
| 192 | } | 215 | } |
| 216 | |||
| 217 | if (device_state != DeviceState::Unavailable) { | ||
| 218 | npad_device->RemoveNfcHandle(); | ||
| 219 | } | ||
| 220 | |||
| 193 | device_state = DeviceState::Unavailable; | 221 | device_state = DeviceState::Unavailable; |
| 194 | is_initalized = false; | 222 | is_initalized = false; |
| 195 | } | 223 | } |
| @@ -200,10 +228,8 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { | |||
| 200 | return ResultWrongDeviceState; | 228 | return ResultWrongDeviceState; |
| 201 | } | 229 | } |
| 202 | 230 | ||
| 203 | if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, | 231 | if (!npad_device->StartNfcPolling()) { |
| 204 | Common::Input::PollingMode::NFC) != | 232 | LOG_ERROR(Service_NFC, "Nfc polling not supported"); |
| 205 | Common::Input::DriverResult::Success) { | ||
| 206 | LOG_ERROR(Service_NFC, "Nfc not supported"); | ||
| 207 | return ResultNfcDisabled; | 233 | return ResultNfcDisabled; |
| 208 | } | 234 | } |
| 209 | 235 | ||
| @@ -213,9 +239,6 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { | |||
| 213 | } | 239 | } |
| 214 | 240 | ||
| 215 | Result NfcDevice::StopDetection() { | 241 | Result NfcDevice::StopDetection() { |
| 216 | npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, | ||
| 217 | Common::Input::PollingMode::Active); | ||
| 218 | |||
| 219 | if (device_state == DeviceState::Initialized) { | 242 | if (device_state == DeviceState::Initialized) { |
| 220 | return ResultSuccess; | 243 | return ResultSuccess; |
| 221 | } | 244 | } |
| @@ -225,6 +248,7 @@ Result NfcDevice::StopDetection() { | |||
| 225 | } | 248 | } |
| 226 | 249 | ||
| 227 | if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { | 250 | if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { |
| 251 | npad_device->StopNfcPolling(); | ||
| 228 | device_state = DeviceState::Initialized; | 252 | device_state = DeviceState::Initialized; |
| 229 | return ResultSuccess; | 253 | return ResultSuccess; |
| 230 | } | 254 | } |
| @@ -233,7 +257,7 @@ Result NfcDevice::StopDetection() { | |||
| 233 | return ResultWrongDeviceState; | 257 | return ResultWrongDeviceState; |
| 234 | } | 258 | } |
| 235 | 259 | ||
| 236 | Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const { | 260 | Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { |
| 237 | if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { | 261 | if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { |
| 238 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | 262 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |
| 239 | if (device_state == DeviceState::TagRemoved) { | 263 | if (device_state == DeviceState::TagRemoved) { |
| @@ -242,41 +266,15 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const { | |||
| 242 | return ResultWrongDeviceState; | 266 | return ResultWrongDeviceState; |
| 243 | } | 267 | } |
| 244 | 268 | ||
| 245 | UniqueSerialNumber uuid{}; | 269 | tag_info = real_tag_info; |
| 246 | u8 uuid_length{}; | ||
| 247 | NfcProtocol protocol{NfcProtocol::TypeA}; | ||
| 248 | TagType tag_type{TagType::Type2}; | ||
| 249 | |||
| 250 | if (is_mifare) { | ||
| 251 | tag_type = TagType::Mifare; | ||
| 252 | uuid_length = sizeof(NFP::NtagTagUuid); | ||
| 253 | memcpy(uuid.data(), mifare_data.data(), uuid_length); | ||
| 254 | } else { | ||
| 255 | tag_type = TagType::Type2; | ||
| 256 | uuid_length = sizeof(NFP::NtagTagUuid); | ||
| 257 | NFP::NtagTagUuid nUuid{ | ||
| 258 | .part1 = encrypted_tag_data.uuid.part1, | ||
| 259 | .part2 = encrypted_tag_data.uuid.part2, | ||
| 260 | .nintendo_id = encrypted_tag_data.uuid.nintendo_id, | ||
| 261 | }; | ||
| 262 | memcpy(uuid.data(), &nUuid, uuid_length); | ||
| 263 | 270 | ||
| 264 | // Generate random UUID to bypass amiibo load limits | 271 | // Generate random UUID to bypass amiibo load limits |
| 265 | if (Settings::values.random_amiibo_id) { | 272 | if (real_tag_info.tag_type == TagType::Type2 && Settings::values.random_amiibo_id) { |
| 266 | Common::TinyMT rng{}; | 273 | Common::TinyMT rng{}; |
| 267 | rng.Initialize(static_cast<u32>(GetCurrentPosixTime())); | 274 | rng.Initialize(static_cast<u32>(GetCurrentPosixTime())); |
| 268 | rng.GenerateRandomBytes(uuid.data(), uuid_length); | 275 | rng.GenerateRandomBytes(tag_info.uuid.data(), tag_info.uuid_length); |
| 269 | } | ||
| 270 | } | 276 | } |
| 271 | 277 | ||
| 272 | // Protocol and tag type may change here | ||
| 273 | tag_info = { | ||
| 274 | .uuid = uuid, | ||
| 275 | .uuid_length = uuid_length, | ||
| 276 | .protocol = protocol, | ||
| 277 | .tag_type = tag_type, | ||
| 278 | }; | ||
| 279 | |||
| 280 | return ResultSuccess; | 278 | return ResultSuccess; |
| 281 | } | 279 | } |
| 282 | 280 | ||
| @@ -293,7 +291,7 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter | |||
| 293 | Result result = ResultSuccess; | 291 | Result result = ResultSuccess; |
| 294 | 292 | ||
| 295 | TagInfo tag_info{}; | 293 | TagInfo tag_info{}; |
| 296 | result = GetTagInfo(tag_info, true); | 294 | result = GetTagInfo(tag_info); |
| 297 | 295 | ||
| 298 | if (result.IsError()) { | 296 | if (result.IsError()) { |
| 299 | return result; | 297 | return result; |
| @@ -307,6 +305,8 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter | |||
| 307 | return ResultInvalidArgument; | 305 | return ResultInvalidArgument; |
| 308 | } | 306 | } |
| 309 | 307 | ||
| 308 | Common::Input::MifareRequest request{}; | ||
| 309 | Common::Input::MifareRequest out_data{}; | ||
| 310 | const auto unknown = parameters[0].sector_key.unknown; | 310 | const auto unknown = parameters[0].sector_key.unknown; |
| 311 | for (std::size_t i = 0; i < parameters.size(); i++) { | 311 | for (std::size_t i = 0; i < parameters.size(); i++) { |
| 312 | if (unknown != parameters[i].sector_key.unknown) { | 312 | if (unknown != parameters[i].sector_key.unknown) { |
| @@ -315,25 +315,29 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter | |||
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | for (std::size_t i = 0; i < parameters.size(); i++) { | 317 | for (std::size_t i = 0; i < parameters.size(); i++) { |
| 318 | result = ReadMifare(parameters[i], read_block_data[i]); | 318 | if (parameters[i].sector_key.command == MifareCmd::None) { |
| 319 | if (result.IsError()) { | 319 | continue; |
| 320 | break; | ||
| 321 | } | 320 | } |
| 321 | request.data[i].command = static_cast<u8>(parameters[i].sector_key.command); | ||
| 322 | request.data[i].sector = parameters[i].sector_number; | ||
| 323 | memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(), | ||
| 324 | sizeof(KeyData)); | ||
| 322 | } | 325 | } |
| 323 | 326 | ||
| 324 | return result; | 327 | if (!npad_device->ReadMifareData(request, out_data)) { |
| 325 | } | ||
| 326 | |||
| 327 | Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter, | ||
| 328 | MifareReadBlockData& read_block_data) const { | ||
| 329 | const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock); | ||
| 330 | read_block_data.sector_number = parameter.sector_number; | ||
| 331 | if (mifare_data.size() < sector_index + sizeof(DataBlock)) { | ||
| 332 | return ResultMifareError288; | 328 | return ResultMifareError288; |
| 333 | } | 329 | } |
| 334 | 330 | ||
| 335 | // TODO: Use parameter.sector_key to read encrypted data | 331 | for (std::size_t i = 0; i < read_block_data.size(); i++) { |
| 336 | memcpy(read_block_data.data.data(), mifare_data.data() + sector_index, sizeof(DataBlock)); | 332 | if (static_cast<MifareCmd>(out_data.data[i].command) == MifareCmd::None) { |
| 333 | continue; | ||
| 334 | } | ||
| 335 | |||
| 336 | read_block_data[i] = { | ||
| 337 | .data = out_data.data[i].data, | ||
| 338 | .sector_number = out_data.data[i].sector, | ||
| 339 | }; | ||
| 340 | } | ||
| 337 | 341 | ||
| 338 | return ResultSuccess; | 342 | return ResultSuccess; |
| 339 | } | 343 | } |
| @@ -342,7 +346,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet | |||
| 342 | Result result = ResultSuccess; | 346 | Result result = ResultSuccess; |
| 343 | 347 | ||
| 344 | TagInfo tag_info{}; | 348 | TagInfo tag_info{}; |
| 345 | result = GetTagInfo(tag_info, true); | 349 | result = GetTagInfo(tag_info); |
| 346 | 350 | ||
| 347 | if (result.IsError()) { | 351 | if (result.IsError()) { |
| 348 | return result; | 352 | return result; |
| @@ -363,42 +367,25 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet | |||
| 363 | } | 367 | } |
| 364 | } | 368 | } |
| 365 | 369 | ||
| 370 | Common::Input::MifareRequest request{}; | ||
| 366 | for (std::size_t i = 0; i < parameters.size(); i++) { | 371 | for (std::size_t i = 0; i < parameters.size(); i++) { |
| 367 | result = WriteMifare(parameters[i]); | 372 | if (parameters[i].sector_key.command == MifareCmd::None) { |
| 368 | if (result.IsError()) { | 373 | continue; |
| 369 | break; | ||
| 370 | } | 374 | } |
| 375 | request.data[i].command = static_cast<u8>(parameters[i].sector_key.command); | ||
| 376 | request.data[i].sector = parameters[i].sector_number; | ||
| 377 | memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(), | ||
| 378 | sizeof(KeyData)); | ||
| 379 | memcpy(request.data[i].data.data(), parameters[i].data.data(), sizeof(KeyData)); | ||
| 371 | } | 380 | } |
| 372 | 381 | ||
| 373 | if (!npad_device->WriteNfc(mifare_data)) { | 382 | if (!npad_device->WriteMifareData(request)) { |
| 374 | LOG_ERROR(Service_NFP, "Error writing to file"); | ||
| 375 | return ResultMifareError288; | 383 | return ResultMifareError288; |
| 376 | } | 384 | } |
| 377 | 385 | ||
| 378 | return result; | 386 | return result; |
| 379 | } | 387 | } |
| 380 | 388 | ||
| 381 | Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) { | ||
| 382 | const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock); | ||
| 383 | |||
| 384 | if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { | ||
| 385 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 386 | if (device_state == DeviceState::TagRemoved) { | ||
| 387 | return ResultTagRemoved; | ||
| 388 | } | ||
| 389 | return ResultWrongDeviceState; | ||
| 390 | } | ||
| 391 | |||
| 392 | if (mifare_data.size() < sector_index + sizeof(DataBlock)) { | ||
| 393 | return ResultMifareError288; | ||
| 394 | } | ||
| 395 | |||
| 396 | // TODO: Use parameter.sector_key to encrypt the data | ||
| 397 | memcpy(mifare_data.data() + sector_index, parameter.data.data(), sizeof(DataBlock)); | ||
| 398 | |||
| 399 | return ResultSuccess; | ||
| 400 | } | ||
| 401 | |||
| 402 | Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, | 389 | Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, |
| 403 | std::span<const u8> command_data, | 390 | std::span<const u8> command_data, |
| 404 | std::span<u8> out_data) { | 391 | std::span<u8> out_data) { |
| @@ -412,6 +399,11 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target | |||
| 412 | return ResultWrongDeviceState; | 399 | return ResultWrongDeviceState; |
| 413 | } | 400 | } |
| 414 | 401 | ||
| 402 | if (!LoadAmiiboData()) { | ||
| 403 | LOG_ERROR(Service_NFP, "Not an amiibo"); | ||
| 404 | return ResultInvalidTagType; | ||
| 405 | } | ||
| 406 | |||
| 415 | if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) { | 407 | if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) { |
| 416 | LOG_ERROR(Service_NFP, "Not an amiibo"); | 408 | LOG_ERROR(Service_NFP, "Not an amiibo"); |
| 417 | return ResultInvalidTagType; | 409 | return ResultInvalidTagType; |
| @@ -562,7 +554,7 @@ Result NfcDevice::Restore() { | |||
| 562 | 554 | ||
| 563 | NFC::TagInfo tag_info{}; | 555 | NFC::TagInfo tag_info{}; |
| 564 | std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{}; | 556 | std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{}; |
| 565 | Result result = GetTagInfo(tag_info, false); | 557 | Result result = GetTagInfo(tag_info); |
| 566 | 558 | ||
| 567 | if (result.IsError()) { | 559 | if (result.IsError()) { |
| 568 | return result; | 560 | return result; |
| @@ -635,7 +627,7 @@ Result NfcDevice::GetCommonInfo(NFP::CommonInfo& common_info) const { | |||
| 635 | // TODO: Validate this data | 627 | // TODO: Validate this data |
| 636 | common_info = { | 628 | common_info = { |
| 637 | .last_write_date = settings.write_date.GetWriteDate(), | 629 | .last_write_date = settings.write_date.GetWriteDate(), |
| 638 | .write_counter = tag_data.write_counter, | 630 | .write_counter = tag_data.application_write_counter, |
| 639 | .version = tag_data.amiibo_version, | 631 | .version = tag_data.amiibo_version, |
| 640 | .application_area_size = sizeof(NFP::ApplicationArea), | 632 | .application_area_size = sizeof(NFP::ApplicationArea), |
| 641 | }; | 633 | }; |
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h index 7560210d6..0ed1ff34c 100644 --- a/src/core/hle/service/nfc/common/device.h +++ b/src/core/hle/service/nfc/common/device.h | |||
| @@ -42,15 +42,12 @@ public: | |||
| 42 | Result StartDetection(NfcProtocol allowed_protocol); | 42 | Result StartDetection(NfcProtocol allowed_protocol); |
| 43 | Result StopDetection(); | 43 | Result StopDetection(); |
| 44 | 44 | ||
| 45 | Result GetTagInfo(TagInfo& tag_info, bool is_mifare) const; | 45 | Result GetTagInfo(TagInfo& tag_info) const; |
| 46 | 46 | ||
| 47 | Result ReadMifare(std::span<const MifareReadBlockParameter> parameters, | 47 | Result ReadMifare(std::span<const MifareReadBlockParameter> parameters, |
| 48 | std::span<MifareReadBlockData> read_block_data) const; | 48 | std::span<MifareReadBlockData> read_block_data) const; |
| 49 | Result ReadMifare(const MifareReadBlockParameter& parameter, | ||
| 50 | MifareReadBlockData& read_block_data) const; | ||
| 51 | 49 | ||
| 52 | Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters); | 50 | Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters); |
| 53 | Result WriteMifare(const MifareWriteBlockParameter& parameter); | ||
| 54 | 51 | ||
| 55 | Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, | 52 | Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, |
| 56 | std::span<const u8> command_data, std::span<u8> out_data); | 53 | std::span<const u8> command_data, std::span<u8> out_data); |
| @@ -105,7 +102,8 @@ public: | |||
| 105 | 102 | ||
| 106 | private: | 103 | private: |
| 107 | void NpadUpdate(Core::HID::ControllerTriggerType type); | 104 | void NpadUpdate(Core::HID::ControllerTriggerType type); |
| 108 | bool LoadNfcTag(std::span<const u8> data); | 105 | bool LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid); |
| 106 | bool LoadAmiiboData(); | ||
| 109 | void CloseNfcTag(); | 107 | void CloseNfcTag(); |
| 110 | 108 | ||
| 111 | NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; | 109 | NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; |
| @@ -140,8 +138,8 @@ private: | |||
| 140 | bool is_write_protected{}; | 138 | bool is_write_protected{}; |
| 141 | NFP::MountTarget mount_target{NFP::MountTarget::None}; | 139 | NFP::MountTarget mount_target{NFP::MountTarget::None}; |
| 142 | 140 | ||
| 141 | TagInfo real_tag_info{}; | ||
| 143 | NFP::NTAG215File tag_data{}; | 142 | NFP::NTAG215File tag_data{}; |
| 144 | std::vector<u8> mifare_data{}; | ||
| 145 | NFP::EncryptedNTAG215File encrypted_tag_data{}; | 143 | NFP::EncryptedNTAG215File encrypted_tag_data{}; |
| 146 | }; | 144 | }; |
| 147 | 145 | ||
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp index b0456508e..562f3a28e 100644 --- a/src/core/hle/service/nfc/common/device_manager.cpp +++ b/src/core/hle/service/nfc/common/device_manager.cpp | |||
| @@ -29,6 +29,9 @@ DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContex | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | DeviceManager ::~DeviceManager() { | 31 | DeviceManager ::~DeviceManager() { |
| 32 | if (is_initialized) { | ||
| 33 | Finalize(); | ||
| 34 | } | ||
| 32 | service_context.CloseEvent(availability_change_event); | 35 | service_context.CloseEvent(availability_change_event); |
| 33 | } | 36 | } |
| 34 | 37 | ||
| @@ -125,14 +128,14 @@ Result DeviceManager::StopDetection(u64 device_handle) { | |||
| 125 | return result; | 128 | return result; |
| 126 | } | 129 | } |
| 127 | 130 | ||
| 128 | Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const { | 131 | Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const { |
| 129 | std::scoped_lock lock{mutex}; | 132 | std::scoped_lock lock{mutex}; |
| 130 | 133 | ||
| 131 | std::shared_ptr<NfcDevice> device = nullptr; | 134 | std::shared_ptr<NfcDevice> device = nullptr; |
| 132 | auto result = GetDeviceHandle(device_handle, device); | 135 | auto result = GetDeviceHandle(device_handle, device); |
| 133 | 136 | ||
| 134 | if (result.IsSuccess()) { | 137 | if (result.IsSuccess()) { |
| 135 | result = device->GetTagInfo(tag_info, is_mifare); | 138 | result = device->GetTagInfo(tag_info); |
| 136 | result = VerifyDeviceResult(device, result); | 139 | result = VerifyDeviceResult(device, result); |
| 137 | } | 140 | } |
| 138 | 141 | ||
| @@ -546,7 +549,7 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) cons | |||
| 546 | NFC::TagInfo tag_info{}; | 549 | NFC::TagInfo tag_info{}; |
| 547 | 550 | ||
| 548 | if (result.IsSuccess()) { | 551 | if (result.IsSuccess()) { |
| 549 | result = device->GetTagInfo(tag_info, false); | 552 | result = device->GetTagInfo(tag_info); |
| 550 | } | 553 | } |
| 551 | 554 | ||
| 552 | if (result.IsSuccess()) { | 555 | if (result.IsSuccess()) { |
| @@ -565,7 +568,7 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> dat | |||
| 565 | NFC::TagInfo tag_info{}; | 568 | NFC::TagInfo tag_info{}; |
| 566 | 569 | ||
| 567 | if (result.IsSuccess()) { | 570 | if (result.IsSuccess()) { |
| 568 | result = device->GetTagInfo(tag_info, false); | 571 | result = device->GetTagInfo(tag_info); |
| 569 | } | 572 | } |
| 570 | 573 | ||
| 571 | if (result.IsSuccess()) { | 574 | if (result.IsSuccess()) { |
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h index 2971e280f..c61ba0cf3 100644 --- a/src/core/hle/service/nfc/common/device_manager.h +++ b/src/core/hle/service/nfc/common/device_manager.h | |||
| @@ -33,7 +33,7 @@ public: | |||
| 33 | Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const; | 33 | Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const; |
| 34 | Result StartDetection(u64 device_handle, NfcProtocol tag_protocol); | 34 | Result StartDetection(u64 device_handle, NfcProtocol tag_protocol); |
| 35 | Result StopDetection(u64 device_handle); | 35 | Result StopDetection(u64 device_handle); |
| 36 | Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info, bool is_mifare) const; | 36 | Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info) const; |
| 37 | Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const; | 37 | Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const; |
| 38 | Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const; | 38 | Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const; |
| 39 | Result ReadMifare(u64 device_handle, | 39 | Result ReadMifare(u64 device_handle, |
diff --git a/src/core/hle/service/nfc/mifare_types.h b/src/core/hle/service/nfc/mifare_types.h index 75b59f021..467937399 100644 --- a/src/core/hle/service/nfc/mifare_types.h +++ b/src/core/hle/service/nfc/mifare_types.h | |||
| @@ -11,9 +11,10 @@ | |||
| 11 | namespace Service::NFC { | 11 | namespace Service::NFC { |
| 12 | 12 | ||
| 13 | enum class MifareCmd : u8 { | 13 | enum class MifareCmd : u8 { |
| 14 | None = 0x00, | ||
| 15 | Read = 0x30, | ||
| 14 | AuthA = 0x60, | 16 | AuthA = 0x60, |
| 15 | AuthB = 0x61, | 17 | AuthB = 0x61, |
| 16 | Read = 0x30, | ||
| 17 | Write = 0xA0, | 18 | Write = 0xA0, |
| 18 | Transfer = 0xB0, | 19 | Transfer = 0xB0, |
| 19 | Decrement = 0xC0, | 20 | Decrement = 0xC0, |
| @@ -35,17 +36,17 @@ static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size"); | |||
| 35 | 36 | ||
| 36 | // This is nn::nfc::MifareReadBlockParameter | 37 | // This is nn::nfc::MifareReadBlockParameter |
| 37 | struct MifareReadBlockParameter { | 38 | struct MifareReadBlockParameter { |
| 38 | u8 sector_number; | 39 | u8 sector_number{}; |
| 39 | INSERT_PADDING_BYTES(0x7); | 40 | INSERT_PADDING_BYTES(0x7); |
| 40 | SectorKey sector_key; | 41 | SectorKey sector_key{}; |
| 41 | }; | 42 | }; |
| 42 | static_assert(sizeof(MifareReadBlockParameter) == 0x18, | 43 | static_assert(sizeof(MifareReadBlockParameter) == 0x18, |
| 43 | "MifareReadBlockParameter is an invalid size"); | 44 | "MifareReadBlockParameter is an invalid size"); |
| 44 | 45 | ||
| 45 | // This is nn::nfc::MifareReadBlockData | 46 | // This is nn::nfc::MifareReadBlockData |
| 46 | struct MifareReadBlockData { | 47 | struct MifareReadBlockData { |
| 47 | DataBlock data; | 48 | DataBlock data{}; |
| 48 | u8 sector_number; | 49 | u8 sector_number{}; |
| 49 | INSERT_PADDING_BYTES(0x7); | 50 | INSERT_PADDING_BYTES(0x7); |
| 50 | }; | 51 | }; |
| 51 | static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); | 52 | static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); |
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp index 130fb7f78..e7ca7582e 100644 --- a/src/core/hle/service/nfc/nfc_interface.cpp +++ b/src/core/hle/service/nfc/nfc_interface.cpp | |||
| @@ -174,8 +174,7 @@ void NfcInterface::GetTagInfo(HLERequestContext& ctx) { | |||
| 174 | LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); | 174 | LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); |
| 175 | 175 | ||
| 176 | TagInfo tag_info{}; | 176 | TagInfo tag_info{}; |
| 177 | auto result = | 177 | auto result = GetManager()->GetTagInfo(device_handle, tag_info); |
| 178 | GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare); | ||
| 179 | result = TranslateResultToServiceError(result); | 178 | result = TranslateResultToServiceError(result); |
| 180 | 179 | ||
| 181 | if (result.IsSuccess()) { | 180 | if (result.IsSuccess()) { |
| @@ -216,8 +215,8 @@ void NfcInterface::ReadMifare(HLERequestContext& ctx) { | |||
| 216 | memcpy(read_commands.data(), buffer.data(), | 215 | memcpy(read_commands.data(), buffer.data(), |
| 217 | number_of_commands * sizeof(MifareReadBlockParameter)); | 216 | number_of_commands * sizeof(MifareReadBlockParameter)); |
| 218 | 217 | ||
| 219 | LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}", | 218 | LOG_INFO(Service_NFC, "called, device_handle={}, read_commands_size={}", device_handle, |
| 220 | device_handle, number_of_commands); | 219 | number_of_commands); |
| 221 | 220 | ||
| 222 | std::vector<MifareReadBlockData> out_data(number_of_commands); | 221 | std::vector<MifareReadBlockData> out_data(number_of_commands); |
| 223 | auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data); | 222 | auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data); |
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index b2b5677c8..52494e0d9 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp | |||
| @@ -195,8 +195,8 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) { | |||
| 195 | OnMotionUpdate(port, type, id, value); | 195 | OnMotionUpdate(port, type, id, value); |
| 196 | }}, | 196 | }}, |
| 197 | .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }}, | 197 | .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }}, |
| 198 | .on_amiibo_data = {[this, port, type](const std::vector<u8>& amiibo_data) { | 198 | .on_amiibo_data = {[this, port, type](const Joycon::TagInfo& tag_info) { |
| 199 | OnAmiiboUpdate(port, type, amiibo_data); | 199 | OnAmiiboUpdate(port, type, tag_info); |
| 200 | }}, | 200 | }}, |
| 201 | .on_camera_data = {[this, port](const std::vector<u8>& camera_data, | 201 | .on_camera_data = {[this, port](const std::vector<u8>& camera_data, |
| 202 | Joycon::IrsResolution format) { | 202 | Joycon::IrsResolution format) { |
| @@ -291,13 +291,105 @@ Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) c | |||
| 291 | return Common::Input::NfcState::Success; | 291 | return Common::Input::NfcState::Success; |
| 292 | }; | 292 | }; |
| 293 | 293 | ||
| 294 | Common::Input::NfcState Joycons::StartNfcPolling(const PadIdentifier& identifier) { | ||
| 295 | auto handle = GetHandle(identifier); | ||
| 296 | if (handle == nullptr) { | ||
| 297 | return Common::Input::NfcState::Unknown; | ||
| 298 | } | ||
| 299 | return TranslateDriverResult(handle->StartNfcPolling()); | ||
| 300 | }; | ||
| 301 | |||
| 302 | Common::Input::NfcState Joycons::StopNfcPolling(const PadIdentifier& identifier) { | ||
| 303 | auto handle = GetHandle(identifier); | ||
| 304 | if (handle == nullptr) { | ||
| 305 | return Common::Input::NfcState::Unknown; | ||
| 306 | } | ||
| 307 | return TranslateDriverResult(handle->StopNfcPolling()); | ||
| 308 | }; | ||
| 309 | |||
| 310 | Common::Input::NfcState Joycons::ReadAmiiboData(const PadIdentifier& identifier, | ||
| 311 | std::vector<u8>& out_data) { | ||
| 312 | auto handle = GetHandle(identifier); | ||
| 313 | if (handle == nullptr) { | ||
| 314 | return Common::Input::NfcState::Unknown; | ||
| 315 | } | ||
| 316 | return TranslateDriverResult(handle->ReadAmiiboData(out_data)); | ||
| 317 | } | ||
| 318 | |||
| 294 | Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier, | 319 | Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier, |
| 295 | const std::vector<u8>& data) { | 320 | const std::vector<u8>& data) { |
| 296 | auto handle = GetHandle(identifier); | 321 | auto handle = GetHandle(identifier); |
| 297 | if (handle->WriteNfcData(data) != Joycon::DriverResult::Success) { | 322 | if (handle == nullptr) { |
| 298 | return Common::Input::NfcState::WriteFailed; | 323 | return Common::Input::NfcState::Unknown; |
| 299 | } | 324 | } |
| 300 | return Common::Input::NfcState::Success; | 325 | return TranslateDriverResult(handle->WriteNfcData(data)); |
| 326 | }; | ||
| 327 | |||
| 328 | Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier, | ||
| 329 | const Common::Input::MifareRequest& request, | ||
| 330 | Common::Input::MifareRequest& data) { | ||
| 331 | auto handle = GetHandle(identifier); | ||
| 332 | if (handle == nullptr) { | ||
| 333 | return Common::Input::NfcState::Unknown; | ||
| 334 | } | ||
| 335 | |||
| 336 | const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); | ||
| 337 | std::vector<Joycon::MifareReadChunk> read_request{}; | ||
| 338 | for (const auto& request_data : request.data) { | ||
| 339 | if (request_data.command == 0) { | ||
| 340 | continue; | ||
| 341 | } | ||
| 342 | Joycon::MifareReadChunk chunk = { | ||
| 343 | .command = command, | ||
| 344 | .sector_key = {}, | ||
| 345 | .sector = request_data.sector, | ||
| 346 | }; | ||
| 347 | memcpy(chunk.sector_key.data(), request_data.key.data(), | ||
| 348 | sizeof(Joycon::MifareReadChunk::sector_key)); | ||
| 349 | read_request.emplace_back(chunk); | ||
| 350 | } | ||
| 351 | |||
| 352 | std::vector<Joycon::MifareReadData> read_data(read_request.size()); | ||
| 353 | const auto result = handle->ReadMifareData(read_request, read_data); | ||
| 354 | if (result == Joycon::DriverResult::Success) { | ||
| 355 | for (std::size_t i = 0; i < read_request.size(); i++) { | ||
| 356 | data.data[i] = { | ||
| 357 | .command = static_cast<u8>(command), | ||
| 358 | .sector = read_data[i].sector, | ||
| 359 | .key = {}, | ||
| 360 | .data = read_data[i].data, | ||
| 361 | }; | ||
| 362 | } | ||
| 363 | } | ||
| 364 | return TranslateDriverResult(result); | ||
| 365 | }; | ||
| 366 | |||
| 367 | Common::Input::NfcState Joycons::WriteMifareData(const PadIdentifier& identifier, | ||
| 368 | const Common::Input::MifareRequest& request) { | ||
| 369 | auto handle = GetHandle(identifier); | ||
| 370 | if (handle == nullptr) { | ||
| 371 | return Common::Input::NfcState::Unknown; | ||
| 372 | } | ||
| 373 | |||
| 374 | const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); | ||
| 375 | std::vector<Joycon::MifareWriteChunk> write_request{}; | ||
| 376 | for (const auto& request_data : request.data) { | ||
| 377 | if (request_data.command == 0) { | ||
| 378 | continue; | ||
| 379 | } | ||
| 380 | Joycon::MifareWriteChunk chunk = { | ||
| 381 | .command = command, | ||
| 382 | .sector_key = {}, | ||
| 383 | .sector = request_data.sector, | ||
| 384 | .data = {}, | ||
| 385 | }; | ||
| 386 | memcpy(chunk.sector_key.data(), request_data.key.data(), | ||
| 387 | sizeof(Joycon::MifareReadChunk::sector_key)); | ||
| 388 | memcpy(chunk.data.data(), request_data.data.data(), sizeof(Joycon::MifareWriteChunk::data)); | ||
| 389 | write_request.emplace_back(chunk); | ||
| 390 | } | ||
| 391 | |||
| 392 | return TranslateDriverResult(handle->WriteMifareData(write_request)); | ||
| 301 | }; | 393 | }; |
| 302 | 394 | ||
| 303 | Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier, | 395 | Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier, |
| @@ -403,11 +495,20 @@ void Joycons::OnRingConUpdate(f32 ring_data) { | |||
| 403 | } | 495 | } |
| 404 | 496 | ||
| 405 | void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, | 497 | void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, |
| 406 | const std::vector<u8>& amiibo_data) { | 498 | const Joycon::TagInfo& tag_info) { |
| 407 | const auto identifier = GetIdentifier(port, type); | 499 | const auto identifier = GetIdentifier(port, type); |
| 408 | const auto nfc_state = amiibo_data.empty() ? Common::Input::NfcState::AmiiboRemoved | 500 | const auto nfc_state = tag_info.uuid_length == 0 ? Common::Input::NfcState::AmiiboRemoved |
| 409 | : Common::Input::NfcState::NewAmiibo; | 501 | : Common::Input::NfcState::NewAmiibo; |
| 410 | SetNfc(identifier, {nfc_state, amiibo_data}); | 502 | |
| 503 | const Common::Input::NfcStatus nfc_status{ | ||
| 504 | .state = nfc_state, | ||
| 505 | .uuid_length = tag_info.uuid_length, | ||
| 506 | .protocol = tag_info.protocol, | ||
| 507 | .tag_type = tag_info.tag_type, | ||
| 508 | .uuid = tag_info.uuid, | ||
| 509 | }; | ||
| 510 | |||
| 511 | SetNfc(identifier, nfc_status); | ||
| 411 | } | 512 | } |
| 412 | 513 | ||
| 413 | void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, | 514 | void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, |
| @@ -726,4 +827,18 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const { | |||
| 726 | return "Unknown Switch Controller"; | 827 | return "Unknown Switch Controller"; |
| 727 | } | 828 | } |
| 728 | } | 829 | } |
| 830 | |||
| 831 | Common::Input::NfcState Joycons::TranslateDriverResult(Joycon::DriverResult result) const { | ||
| 832 | switch (result) { | ||
| 833 | case Joycon::DriverResult::Success: | ||
| 834 | return Common::Input::NfcState::Success; | ||
| 835 | case Joycon::DriverResult::Disabled: | ||
| 836 | return Common::Input::NfcState::WrongDeviceState; | ||
| 837 | case Joycon::DriverResult::NotSupported: | ||
| 838 | return Common::Input::NfcState::NotSupported; | ||
| 839 | default: | ||
| 840 | return Common::Input::NfcState::Unknown; | ||
| 841 | } | ||
| 842 | } | ||
| 843 | |||
| 729 | } // namespace InputCommon | 844 | } // namespace InputCommon |
diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index e3f0ad78f..4c323d7d6 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h | |||
| @@ -15,6 +15,7 @@ using SerialNumber = std::array<u8, 15>; | |||
| 15 | struct Battery; | 15 | struct Battery; |
| 16 | struct Color; | 16 | struct Color; |
| 17 | struct MotionData; | 17 | struct MotionData; |
| 18 | struct TagInfo; | ||
| 18 | enum class ControllerType : u8; | 19 | enum class ControllerType : u8; |
| 19 | enum class DriverResult; | 20 | enum class DriverResult; |
| 20 | enum class IrsResolution; | 21 | enum class IrsResolution; |
| @@ -39,9 +40,18 @@ public: | |||
| 39 | Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier, | 40 | Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier, |
| 40 | Common::Input::CameraFormat camera_format) override; | 41 | Common::Input::CameraFormat camera_format) override; |
| 41 | 42 | ||
| 42 | Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; | 43 | Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier) const override; |
| 43 | Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, | 44 | Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier) override; |
| 45 | Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier) override; | ||
| 46 | Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier, | ||
| 47 | std::vector<u8>& out_data) override; | ||
| 48 | Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier, | ||
| 44 | const std::vector<u8>& data) override; | 49 | const std::vector<u8>& data) override; |
| 50 | Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier, | ||
| 51 | const Common::Input::MifareRequest& request, | ||
| 52 | Common::Input::MifareRequest& out_data) override; | ||
| 53 | Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier, | ||
| 54 | const Common::Input::MifareRequest& request) override; | ||
| 45 | 55 | ||
| 46 | Common::Input::DriverResult SetPollingMode( | 56 | Common::Input::DriverResult SetPollingMode( |
| 47 | const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override; | 57 | const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override; |
| @@ -82,7 +92,7 @@ private: | |||
| 82 | const Joycon::MotionData& value); | 92 | const Joycon::MotionData& value); |
| 83 | void OnRingConUpdate(f32 ring_data); | 93 | void OnRingConUpdate(f32 ring_data); |
| 84 | void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, | 94 | void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, |
| 85 | const std::vector<u8>& amiibo_data); | 95 | const Joycon::TagInfo& amiibo_data); |
| 86 | void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, | 96 | void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, |
| 87 | Joycon::IrsResolution format); | 97 | Joycon::IrsResolution format); |
| 88 | 98 | ||
| @@ -102,6 +112,8 @@ private: | |||
| 102 | /// Returns the name of the device in text format | 112 | /// Returns the name of the device in text format |
| 103 | std::string JoyconName(Joycon::ControllerType type) const; | 113 | std::string JoyconName(Joycon::ControllerType type) const; |
| 104 | 114 | ||
| 115 | Common::Input::NfcState TranslateDriverResult(Joycon::DriverResult result) const; | ||
| 116 | |||
| 105 | std::jthread scan_thread; | 117 | std::jthread scan_thread; |
| 106 | 118 | ||
| 107 | // Joycon types are split by type to ease supporting dualjoycon configurations | 119 | // Joycon types are split by type to ease supporting dualjoycon configurations |
diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 6435b8af8..180eb53ef 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp | |||
| @@ -29,14 +29,13 @@ Common::Input::DriverResult VirtualAmiibo::SetPollingMode( | |||
| 29 | 29 | ||
| 30 | switch (polling_mode) { | 30 | switch (polling_mode) { |
| 31 | case Common::Input::PollingMode::NFC: | 31 | case Common::Input::PollingMode::NFC: |
| 32 | if (state == State::Initialized) { | 32 | state = State::Initialized; |
| 33 | state = State::WaitingForAmiibo; | ||
| 34 | } | ||
| 35 | return Common::Input::DriverResult::Success; | 33 | return Common::Input::DriverResult::Success; |
| 36 | default: | 34 | default: |
| 37 | if (state == State::AmiiboIsOpen) { | 35 | if (state == State::TagNearby) { |
| 38 | CloseAmiibo(); | 36 | CloseAmiibo(); |
| 39 | } | 37 | } |
| 38 | state = State::Disabled; | ||
| 40 | return Common::Input::DriverResult::NotSupported; | 39 | return Common::Input::DriverResult::NotSupported; |
| 41 | } | 40 | } |
| 42 | } | 41 | } |
| @@ -45,6 +44,39 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc( | |||
| 45 | [[maybe_unused]] const PadIdentifier& identifier_) const { | 44 | [[maybe_unused]] const PadIdentifier& identifier_) const { |
| 46 | return Common::Input::NfcState::Success; | 45 | return Common::Input::NfcState::Success; |
| 47 | } | 46 | } |
| 47 | Common::Input::NfcState VirtualAmiibo::StartNfcPolling(const PadIdentifier& identifier_) { | ||
| 48 | if (state != State::Initialized) { | ||
| 49 | return Common::Input::NfcState::WrongDeviceState; | ||
| 50 | } | ||
| 51 | state = State::WaitingForAmiibo; | ||
| 52 | return Common::Input::NfcState::Success; | ||
| 53 | } | ||
| 54 | |||
| 55 | Common::Input::NfcState VirtualAmiibo::StopNfcPolling(const PadIdentifier& identifier_) { | ||
| 56 | if (state == State::Disabled) { | ||
| 57 | return Common::Input::NfcState::WrongDeviceState; | ||
| 58 | } | ||
| 59 | if (state == State::TagNearby) { | ||
| 60 | CloseAmiibo(); | ||
| 61 | } | ||
| 62 | state = State::Initialized; | ||
| 63 | return Common::Input::NfcState::Success; | ||
| 64 | } | ||
| 65 | |||
| 66 | Common::Input::NfcState VirtualAmiibo::ReadAmiiboData(const PadIdentifier& identifier_, | ||
| 67 | std::vector<u8>& out_data) { | ||
| 68 | if (state != State::TagNearby) { | ||
| 69 | return Common::Input::NfcState::WrongDeviceState; | ||
| 70 | } | ||
| 71 | |||
| 72 | if (status.tag_type != 1U << 1) { | ||
| 73 | return Common::Input::NfcState::InvalidTagType; | ||
| 74 | } | ||
| 75 | |||
| 76 | out_data.resize(nfc_data.size()); | ||
| 77 | memcpy(out_data.data(), nfc_data.data(), nfc_data.size()); | ||
| 78 | return Common::Input::NfcState::Success; | ||
| 79 | } | ||
| 48 | 80 | ||
| 49 | Common::Input::NfcState VirtualAmiibo::WriteNfcData( | 81 | Common::Input::NfcState VirtualAmiibo::WriteNfcData( |
| 50 | [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { | 82 | [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { |
| @@ -66,6 +98,69 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData( | |||
| 66 | return Common::Input::NfcState::Success; | 98 | return Common::Input::NfcState::Success; |
| 67 | } | 99 | } |
| 68 | 100 | ||
| 101 | Common::Input::NfcState VirtualAmiibo::ReadMifareData(const PadIdentifier& identifier_, | ||
| 102 | const Common::Input::MifareRequest& request, | ||
| 103 | Common::Input::MifareRequest& out_data) { | ||
| 104 | if (state != State::TagNearby) { | ||
| 105 | return Common::Input::NfcState::WrongDeviceState; | ||
| 106 | } | ||
| 107 | |||
| 108 | if (status.tag_type != 1U << 6) { | ||
| 109 | return Common::Input::NfcState::InvalidTagType; | ||
| 110 | } | ||
| 111 | |||
| 112 | for (std::size_t i = 0; i < request.data.size(); i++) { | ||
| 113 | if (request.data[i].command == 0) { | ||
| 114 | continue; | ||
| 115 | } | ||
| 116 | out_data.data[i].command = request.data[i].command; | ||
| 117 | out_data.data[i].sector = request.data[i].sector; | ||
| 118 | |||
| 119 | const std::size_t sector_index = | ||
| 120 | request.data[i].sector * sizeof(Common::Input::MifareData::data); | ||
| 121 | |||
| 122 | if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { | ||
| 123 | return Common::Input::NfcState::WriteFailed; | ||
| 124 | } | ||
| 125 | |||
| 126 | // Ignore the sector key as we don't support it | ||
| 127 | memcpy(out_data.data[i].data.data(), nfc_data.data() + sector_index, | ||
| 128 | sizeof(Common::Input::MifareData::data)); | ||
| 129 | } | ||
| 130 | |||
| 131 | return Common::Input::NfcState::Success; | ||
| 132 | } | ||
| 133 | |||
| 134 | Common::Input::NfcState VirtualAmiibo::WriteMifareData( | ||
| 135 | const PadIdentifier& identifier_, const Common::Input::MifareRequest& request) { | ||
| 136 | if (state != State::TagNearby) { | ||
| 137 | return Common::Input::NfcState::WrongDeviceState; | ||
| 138 | } | ||
| 139 | |||
| 140 | if (status.tag_type != 1U << 6) { | ||
| 141 | return Common::Input::NfcState::InvalidTagType; | ||
| 142 | } | ||
| 143 | |||
| 144 | for (std::size_t i = 0; i < request.data.size(); i++) { | ||
| 145 | if (request.data[i].command == 0) { | ||
| 146 | continue; | ||
| 147 | } | ||
| 148 | |||
| 149 | const std::size_t sector_index = | ||
| 150 | request.data[i].sector * sizeof(Common::Input::MifareData::data); | ||
| 151 | |||
| 152 | if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { | ||
| 153 | return Common::Input::NfcState::WriteFailed; | ||
| 154 | } | ||
| 155 | |||
| 156 | // Ignore the sector key as we don't support it | ||
| 157 | memcpy(nfc_data.data() + sector_index, request.data[i].data.data(), | ||
| 158 | sizeof(Common::Input::MifareData::data)); | ||
| 159 | } | ||
| 160 | |||
| 161 | return Common::Input::NfcState::Success; | ||
| 162 | } | ||
| 163 | |||
| 69 | VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { | 164 | VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { |
| 70 | return state; | 165 | return state; |
| 71 | } | 166 | } |
| @@ -112,23 +207,31 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span<u8> data) { | |||
| 112 | case AmiiboSizeWithoutPassword: | 207 | case AmiiboSizeWithoutPassword: |
| 113 | case AmiiboSizeWithSignature: | 208 | case AmiiboSizeWithSignature: |
| 114 | nfc_data.resize(AmiiboSize); | 209 | nfc_data.resize(AmiiboSize); |
| 210 | status.tag_type = 1U << 1; | ||
| 211 | status.uuid_length = 7; | ||
| 115 | break; | 212 | break; |
| 116 | case MifareSize: | 213 | case MifareSize: |
| 117 | nfc_data.resize(MifareSize); | 214 | nfc_data.resize(MifareSize); |
| 215 | status.tag_type = 1U << 6; | ||
| 216 | status.uuid_length = 4; | ||
| 118 | break; | 217 | break; |
| 119 | default: | 218 | default: |
| 120 | return Info::NotAnAmiibo; | 219 | return Info::NotAnAmiibo; |
| 121 | } | 220 | } |
| 122 | 221 | ||
| 123 | state = State::AmiiboIsOpen; | 222 | status.uuid = {}; |
| 223 | status.protocol = 1; | ||
| 224 | state = State::TagNearby; | ||
| 225 | status.state = Common::Input::NfcState::NewAmiibo, | ||
| 124 | memcpy(nfc_data.data(), data.data(), data.size_bytes()); | 226 | memcpy(nfc_data.data(), data.data(), data.size_bytes()); |
| 125 | SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); | 227 | memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length); |
| 228 | SetNfc(identifier, status); | ||
| 126 | return Info::Success; | 229 | return Info::Success; |
| 127 | } | 230 | } |
| 128 | 231 | ||
| 129 | VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { | 232 | VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { |
| 130 | if (state == State::AmiiboIsOpen) { | 233 | if (state == State::TagNearby) { |
| 131 | SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); | 234 | SetNfc(identifier, status); |
| 132 | return Info::Success; | 235 | return Info::Success; |
| 133 | } | 236 | } |
| 134 | 237 | ||
| @@ -136,9 +239,14 @@ VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { | |||
| 136 | } | 239 | } |
| 137 | 240 | ||
| 138 | VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { | 241 | VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { |
| 139 | state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo | 242 | if (state != State::TagNearby) { |
| 140 | : State::Initialized; | 243 | return Info::Success; |
| 141 | SetNfc(identifier, {Common::Input::NfcState::AmiiboRemoved, {}}); | 244 | } |
| 245 | |||
| 246 | state = State::WaitingForAmiibo; | ||
| 247 | status.state = Common::Input::NfcState::AmiiboRemoved; | ||
| 248 | SetNfc(identifier, status); | ||
| 249 | status.tag_type = 0; | ||
| 142 | return Info::Success; | 250 | return Info::Success; |
| 143 | } | 251 | } |
| 144 | 252 | ||
diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 09ca09e68..490f38e05 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h | |||
| @@ -20,9 +20,10 @@ namespace InputCommon { | |||
| 20 | class VirtualAmiibo final : public InputEngine { | 20 | class VirtualAmiibo final : public InputEngine { |
| 21 | public: | 21 | public: |
| 22 | enum class State { | 22 | enum class State { |
| 23 | Disabled, | ||
| 23 | Initialized, | 24 | Initialized, |
| 24 | WaitingForAmiibo, | 25 | WaitingForAmiibo, |
| 25 | AmiiboIsOpen, | 26 | TagNearby, |
| 26 | }; | 27 | }; |
| 27 | 28 | ||
| 28 | enum class Info { | 29 | enum class Info { |
| @@ -41,9 +42,17 @@ public: | |||
| 41 | const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override; | 42 | const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override; |
| 42 | 43 | ||
| 43 | Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; | 44 | Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; |
| 44 | 45 | Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier_) override; | |
| 46 | Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier_) override; | ||
| 47 | Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier_, | ||
| 48 | std::vector<u8>& out_data) override; | ||
| 45 | Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, | 49 | Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, |
| 46 | const std::vector<u8>& data) override; | 50 | const std::vector<u8>& data) override; |
| 51 | Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier_, | ||
| 52 | const Common::Input::MifareRequest& data, | ||
| 53 | Common::Input::MifareRequest& out_data) override; | ||
| 54 | Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier_, | ||
| 55 | const Common::Input::MifareRequest& data) override; | ||
| 47 | 56 | ||
| 48 | State GetCurrentState() const; | 57 | State GetCurrentState() const; |
| 49 | 58 | ||
| @@ -61,8 +70,9 @@ private: | |||
| 61 | static constexpr std::size_t MifareSize = 0x400; | 70 | static constexpr std::size_t MifareSize = 0x400; |
| 62 | 71 | ||
| 63 | std::string file_path{}; | 72 | std::string file_path{}; |
| 64 | State state{State::Initialized}; | 73 | State state{State::Disabled}; |
| 65 | std::vector<u8> nfc_data; | 74 | std::vector<u8> nfc_data; |
| 75 | Common::Input::NfcStatus status; | ||
| 66 | Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive}; | 76 | Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive}; |
| 67 | }; | 77 | }; |
| 68 | } // namespace InputCommon | 78 | } // namespace InputCommon |
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 95106f16d..2c8c66951 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/logging/log.h" | 4 | #include "common/logging/log.h" |
| 5 | #include "common/scope_exit.h" | ||
| 5 | #include "common/swap.h" | 6 | #include "common/swap.h" |
| 6 | #include "common/thread.h" | 7 | #include "common/thread.h" |
| 7 | #include "input_common/helpers/joycon_driver.h" | 8 | #include "input_common/helpers/joycon_driver.h" |
| @@ -112,7 +113,7 @@ DriverResult JoyconDriver::InitializeDevice() { | |||
| 112 | joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration, | 113 | joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration, |
| 113 | right_stick_calibration, motion_calibration); | 114 | right_stick_calibration, motion_calibration); |
| 114 | 115 | ||
| 115 | // Start pooling for data | 116 | // Start polling for data |
| 116 | is_connected = true; | 117 | is_connected = true; |
| 117 | if (!input_thread_running) { | 118 | if (!input_thread_running) { |
| 118 | input_thread = | 119 | input_thread = |
| @@ -208,7 +209,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 208 | joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); | 209 | joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); |
| 209 | } | 210 | } |
| 210 | 211 | ||
| 211 | if (nfc_protocol->IsEnabled()) { | 212 | if (nfc_protocol->IsPolling()) { |
| 212 | if (amiibo_detected) { | 213 | if (amiibo_detected) { |
| 213 | if (!nfc_protocol->HasAmiibo()) { | 214 | if (!nfc_protocol->HasAmiibo()) { |
| 214 | joycon_poller->UpdateAmiibo({}); | 215 | joycon_poller->UpdateAmiibo({}); |
| @@ -218,10 +219,10 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 218 | } | 219 | } |
| 219 | 220 | ||
| 220 | if (!amiibo_detected) { | 221 | if (!amiibo_detected) { |
| 221 | std::vector<u8> data(0x21C); | 222 | Joycon::TagInfo tag_info; |
| 222 | const auto result = nfc_protocol->ScanAmiibo(data); | 223 | const auto result = nfc_protocol->GetTagInfo(tag_info); |
| 223 | if (result == DriverResult::Success) { | 224 | if (result == DriverResult::Success) { |
| 224 | joycon_poller->UpdateAmiibo(data); | 225 | joycon_poller->UpdateAmiibo(tag_info); |
| 225 | amiibo_detected = true; | 226 | amiibo_detected = true; |
| 226 | } | 227 | } |
| 227 | } | 228 | } |
| @@ -247,6 +248,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { | |||
| 247 | } | 248 | } |
| 248 | 249 | ||
| 249 | DriverResult JoyconDriver::SetPollingMode() { | 250 | DriverResult JoyconDriver::SetPollingMode() { |
| 251 | SCOPE_EXIT({ disable_input_thread = false; }); | ||
| 250 | disable_input_thread = true; | 252 | disable_input_thread = true; |
| 251 | 253 | ||
| 252 | rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); | 254 | rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); |
| @@ -276,7 +278,6 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 276 | if (irs_enabled && supported_features.irs) { | 278 | if (irs_enabled && supported_features.irs) { |
| 277 | auto result = irs_protocol->EnableIrs(); | 279 | auto result = irs_protocol->EnableIrs(); |
| 278 | if (result == DriverResult::Success) { | 280 | if (result == DriverResult::Success) { |
| 279 | disable_input_thread = false; | ||
| 280 | return result; | 281 | return result; |
| 281 | } | 282 | } |
| 282 | irs_protocol->DisableIrs(); | 283 | irs_protocol->DisableIrs(); |
| @@ -286,10 +287,6 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 286 | if (nfc_enabled && supported_features.nfc) { | 287 | if (nfc_enabled && supported_features.nfc) { |
| 287 | auto result = nfc_protocol->EnableNfc(); | 288 | auto result = nfc_protocol->EnableNfc(); |
| 288 | if (result == DriverResult::Success) { | 289 | if (result == DriverResult::Success) { |
| 289 | result = nfc_protocol->StartNFCPollingMode(); | ||
| 290 | } | ||
| 291 | if (result == DriverResult::Success) { | ||
| 292 | disable_input_thread = false; | ||
| 293 | return result; | 290 | return result; |
| 294 | } | 291 | } |
| 295 | nfc_protocol->DisableNfc(); | 292 | nfc_protocol->DisableNfc(); |
| @@ -303,7 +300,6 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 303 | } | 300 | } |
| 304 | if (result == DriverResult::Success) { | 301 | if (result == DriverResult::Success) { |
| 305 | ring_connected = true; | 302 | ring_connected = true; |
| 306 | disable_input_thread = false; | ||
| 307 | return result; | 303 | return result; |
| 308 | } | 304 | } |
| 309 | ring_connected = false; | 305 | ring_connected = false; |
| @@ -314,7 +310,6 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 314 | if (passive_enabled && supported_features.passive) { | 310 | if (passive_enabled && supported_features.passive) { |
| 315 | const auto result = generic_protocol->EnablePassiveMode(); | 311 | const auto result = generic_protocol->EnablePassiveMode(); |
| 316 | if (result == DriverResult::Success) { | 312 | if (result == DriverResult::Success) { |
| 317 | disable_input_thread = false; | ||
| 318 | return result; | 313 | return result; |
| 319 | } | 314 | } |
| 320 | LOG_ERROR(Input, "Error enabling passive mode"); | 315 | LOG_ERROR(Input, "Error enabling passive mode"); |
| @@ -328,7 +323,6 @@ DriverResult JoyconDriver::SetPollingMode() { | |||
| 328 | // Switch calls this function after enabling active mode | 323 | // Switch calls this function after enabling active mode |
| 329 | generic_protocol->TriggersElapsed(); | 324 | generic_protocol->TriggersElapsed(); |
| 330 | 325 | ||
| 331 | disable_input_thread = false; | ||
| 332 | return result; | 326 | return result; |
| 333 | } | 327 | } |
| 334 | 328 | ||
| @@ -492,9 +486,63 @@ DriverResult JoyconDriver::SetRingConMode() { | |||
| 492 | return result; | 486 | return result; |
| 493 | } | 487 | } |
| 494 | 488 | ||
| 495 | DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { | 489 | DriverResult JoyconDriver::StartNfcPolling() { |
| 496 | std::scoped_lock lock{mutex}; | 490 | std::scoped_lock lock{mutex}; |
| 491 | |||
| 492 | if (!supported_features.nfc) { | ||
| 493 | return DriverResult::NotSupported; | ||
| 494 | } | ||
| 495 | if (!nfc_protocol->IsEnabled()) { | ||
| 496 | return DriverResult::Disabled; | ||
| 497 | } | ||
| 498 | |||
| 499 | disable_input_thread = true; | ||
| 500 | const auto result = nfc_protocol->StartNFCPollingMode(); | ||
| 501 | disable_input_thread = false; | ||
| 502 | |||
| 503 | return result; | ||
| 504 | } | ||
| 505 | |||
| 506 | DriverResult JoyconDriver::StopNfcPolling() { | ||
| 507 | std::scoped_lock lock{mutex}; | ||
| 508 | |||
| 509 | if (!supported_features.nfc) { | ||
| 510 | return DriverResult::NotSupported; | ||
| 511 | } | ||
| 512 | if (!nfc_protocol->IsEnabled()) { | ||
| 513 | return DriverResult::Disabled; | ||
| 514 | } | ||
| 515 | |||
| 516 | disable_input_thread = true; | ||
| 517 | const auto result = nfc_protocol->StopNFCPollingMode(); | ||
| 518 | disable_input_thread = false; | ||
| 519 | |||
| 520 | return result; | ||
| 521 | } | ||
| 522 | |||
| 523 | DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) { | ||
| 524 | std::scoped_lock lock{mutex}; | ||
| 525 | |||
| 526 | if (!supported_features.nfc) { | ||
| 527 | return DriverResult::NotSupported; | ||
| 528 | } | ||
| 529 | if (!nfc_protocol->IsEnabled()) { | ||
| 530 | return DriverResult::Disabled; | ||
| 531 | } | ||
| 532 | if (!amiibo_detected) { | ||
| 533 | return DriverResult::ErrorWritingData; | ||
| 534 | } | ||
| 535 | |||
| 536 | out_data.resize(0x21C); | ||
| 497 | disable_input_thread = true; | 537 | disable_input_thread = true; |
| 538 | const auto result = nfc_protocol->ReadAmiibo(out_data); | ||
| 539 | disable_input_thread = false; | ||
| 540 | |||
| 541 | return result; | ||
| 542 | } | ||
| 543 | |||
| 544 | DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { | ||
| 545 | std::scoped_lock lock{mutex}; | ||
| 498 | 546 | ||
| 499 | if (!supported_features.nfc) { | 547 | if (!supported_features.nfc) { |
| 500 | return DriverResult::NotSupported; | 548 | return DriverResult::NotSupported; |
| @@ -506,9 +554,51 @@ DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { | |||
| 506 | return DriverResult::ErrorWritingData; | 554 | return DriverResult::ErrorWritingData; |
| 507 | } | 555 | } |
| 508 | 556 | ||
| 557 | disable_input_thread = true; | ||
| 509 | const auto result = nfc_protocol->WriteAmiibo(data); | 558 | const auto result = nfc_protocol->WriteAmiibo(data); |
| 559 | disable_input_thread = false; | ||
| 510 | 560 | ||
| 561 | return result; | ||
| 562 | } | ||
| 563 | |||
| 564 | DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data, | ||
| 565 | std::span<MifareReadData> out_data) { | ||
| 566 | std::scoped_lock lock{mutex}; | ||
| 567 | |||
| 568 | if (!supported_features.nfc) { | ||
| 569 | return DriverResult::NotSupported; | ||
| 570 | } | ||
| 571 | if (!nfc_protocol->IsEnabled()) { | ||
| 572 | return DriverResult::Disabled; | ||
| 573 | } | ||
| 574 | if (!amiibo_detected) { | ||
| 575 | return DriverResult::ErrorWritingData; | ||
| 576 | } | ||
| 577 | |||
| 578 | disable_input_thread = true; | ||
| 579 | const auto result = nfc_protocol->ReadMifare(data, out_data); | ||
| 580 | disable_input_thread = false; | ||
| 581 | |||
| 582 | return result; | ||
| 583 | } | ||
| 584 | |||
| 585 | DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) { | ||
| 586 | std::scoped_lock lock{mutex}; | ||
| 587 | |||
| 588 | if (!supported_features.nfc) { | ||
| 589 | return DriverResult::NotSupported; | ||
| 590 | } | ||
| 591 | if (!nfc_protocol->IsEnabled()) { | ||
| 592 | return DriverResult::Disabled; | ||
| 593 | } | ||
| 594 | if (!amiibo_detected) { | ||
| 595 | return DriverResult::ErrorWritingData; | ||
| 596 | } | ||
| 597 | |||
| 598 | disable_input_thread = true; | ||
| 599 | const auto result = nfc_protocol->WriteMifare(data); | ||
| 511 | disable_input_thread = false; | 600 | disable_input_thread = false; |
| 601 | |||
| 512 | return result; | 602 | return result; |
| 513 | } | 603 | } |
| 514 | 604 | ||
diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index e9b2fccbb..bc7025a21 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h | |||
| @@ -49,7 +49,13 @@ public: | |||
| 49 | DriverResult SetIrMode(); | 49 | DriverResult SetIrMode(); |
| 50 | DriverResult SetNfcMode(); | 50 | DriverResult SetNfcMode(); |
| 51 | DriverResult SetRingConMode(); | 51 | DriverResult SetRingConMode(); |
| 52 | DriverResult StartNfcPolling(); | ||
| 53 | DriverResult StopNfcPolling(); | ||
| 54 | DriverResult ReadAmiiboData(std::vector<u8>& out_data); | ||
| 52 | DriverResult WriteNfcData(std::span<const u8> data); | 55 | DriverResult WriteNfcData(std::span<const u8> data); |
| 56 | DriverResult ReadMifareData(std::span<const MifareReadChunk> request, | ||
| 57 | std::span<MifareReadData> out_data); | ||
| 58 | DriverResult WriteMifareData(std::span<const MifareWriteChunk> request); | ||
| 53 | 59 | ||
| 54 | void SetCallbacks(const JoyconCallbacks& callbacks); | 60 | void SetCallbacks(const JoyconCallbacks& callbacks); |
| 55 | 61 | ||
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index 5007b0e18..e0e431156 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h | |||
| @@ -24,6 +24,7 @@ constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x | |||
| 24 | using MacAddress = std::array<u8, 6>; | 24 | using MacAddress = std::array<u8, 6>; |
| 25 | using SerialNumber = std::array<u8, 15>; | 25 | using SerialNumber = std::array<u8, 15>; |
| 26 | using TagUUID = std::array<u8, 7>; | 26 | using TagUUID = std::array<u8, 7>; |
| 27 | using MifareUUID = std::array<u8, 4>; | ||
| 27 | 28 | ||
| 28 | enum class ControllerType : u8 { | 29 | enum class ControllerType : u8 { |
| 29 | None = 0x00, | 30 | None = 0x00, |
| @@ -307,6 +308,19 @@ enum class NFCStatus : u8 { | |||
| 307 | WriteDone = 0x05, | 308 | WriteDone = 0x05, |
| 308 | TagLost = 0x07, | 309 | TagLost = 0x07, |
| 309 | WriteReady = 0x09, | 310 | WriteReady = 0x09, |
| 311 | MifareDone = 0x10, | ||
| 312 | }; | ||
| 313 | |||
| 314 | enum class MifareCmd : u8 { | ||
| 315 | None = 0x00, | ||
| 316 | Read = 0x30, | ||
| 317 | AuthA = 0x60, | ||
| 318 | AuthB = 0x61, | ||
| 319 | Write = 0xA0, | ||
| 320 | Transfer = 0xB0, | ||
| 321 | Decrement = 0xC0, | ||
| 322 | Increment = 0xC1, | ||
| 323 | Store = 0xC2 | ||
| 310 | }; | 324 | }; |
| 311 | 325 | ||
| 312 | enum class IrsMode : u8 { | 326 | enum class IrsMode : u8 { |
| @@ -592,6 +606,14 @@ struct NFCWriteCommandData { | |||
| 592 | static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); | 606 | static_assert(sizeof(NFCWriteCommandData) == 0x15, "NFCWriteCommandData is an invalid size"); |
| 593 | #pragma pack(pop) | 607 | #pragma pack(pop) |
| 594 | 608 | ||
| 609 | struct MifareCommandData { | ||
| 610 | u8 unknown1; | ||
| 611 | u8 unknown2; | ||
| 612 | u8 number_of_short_bytes; | ||
| 613 | MifareUUID uid; | ||
| 614 | }; | ||
| 615 | static_assert(sizeof(MifareCommandData) == 0x7, "MifareCommandData is an invalid size"); | ||
| 616 | |||
| 595 | struct NFCPollingCommandData { | 617 | struct NFCPollingCommandData { |
| 596 | u8 enable_mifare; | 618 | u8 enable_mifare; |
| 597 | u8 unknown_1; | 619 | u8 unknown_1; |
| @@ -629,6 +651,41 @@ struct NFCWritePackage { | |||
| 629 | std::array<NFCDataChunk, 4> data_chunks; | 651 | std::array<NFCDataChunk, 4> data_chunks; |
| 630 | }; | 652 | }; |
| 631 | 653 | ||
| 654 | struct MifareReadChunk { | ||
| 655 | MifareCmd command; | ||
| 656 | std::array<u8, 0x6> sector_key; | ||
| 657 | u8 sector; | ||
| 658 | }; | ||
| 659 | |||
| 660 | struct MifareWriteChunk { | ||
| 661 | MifareCmd command; | ||
| 662 | std::array<u8, 0x6> sector_key; | ||
| 663 | u8 sector; | ||
| 664 | std::array<u8, 0x10> data; | ||
| 665 | }; | ||
| 666 | |||
| 667 | struct MifareReadData { | ||
| 668 | u8 sector; | ||
| 669 | std::array<u8, 0x10> data; | ||
| 670 | }; | ||
| 671 | |||
| 672 | struct MifareReadPackage { | ||
| 673 | MifareCommandData command_data; | ||
| 674 | std::array<MifareReadChunk, 0x10> data_chunks; | ||
| 675 | }; | ||
| 676 | |||
| 677 | struct MifareWritePackage { | ||
| 678 | MifareCommandData command_data; | ||
| 679 | std::array<MifareWriteChunk, 0x10> data_chunks; | ||
| 680 | }; | ||
| 681 | |||
| 682 | struct TagInfo { | ||
| 683 | u8 uuid_length; | ||
| 684 | u8 protocol; | ||
| 685 | u8 tag_type; | ||
| 686 | std::array<u8, 10> uuid; | ||
| 687 | }; | ||
| 688 | |||
| 632 | struct IrsConfigure { | 689 | struct IrsConfigure { |
| 633 | MCUCommand command; | 690 | MCUCommand command; |
| 634 | MCUSubCommand sub_command; | 691 | MCUSubCommand sub_command; |
| @@ -744,7 +801,7 @@ struct JoyconCallbacks { | |||
| 744 | std::function<void(int, f32)> on_stick_data; | 801 | std::function<void(int, f32)> on_stick_data; |
| 745 | std::function<void(int, const MotionData&)> on_motion_data; | 802 | std::function<void(int, const MotionData&)> on_motion_data; |
| 746 | std::function<void(f32)> on_ring_data; | 803 | std::function<void(f32)> on_ring_data; |
| 747 | std::function<void(const std::vector<u8>&)> on_amiibo_data; | 804 | std::function<void(const Joycon::TagInfo&)> on_amiibo_data; |
| 748 | std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data; | 805 | std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data; |
| 749 | }; | 806 | }; |
| 750 | 807 | ||
diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp index f7058c4a7..261f46255 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.cpp +++ b/src/input_common/helpers/joycon_protocol/nfc.cpp | |||
| @@ -40,6 +40,16 @@ DriverResult NfcProtocol::EnableNfc() { | |||
| 40 | if (result == DriverResult::Success) { | 40 | if (result == DriverResult::Success) { |
| 41 | result = WaitUntilNfcIs(NFCStatus::Ready); | 41 | result = WaitUntilNfcIs(NFCStatus::Ready); |
| 42 | } | 42 | } |
| 43 | if (result == DriverResult::Success) { | ||
| 44 | MCUCommandResponse output{}; | ||
| 45 | result = SendStopPollingRequest(output); | ||
| 46 | } | ||
| 47 | if (result == DriverResult::Success) { | ||
| 48 | result = WaitUntilNfcIs(NFCStatus::Ready); | ||
| 49 | } | ||
| 50 | if (result == DriverResult::Success) { | ||
| 51 | is_enabled = true; | ||
| 52 | } | ||
| 43 | 53 | ||
| 44 | return result; | 54 | return result; |
| 45 | } | 55 | } |
| @@ -54,37 +64,50 @@ DriverResult NfcProtocol::DisableNfc() { | |||
| 54 | } | 64 | } |
| 55 | 65 | ||
| 56 | is_enabled = false; | 66 | is_enabled = false; |
| 67 | is_polling = false; | ||
| 57 | 68 | ||
| 58 | return result; | 69 | return result; |
| 59 | } | 70 | } |
| 60 | 71 | ||
| 61 | DriverResult NfcProtocol::StartNFCPollingMode() { | 72 | DriverResult NfcProtocol::StartNFCPollingMode() { |
| 62 | LOG_DEBUG(Input, "Start NFC pooling Mode"); | 73 | LOG_DEBUG(Input, "Start NFC polling Mode"); |
| 63 | ScopedSetBlocking sb(this); | 74 | ScopedSetBlocking sb(this); |
| 64 | DriverResult result{DriverResult::Success}; | 75 | DriverResult result{DriverResult::Success}; |
| 65 | 76 | ||
| 66 | if (result == DriverResult::Success) { | 77 | if (result == DriverResult::Success) { |
| 67 | MCUCommandResponse output{}; | 78 | MCUCommandResponse output{}; |
| 68 | result = SendStopPollingRequest(output); | 79 | result = SendStartPollingRequest(output); |
| 69 | } | 80 | } |
| 70 | if (result == DriverResult::Success) { | 81 | if (result == DriverResult::Success) { |
| 71 | result = WaitUntilNfcIs(NFCStatus::Ready); | 82 | result = WaitUntilNfcIs(NFCStatus::Polling); |
| 72 | } | 83 | } |
| 73 | if (result == DriverResult::Success) { | 84 | if (result == DriverResult::Success) { |
| 85 | is_polling = true; | ||
| 86 | } | ||
| 87 | |||
| 88 | return result; | ||
| 89 | } | ||
| 90 | |||
| 91 | DriverResult NfcProtocol::StopNFCPollingMode() { | ||
| 92 | LOG_DEBUG(Input, "Stop NFC polling Mode"); | ||
| 93 | ScopedSetBlocking sb(this); | ||
| 94 | DriverResult result{DriverResult::Success}; | ||
| 95 | |||
| 96 | if (result == DriverResult::Success) { | ||
| 74 | MCUCommandResponse output{}; | 97 | MCUCommandResponse output{}; |
| 75 | result = SendStartPollingRequest(output); | 98 | result = SendStopPollingRequest(output); |
| 76 | } | 99 | } |
| 77 | if (result == DriverResult::Success) { | 100 | if (result == DriverResult::Success) { |
| 78 | result = WaitUntilNfcIs(NFCStatus::Polling); | 101 | result = WaitUntilNfcIs(NFCStatus::WriteReady); |
| 79 | } | 102 | } |
| 80 | if (result == DriverResult::Success) { | 103 | if (result == DriverResult::Success) { |
| 81 | is_enabled = true; | 104 | is_polling = false; |
| 82 | } | 105 | } |
| 83 | 106 | ||
| 84 | return result; | 107 | return result; |
| 85 | } | 108 | } |
| 86 | 109 | ||
| 87 | DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { | 110 | DriverResult NfcProtocol::GetTagInfo(Joycon::TagInfo& tag_info) { |
| 88 | if (update_counter++ < AMIIBO_UPDATE_DELAY) { | 111 | if (update_counter++ < AMIIBO_UPDATE_DELAY) { |
| 89 | return DriverResult::Delayed; | 112 | return DriverResult::Delayed; |
| 90 | } | 113 | } |
| @@ -100,11 +123,41 @@ DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { | |||
| 100 | } | 123 | } |
| 101 | 124 | ||
| 102 | if (result == DriverResult::Success) { | 125 | if (result == DriverResult::Success) { |
| 126 | tag_info = { | ||
| 127 | .uuid_length = tag_data.uuid_size, | ||
| 128 | .protocol = 1, | ||
| 129 | .tag_type = tag_data.type, | ||
| 130 | .uuid = {}, | ||
| 131 | }; | ||
| 132 | |||
| 133 | memcpy(tag_info.uuid.data(), tag_data.uuid.data(), tag_data.uuid_size); | ||
| 134 | |||
| 135 | // Investigate why mifare type is not correct | ||
| 136 | if (tag_info.tag_type == 144) { | ||
| 137 | tag_info.tag_type = 1U << 6; | ||
| 138 | } | ||
| 139 | |||
| 103 | std::string uuid_string; | 140 | std::string uuid_string; |
| 104 | for (auto& content : tag_data.uuid) { | 141 | for (auto& content : tag_data.uuid) { |
| 105 | uuid_string += fmt::format(" {:02x}", content); | 142 | uuid_string += fmt::format(" {:02x}", content); |
| 106 | } | 143 | } |
| 107 | LOG_INFO(Input, "Tag detected, type={}, uuid={}", tag_data.type, uuid_string); | 144 | LOG_INFO(Input, "Tag detected, type={}, uuid={}", tag_data.type, uuid_string); |
| 145 | } | ||
| 146 | |||
| 147 | return result; | ||
| 148 | } | ||
| 149 | |||
| 150 | DriverResult NfcProtocol::ReadAmiibo(std::vector<u8>& data) { | ||
| 151 | LOG_DEBUG(Input, "Scan for amiibos"); | ||
| 152 | ScopedSetBlocking sb(this); | ||
| 153 | DriverResult result{DriverResult::Success}; | ||
| 154 | TagFoundData tag_data{}; | ||
| 155 | |||
| 156 | if (result == DriverResult::Success) { | ||
| 157 | result = IsTagInRange(tag_data, 7); | ||
| 158 | } | ||
| 159 | |||
| 160 | if (result == DriverResult::Success) { | ||
| 108 | result = GetAmiiboData(data); | 161 | result = GetAmiiboData(data); |
| 109 | } | 162 | } |
| 110 | 163 | ||
| @@ -154,6 +207,69 @@ DriverResult NfcProtocol::WriteAmiibo(std::span<const u8> data) { | |||
| 154 | return result; | 207 | return result; |
| 155 | } | 208 | } |
| 156 | 209 | ||
| 210 | DriverResult NfcProtocol::ReadMifare(std::span<const MifareReadChunk> read_request, | ||
| 211 | std::span<MifareReadData> out_data) { | ||
| 212 | LOG_DEBUG(Input, "Read mifare"); | ||
| 213 | ScopedSetBlocking sb(this); | ||
| 214 | DriverResult result{DriverResult::Success}; | ||
| 215 | TagFoundData tag_data{}; | ||
| 216 | MifareUUID tag_uuid{}; | ||
| 217 | |||
| 218 | if (result == DriverResult::Success) { | ||
| 219 | result = IsTagInRange(tag_data, 7); | ||
| 220 | } | ||
| 221 | if (result == DriverResult::Success) { | ||
| 222 | memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); | ||
| 223 | result = GetMifareData(tag_uuid, read_request, out_data); | ||
| 224 | } | ||
| 225 | if (result == DriverResult::Success) { | ||
| 226 | MCUCommandResponse output{}; | ||
| 227 | result = SendStopPollingRequest(output); | ||
| 228 | } | ||
| 229 | if (result == DriverResult::Success) { | ||
| 230 | result = WaitUntilNfcIs(NFCStatus::Ready); | ||
| 231 | } | ||
| 232 | if (result == DriverResult::Success) { | ||
| 233 | MCUCommandResponse output{}; | ||
| 234 | result = SendStartPollingRequest(output, true); | ||
| 235 | } | ||
| 236 | if (result == DriverResult::Success) { | ||
| 237 | result = WaitUntilNfcIs(NFCStatus::WriteReady); | ||
| 238 | } | ||
| 239 | return result; | ||
| 240 | } | ||
| 241 | |||
| 242 | DriverResult NfcProtocol::WriteMifare(std::span<const MifareWriteChunk> write_request) { | ||
| 243 | LOG_DEBUG(Input, "Write mifare"); | ||
| 244 | ScopedSetBlocking sb(this); | ||
| 245 | DriverResult result{DriverResult::Success}; | ||
| 246 | TagFoundData tag_data{}; | ||
| 247 | MifareUUID tag_uuid{}; | ||
| 248 | |||
| 249 | if (result == DriverResult::Success) { | ||
| 250 | result = IsTagInRange(tag_data, 7); | ||
| 251 | } | ||
| 252 | if (result == DriverResult::Success) { | ||
| 253 | memcpy(tag_uuid.data(), tag_data.uuid.data(), sizeof(MifareUUID)); | ||
| 254 | result = WriteMifareData(tag_uuid, write_request); | ||
| 255 | } | ||
| 256 | if (result == DriverResult::Success) { | ||
| 257 | MCUCommandResponse output{}; | ||
| 258 | result = SendStopPollingRequest(output); | ||
| 259 | } | ||
| 260 | if (result == DriverResult::Success) { | ||
| 261 | result = WaitUntilNfcIs(NFCStatus::Ready); | ||
| 262 | } | ||
| 263 | if (result == DriverResult::Success) { | ||
| 264 | MCUCommandResponse output{}; | ||
| 265 | result = SendStartPollingRequest(output, true); | ||
| 266 | } | ||
| 267 | if (result == DriverResult::Success) { | ||
| 268 | result = WaitUntilNfcIs(NFCStatus::WriteReady); | ||
| 269 | } | ||
| 270 | return result; | ||
| 271 | } | ||
| 272 | |||
| 157 | bool NfcProtocol::HasAmiibo() { | 273 | bool NfcProtocol::HasAmiibo() { |
| 158 | if (update_counter++ < AMIIBO_UPDATE_DELAY) { | 274 | if (update_counter++ < AMIIBO_UPDATE_DELAY) { |
| 159 | return true; | 275 | return true; |
| @@ -341,6 +457,158 @@ DriverResult NfcProtocol::WriteAmiiboData(const TagUUID& tag_uuid, std::span<con | |||
| 341 | return result; | 457 | return result; |
| 342 | } | 458 | } |
| 343 | 459 | ||
| 460 | DriverResult NfcProtocol::GetMifareData(const MifareUUID& tag_uuid, | ||
| 461 | std::span<const MifareReadChunk> read_request, | ||
| 462 | std::span<MifareReadData> out_data) { | ||
| 463 | constexpr std::size_t timeout_limit = 60; | ||
| 464 | const auto nfc_data = MakeMifareReadPackage(tag_uuid, read_request); | ||
| 465 | const std::vector<u8> nfc_buffer_data = SerializeMifareReadPackage(nfc_data); | ||
| 466 | std::span<const u8> buffer(nfc_buffer_data); | ||
| 467 | DriverResult result = DriverResult::Success; | ||
| 468 | MCUCommandResponse output{}; | ||
| 469 | u8 block_id = 1; | ||
| 470 | u8 package_index = 0; | ||
| 471 | std::size_t tries = 0; | ||
| 472 | std::size_t current_position = 0; | ||
| 473 | |||
| 474 | LOG_INFO(Input, "Reading Mifare data"); | ||
| 475 | |||
| 476 | // Send data request. Nfc buffer size is 31, Send the data in smaller packages | ||
| 477 | while (current_position < buffer.size() && tries++ < timeout_limit) { | ||
| 478 | const std::size_t next_position = | ||
| 479 | std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size()); | ||
| 480 | const std::size_t block_size = next_position - current_position; | ||
| 481 | const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data); | ||
| 482 | |||
| 483 | SendReadDataMifareRequest(output, block_id, is_last_packet, | ||
| 484 | buffer.subspan(current_position, block_size)); | ||
| 485 | |||
| 486 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 487 | |||
| 488 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 489 | return DriverResult::ErrorReadingData; | ||
| 490 | } | ||
| 491 | |||
| 492 | // Increase position when data is confirmed by the joycon | ||
| 493 | if (output.mcu_report == MCUReport::NFCState && | ||
| 494 | (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 && | ||
| 495 | output.mcu_data[3] == block_id) { | ||
| 496 | block_id++; | ||
| 497 | current_position = next_position; | ||
| 498 | } | ||
| 499 | } | ||
| 500 | |||
| 501 | if (result != DriverResult::Success) { | ||
| 502 | return result; | ||
| 503 | } | ||
| 504 | |||
| 505 | // Wait for reply and save the output data | ||
| 506 | while (tries++ < timeout_limit) { | ||
| 507 | result = SendNextPackageRequest(output, package_index); | ||
| 508 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 509 | |||
| 510 | if (result != DriverResult::Success) { | ||
| 511 | return result; | ||
| 512 | } | ||
| 513 | |||
| 514 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 515 | return DriverResult::ErrorReadingData; | ||
| 516 | } | ||
| 517 | |||
| 518 | if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { | ||
| 519 | constexpr std::size_t DATA_LENGHT = 0x10 + 1; | ||
| 520 | constexpr std::size_t DATA_START = 11; | ||
| 521 | const u8 number_of_elements = output.mcu_data[10]; | ||
| 522 | for (std::size_t i = 0; i < number_of_elements; i++) { | ||
| 523 | out_data[i].sector = output.mcu_data[DATA_START + (i * DATA_LENGHT)]; | ||
| 524 | memcpy(out_data[i].data.data(), | ||
| 525 | output.mcu_data.data() + DATA_START + 1 + (i * DATA_LENGHT), | ||
| 526 | sizeof(MifareReadData::data)); | ||
| 527 | } | ||
| 528 | package_index++; | ||
| 529 | continue; | ||
| 530 | } | ||
| 531 | |||
| 532 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) { | ||
| 533 | LOG_INFO(Input, "Finished reading mifare"); | ||
| 534 | break; | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | return result; | ||
| 539 | } | ||
| 540 | |||
| 541 | DriverResult NfcProtocol::WriteMifareData(const MifareUUID& tag_uuid, | ||
| 542 | std::span<const MifareWriteChunk> write_request) { | ||
| 543 | constexpr std::size_t timeout_limit = 60; | ||
| 544 | const auto nfc_data = MakeMifareWritePackage(tag_uuid, write_request); | ||
| 545 | const std::vector<u8> nfc_buffer_data = SerializeMifareWritePackage(nfc_data); | ||
| 546 | std::span<const u8> buffer(nfc_buffer_data); | ||
| 547 | DriverResult result = DriverResult::Success; | ||
| 548 | MCUCommandResponse output{}; | ||
| 549 | u8 block_id = 1; | ||
| 550 | u8 package_index = 0; | ||
| 551 | std::size_t tries = 0; | ||
| 552 | std::size_t current_position = 0; | ||
| 553 | |||
| 554 | LOG_INFO(Input, "Writing Mifare data"); | ||
| 555 | |||
| 556 | // Send data request. Nfc buffer size is 31, Send the data in smaller packages | ||
| 557 | while (current_position < buffer.size() && tries++ < timeout_limit) { | ||
| 558 | const std::size_t next_position = | ||
| 559 | std::min(current_position + sizeof(NFCRequestState::raw_data), buffer.size()); | ||
| 560 | const std::size_t block_size = next_position - current_position; | ||
| 561 | const bool is_last_packet = block_size < sizeof(NFCRequestState::raw_data); | ||
| 562 | |||
| 563 | SendReadDataMifareRequest(output, block_id, is_last_packet, | ||
| 564 | buffer.subspan(current_position, block_size)); | ||
| 565 | |||
| 566 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 567 | |||
| 568 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 569 | return DriverResult::ErrorReadingData; | ||
| 570 | } | ||
| 571 | |||
| 572 | // Increase position when data is confirmed by the joycon | ||
| 573 | if (output.mcu_report == MCUReport::NFCState && | ||
| 574 | (output.mcu_data[1] << 8) + output.mcu_data[0] == 0x0500 && | ||
| 575 | output.mcu_data[3] == block_id) { | ||
| 576 | block_id++; | ||
| 577 | current_position = next_position; | ||
| 578 | } | ||
| 579 | } | ||
| 580 | |||
| 581 | if (result != DriverResult::Success) { | ||
| 582 | return result; | ||
| 583 | } | ||
| 584 | |||
| 585 | // Wait for reply and ignore the output data | ||
| 586 | while (tries++ < timeout_limit) { | ||
| 587 | result = SendNextPackageRequest(output, package_index); | ||
| 588 | const auto nfc_status = static_cast<NFCStatus>(output.mcu_data[6]); | ||
| 589 | |||
| 590 | if (result != DriverResult::Success) { | ||
| 591 | return result; | ||
| 592 | } | ||
| 593 | |||
| 594 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::TagLost) { | ||
| 595 | return DriverResult::ErrorReadingData; | ||
| 596 | } | ||
| 597 | |||
| 598 | if (output.mcu_report == MCUReport::NFCState && output.mcu_data[1] == 0x10) { | ||
| 599 | package_index++; | ||
| 600 | continue; | ||
| 601 | } | ||
| 602 | |||
| 603 | if (output.mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::MifareDone) { | ||
| 604 | LOG_INFO(Input, "Finished writing mifare"); | ||
| 605 | break; | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | return result; | ||
| 610 | } | ||
| 611 | |||
| 344 | DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, | 612 | DriverResult NfcProtocol::SendStartPollingRequest(MCUCommandResponse& output, |
| 345 | bool is_second_attempt) { | 613 | bool is_second_attempt) { |
| 346 | NFCRequestState request{ | 614 | NFCRequestState request{ |
| @@ -477,6 +745,28 @@ DriverResult NfcProtocol::SendWriteDataAmiiboRequest(MCUCommandResponse& output, | |||
| 477 | output); | 745 | output); |
| 478 | } | 746 | } |
| 479 | 747 | ||
| 748 | DriverResult NfcProtocol::SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, | ||
| 749 | bool is_last_packet, std::span<const u8> data) { | ||
| 750 | const auto data_size = std::min(data.size(), sizeof(NFCRequestState::raw_data)); | ||
| 751 | NFCRequestState request{ | ||
| 752 | .command_argument = NFCCommand::Mifare, | ||
| 753 | .block_id = block_id, | ||
| 754 | .packet_id = {}, | ||
| 755 | .packet_flag = | ||
| 756 | is_last_packet ? MCUPacketFlag::LastCommandPacket : MCUPacketFlag::MorePacketsRemaining, | ||
| 757 | .data_length = static_cast<u8>(data_size), | ||
| 758 | .raw_data = {}, | ||
| 759 | .crc = {}, | ||
| 760 | }; | ||
| 761 | memcpy(request.raw_data.data(), data.data(), data_size); | ||
| 762 | |||
| 763 | std::array<u8, sizeof(NFCRequestState)> request_data{}; | ||
| 764 | memcpy(request_data.data(), &request, sizeof(NFCRequestState)); | ||
| 765 | request_data[36] = CalculateMCU_CRC8(request_data.data(), 36); | ||
| 766 | return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, MCUSubCommand::ReadDeviceMode, request_data, | ||
| 767 | output); | ||
| 768 | } | ||
| 769 | |||
| 480 | std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const { | 770 | std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& package) const { |
| 481 | const std::size_t header_size = | 771 | const std::size_t header_size = |
| 482 | sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks); | 772 | sizeof(NFCWriteCommandData) + sizeof(NFCWritePackage::number_of_chunks); |
| @@ -498,6 +788,48 @@ std::vector<u8> NfcProtocol::SerializeWritePackage(const NFCWritePackage& packag | |||
| 498 | return serialized_data; | 788 | return serialized_data; |
| 499 | } | 789 | } |
| 500 | 790 | ||
| 791 | std::vector<u8> NfcProtocol::SerializeMifareReadPackage(const MifareReadPackage& package) const { | ||
| 792 | const std::size_t header_size = sizeof(MifareCommandData); | ||
| 793 | std::vector<u8> serialized_data(header_size); | ||
| 794 | std::size_t start_index = 0; | ||
| 795 | |||
| 796 | memcpy(serialized_data.data(), &package, header_size); | ||
| 797 | start_index += header_size; | ||
| 798 | |||
| 799 | for (const auto& data_chunk : package.data_chunks) { | ||
| 800 | const std::size_t chunk_size = sizeof(MifareReadChunk); | ||
| 801 | if (data_chunk.command == MifareCmd::None) { | ||
| 802 | continue; | ||
| 803 | } | ||
| 804 | serialized_data.resize(start_index + chunk_size); | ||
| 805 | memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size); | ||
| 806 | start_index += chunk_size; | ||
| 807 | } | ||
| 808 | |||
| 809 | return serialized_data; | ||
| 810 | } | ||
| 811 | |||
| 812 | std::vector<u8> NfcProtocol::SerializeMifareWritePackage(const MifareWritePackage& package) const { | ||
| 813 | const std::size_t header_size = sizeof(MifareCommandData); | ||
| 814 | std::vector<u8> serialized_data(header_size); | ||
| 815 | std::size_t start_index = 0; | ||
| 816 | |||
| 817 | memcpy(serialized_data.data(), &package, header_size); | ||
| 818 | start_index += header_size; | ||
| 819 | |||
| 820 | for (const auto& data_chunk : package.data_chunks) { | ||
| 821 | const std::size_t chunk_size = sizeof(MifareWriteChunk); | ||
| 822 | if (data_chunk.command == MifareCmd::None) { | ||
| 823 | continue; | ||
| 824 | } | ||
| 825 | serialized_data.resize(start_index + chunk_size); | ||
| 826 | memcpy(serialized_data.data() + start_index, &data_chunk, chunk_size); | ||
| 827 | start_index += chunk_size; | ||
| 828 | } | ||
| 829 | |||
| 830 | return serialized_data; | ||
| 831 | } | ||
| 832 | |||
| 501 | NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, | 833 | NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, |
| 502 | std::span<const u8> data) const { | 834 | std::span<const u8> data) const { |
| 503 | return { | 835 | return { |
| @@ -527,6 +859,46 @@ NFCWritePackage NfcProtocol::MakeAmiiboWritePackage(const TagUUID& tag_uuid, | |||
| 527 | }; | 859 | }; |
| 528 | } | 860 | } |
| 529 | 861 | ||
| 862 | MifareReadPackage NfcProtocol::MakeMifareReadPackage( | ||
| 863 | const MifareUUID& tag_uuid, std::span<const MifareReadChunk> read_request) const { | ||
| 864 | MifareReadPackage package{ | ||
| 865 | .command_data{ | ||
| 866 | .unknown1 = 0xd0, | ||
| 867 | .unknown2 = 0x07, | ||
| 868 | .number_of_short_bytes = static_cast<u8>( | ||
| 869 | ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID)) / 2), | ||
| 870 | .uid = tag_uuid, | ||
| 871 | }, | ||
| 872 | .data_chunks = {}, | ||
| 873 | }; | ||
| 874 | |||
| 875 | for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) { | ||
| 876 | package.data_chunks[i] = read_request[i]; | ||
| 877 | } | ||
| 878 | |||
| 879 | return package; | ||
| 880 | } | ||
| 881 | |||
| 882 | MifareWritePackage NfcProtocol::MakeMifareWritePackage( | ||
| 883 | const MifareUUID& tag_uuid, std::span<const MifareWriteChunk> read_request) const { | ||
| 884 | MifareWritePackage package{ | ||
| 885 | .command_data{ | ||
| 886 | .unknown1 = 0xd0, | ||
| 887 | .unknown2 = 0x07, | ||
| 888 | .number_of_short_bytes = static_cast<u8>( | ||
| 889 | ((read_request.size() * sizeof(MifareReadChunk)) + sizeof(MifareUUID) + 2) / 2), | ||
| 890 | .uid = tag_uuid, | ||
| 891 | }, | ||
| 892 | .data_chunks = {}, | ||
| 893 | }; | ||
| 894 | |||
| 895 | for (std::size_t i = 0; i < read_request.size() && i < package.data_chunks.size(); ++i) { | ||
| 896 | package.data_chunks[i] = read_request[i]; | ||
| 897 | } | ||
| 898 | |||
| 899 | return package; | ||
| 900 | } | ||
| 901 | |||
| 530 | NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const { | 902 | NFCDataChunk NfcProtocol::MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const { |
| 531 | constexpr u8 NFC_PAGE_SIZE = 4; | 903 | constexpr u8 NFC_PAGE_SIZE = 4; |
| 532 | 904 | ||
| @@ -606,4 +978,8 @@ bool NfcProtocol::IsEnabled() const { | |||
| 606 | return is_enabled; | 978 | return is_enabled; |
| 607 | } | 979 | } |
| 608 | 980 | ||
| 981 | bool NfcProtocol::IsPolling() const { | ||
| 982 | return is_polling; | ||
| 983 | } | ||
| 984 | |||
| 609 | } // namespace InputCommon::Joycon | 985 | } // namespace InputCommon::Joycon |
diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h index eb58c427d..0be95e40e 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.h +++ b/src/input_common/helpers/joycon_protocol/nfc.h | |||
| @@ -25,14 +25,25 @@ public: | |||
| 25 | 25 | ||
| 26 | DriverResult StartNFCPollingMode(); | 26 | DriverResult StartNFCPollingMode(); |
| 27 | 27 | ||
| 28 | DriverResult ScanAmiibo(std::vector<u8>& data); | 28 | DriverResult StopNFCPollingMode(); |
| 29 | |||
| 30 | DriverResult GetTagInfo(Joycon::TagInfo& tag_info); | ||
| 31 | |||
| 32 | DriverResult ReadAmiibo(std::vector<u8>& data); | ||
| 29 | 33 | ||
| 30 | DriverResult WriteAmiibo(std::span<const u8> data); | 34 | DriverResult WriteAmiibo(std::span<const u8> data); |
| 31 | 35 | ||
| 36 | DriverResult ReadMifare(std::span<const MifareReadChunk> read_request, | ||
| 37 | std::span<MifareReadData> out_data); | ||
| 38 | |||
| 39 | DriverResult WriteMifare(std::span<const MifareWriteChunk> write_request); | ||
| 40 | |||
| 32 | bool HasAmiibo(); | 41 | bool HasAmiibo(); |
| 33 | 42 | ||
| 34 | bool IsEnabled() const; | 43 | bool IsEnabled() const; |
| 35 | 44 | ||
| 45 | bool IsPolling() const; | ||
| 46 | |||
| 36 | private: | 47 | private: |
| 37 | // Number of times the function will be delayed until it outputs valid data | 48 | // Number of times the function will be delayed until it outputs valid data |
| 38 | static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15; | 49 | static constexpr std::size_t AMIIBO_UPDATE_DELAY = 15; |
| @@ -51,6 +62,13 @@ private: | |||
| 51 | 62 | ||
| 52 | DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data); | 63 | DriverResult WriteAmiiboData(const TagUUID& tag_uuid, std::span<const u8> data); |
| 53 | 64 | ||
| 65 | DriverResult GetMifareData(const MifareUUID& tag_uuid, | ||
| 66 | std::span<const MifareReadChunk> read_request, | ||
| 67 | std::span<MifareReadData> out_data); | ||
| 68 | |||
| 69 | DriverResult WriteMifareData(const MifareUUID& tag_uuid, | ||
| 70 | std::span<const MifareWriteChunk> write_request); | ||
| 71 | |||
| 54 | DriverResult SendStartPollingRequest(MCUCommandResponse& output, | 72 | DriverResult SendStartPollingRequest(MCUCommandResponse& output, |
| 55 | bool is_second_attempt = false); | 73 | bool is_second_attempt = false); |
| 56 | 74 | ||
| @@ -65,17 +83,31 @@ private: | |||
| 65 | DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, | 83 | DriverResult SendWriteDataAmiiboRequest(MCUCommandResponse& output, u8 block_id, |
| 66 | bool is_last_packet, std::span<const u8> data); | 84 | bool is_last_packet, std::span<const u8> data); |
| 67 | 85 | ||
| 86 | DriverResult SendReadDataMifareRequest(MCUCommandResponse& output, u8 block_id, | ||
| 87 | bool is_last_packet, std::span<const u8> data); | ||
| 88 | |||
| 68 | std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const; | 89 | std::vector<u8> SerializeWritePackage(const NFCWritePackage& package) const; |
| 69 | 90 | ||
| 91 | std::vector<u8> SerializeMifareReadPackage(const MifareReadPackage& package) const; | ||
| 92 | |||
| 93 | std::vector<u8> SerializeMifareWritePackage(const MifareWritePackage& package) const; | ||
| 94 | |||
| 70 | NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const; | 95 | NFCWritePackage MakeAmiiboWritePackage(const TagUUID& tag_uuid, std::span<const u8> data) const; |
| 71 | 96 | ||
| 72 | NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const; | 97 | NFCDataChunk MakeAmiiboChunk(u8 page, u8 size, std::span<const u8> data) const; |
| 73 | 98 | ||
| 99 | MifareReadPackage MakeMifareReadPackage(const MifareUUID& tag_uuid, | ||
| 100 | std::span<const MifareReadChunk> read_request) const; | ||
| 101 | |||
| 102 | MifareWritePackage MakeMifareWritePackage(const MifareUUID& tag_uuid, | ||
| 103 | std::span<const MifareWriteChunk> read_request) const; | ||
| 104 | |||
| 74 | NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; | 105 | NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; |
| 75 | 106 | ||
| 76 | TagUUID GetTagUUID(std::span<const u8> data) const; | 107 | TagUUID GetTagUUID(std::span<const u8> data) const; |
| 77 | 108 | ||
| 78 | bool is_enabled{}; | 109 | bool is_enabled{}; |
| 110 | bool is_polling{}; | ||
| 79 | std::size_t update_counter{}; | 111 | std::size_t update_counter{}; |
| 80 | }; | 112 | }; |
| 81 | 113 | ||
diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp index dca797f7a..1aab9e12a 100644 --- a/src/input_common/helpers/joycon_protocol/poller.cpp +++ b/src/input_common/helpers/joycon_protocol/poller.cpp | |||
| @@ -70,8 +70,8 @@ void JoyconPoller::UpdateColor(const Color& color) { | |||
| 70 | callbacks.on_color_data(color); | 70 | callbacks.on_color_data(color); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | void JoyconPoller::UpdateAmiibo(const std::vector<u8>& amiibo_data) { | 73 | void JoyconPoller::UpdateAmiibo(const Joycon::TagInfo& tag_info) { |
| 74 | callbacks.on_amiibo_data(amiibo_data); | 74 | callbacks.on_amiibo_data(tag_info); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | void JoyconPoller::UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format) { | 77 | void JoyconPoller::UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format) { |
diff --git a/src/input_common/helpers/joycon_protocol/poller.h b/src/input_common/helpers/joycon_protocol/poller.h index 0fa72c6db..3746abe5d 100644 --- a/src/input_common/helpers/joycon_protocol/poller.h +++ b/src/input_common/helpers/joycon_protocol/poller.h | |||
| @@ -36,8 +36,8 @@ public: | |||
| 36 | 36 | ||
| 37 | void UpdateColor(const Color& color); | 37 | void UpdateColor(const Color& color); |
| 38 | void UpdateRing(s16 value, const RingStatus& ring_status); | 38 | void UpdateRing(s16 value, const RingStatus& ring_status); |
| 39 | void UpdateAmiibo(const std::vector<u8>& amiibo_data); | 39 | void UpdateAmiibo(const Joycon::TagInfo& tag_info); |
| 40 | void UpdateCamera(const std::vector<u8>& amiibo_data, IrsResolution format); | 40 | void UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format); |
| 41 | 41 | ||
| 42 | private: | 42 | private: |
| 43 | void UpdateActiveLeftPadInput(const InputReportActive& input, | 43 | void UpdateActiveLeftPadInput(const InputReportActive& input, |
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 50b5a3dc8..c2d0cbb34 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h | |||
| @@ -143,12 +143,46 @@ public: | |||
| 143 | return Common::Input::NfcState::NotSupported; | 143 | return Common::Input::NfcState::NotSupported; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | // Start scanning for nfc tags | ||
| 147 | virtual Common::Input::NfcState StartNfcPolling( | ||
| 148 | [[maybe_unused]] const PadIdentifier& identifier_) { | ||
| 149 | return Common::Input::NfcState::NotSupported; | ||
| 150 | } | ||
| 151 | |||
| 152 | // Start scanning for nfc tags | ||
| 153 | virtual Common::Input::NfcState StopNfcPolling( | ||
| 154 | [[maybe_unused]] const PadIdentifier& identifier_) { | ||
| 155 | return Common::Input::NfcState::NotSupported; | ||
| 156 | } | ||
| 157 | |||
| 158 | // Reads data from amiibo tag | ||
| 159 | virtual Common::Input::NfcState ReadAmiiboData( | ||
| 160 | [[maybe_unused]] const PadIdentifier& identifier_, | ||
| 161 | [[maybe_unused]] std::vector<u8>& out_data) { | ||
| 162 | return Common::Input::NfcState::NotSupported; | ||
| 163 | } | ||
| 164 | |||
| 146 | // Writes data to an nfc tag | 165 | // Writes data to an nfc tag |
| 147 | virtual Common::Input::NfcState WriteNfcData([[maybe_unused]] const PadIdentifier& identifier, | 166 | virtual Common::Input::NfcState WriteNfcData([[maybe_unused]] const PadIdentifier& identifier, |
| 148 | [[maybe_unused]] const std::vector<u8>& data) { | 167 | [[maybe_unused]] const std::vector<u8>& data) { |
| 149 | return Common::Input::NfcState::NotSupported; | 168 | return Common::Input::NfcState::NotSupported; |
| 150 | } | 169 | } |
| 151 | 170 | ||
| 171 | // Reads data from mifare tag | ||
| 172 | virtual Common::Input::NfcState ReadMifareData( | ||
| 173 | [[maybe_unused]] const PadIdentifier& identifier_, | ||
| 174 | [[maybe_unused]] const Common::Input::MifareRequest& request, | ||
| 175 | [[maybe_unused]] Common::Input::MifareRequest& out_data) { | ||
| 176 | return Common::Input::NfcState::NotSupported; | ||
| 177 | } | ||
| 178 | |||
| 179 | // Write data to mifare tag | ||
| 180 | virtual Common::Input::NfcState WriteMifareData( | ||
| 181 | [[maybe_unused]] const PadIdentifier& identifier_, | ||
| 182 | [[maybe_unused]] const Common::Input::MifareRequest& request) { | ||
| 183 | return Common::Input::NfcState::NotSupported; | ||
| 184 | } | ||
| 185 | |||
| 152 | // Returns the engine name | 186 | // Returns the engine name |
| 153 | [[nodiscard]] const std::string& GetEngineName() const; | 187 | [[nodiscard]] const std::string& GetEngineName() const; |
| 154 | 188 | ||
diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 380a01542..870e76ab0 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp | |||
| @@ -792,8 +792,7 @@ public: | |||
| 792 | 792 | ||
| 793 | const Common::Input::CallbackStatus status{ | 793 | const Common::Input::CallbackStatus status{ |
| 794 | .type = Common::Input::InputType::Nfc, | 794 | .type = Common::Input::InputType::Nfc, |
| 795 | .nfc_status = nfc_status.state, | 795 | .nfc_status = nfc_status, |
| 796 | .raw_data = nfc_status.data, | ||
| 797 | }; | 796 | }; |
| 798 | 797 | ||
| 799 | TriggerOnChange(status); | 798 | TriggerOnChange(status); |
| @@ -836,10 +835,31 @@ public: | |||
| 836 | return input_engine->SupportsNfc(identifier); | 835 | return input_engine->SupportsNfc(identifier); |
| 837 | } | 836 | } |
| 838 | 837 | ||
| 838 | Common::Input::NfcState StartNfcPolling() { | ||
| 839 | return input_engine->StartNfcPolling(identifier); | ||
| 840 | } | ||
| 841 | |||
| 842 | Common::Input::NfcState StopNfcPolling() { | ||
| 843 | return input_engine->StopNfcPolling(identifier); | ||
| 844 | } | ||
| 845 | |||
| 846 | Common::Input::NfcState ReadAmiiboData(std::vector<u8>& out_data) { | ||
| 847 | return input_engine->ReadAmiiboData(identifier, out_data); | ||
| 848 | } | ||
| 849 | |||
| 839 | Common::Input::NfcState WriteNfcData(const std::vector<u8>& data) override { | 850 | Common::Input::NfcState WriteNfcData(const std::vector<u8>& data) override { |
| 840 | return input_engine->WriteNfcData(identifier, data); | 851 | return input_engine->WriteNfcData(identifier, data); |
| 841 | } | 852 | } |
| 842 | 853 | ||
| 854 | Common::Input::NfcState ReadMifareData(const Common::Input::MifareRequest& request, | ||
| 855 | Common::Input::MifareRequest& out_data) { | ||
| 856 | return input_engine->ReadMifareData(identifier, request, out_data); | ||
| 857 | } | ||
| 858 | |||
| 859 | Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) { | ||
| 860 | return input_engine->WriteMifareData(identifier, request); | ||
| 861 | } | ||
| 862 | |||
| 843 | private: | 863 | private: |
| 844 | const PadIdentifier identifier; | 864 | const PadIdentifier identifier; |
| 845 | InputEngine* input_engine; | 865 | InputEngine* input_engine; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 013715b44..cba7c3cce 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -3836,7 +3836,7 @@ void GMainWindow::OnLoadAmiibo() { | |||
| 3836 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); | 3836 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); |
| 3837 | 3837 | ||
| 3838 | // Remove amiibo if one is connected | 3838 | // Remove amiibo if one is connected |
| 3839 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::AmiiboIsOpen) { | 3839 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::TagNearby) { |
| 3840 | virtual_amiibo->CloseAmiibo(); | 3840 | virtual_amiibo->CloseAmiibo(); |
| 3841 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); | 3841 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); |
| 3842 | return; | 3842 | return; |
| @@ -3864,7 +3864,7 @@ void GMainWindow::LoadAmiibo(const QString& filename) { | |||
| 3864 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); | 3864 | auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); |
| 3865 | const QString title = tr("Error loading Amiibo data"); | 3865 | const QString title = tr("Error loading Amiibo data"); |
| 3866 | // Remove amiibo if one is connected | 3866 | // Remove amiibo if one is connected |
| 3867 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::AmiiboIsOpen) { | 3867 | if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::TagNearby) { |
| 3868 | virtual_amiibo->CloseAmiibo(); | 3868 | virtual_amiibo->CloseAmiibo(); |
| 3869 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); | 3869 | QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed")); |
| 3870 | return; | 3870 | return; |