Merge pull request #10842 from german77/native_mifare
input_common: Implement native mifare/skylander support for joycons/pro controller
This commit is contained in:
commit
87b9b5d10f
25 changed files with 1170 additions and 198 deletions
|
@ -149,12 +149,16 @@ void EmulatedController::LoadDevices() {
|
|||
|
||||
camera_params[0] = right_joycon;
|
||||
camera_params[0].Set("camera", true);
|
||||
camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"};
|
||||
ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"};
|
||||
nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"};
|
||||
nfc_params[1] = right_joycon;
|
||||
nfc_params[1].Set("nfc", true);
|
||||
|
||||
// Only map virtual devices to the first controller
|
||||
if (npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld) {
|
||||
camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"};
|
||||
ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"};
|
||||
nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"};
|
||||
}
|
||||
|
||||
output_params[LeftIndex] = left_joycon;
|
||||
output_params[RightIndex] = right_joycon;
|
||||
output_params[2] = camera_params[1];
|
||||
|
@ -1176,10 +1180,7 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
|
|||
return;
|
||||
}
|
||||
|
||||
controller.nfc_state = {
|
||||
controller.nfc_values.state,
|
||||
controller.nfc_values.data,
|
||||
};
|
||||
controller.nfc_state = controller.nfc_values;
|
||||
}
|
||||
|
||||
bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) {
|
||||
|
@ -1308,6 +1309,73 @@ bool EmulatedController::HasNfc() const {
|
|||
return is_connected && (has_virtual_nfc && is_virtual_nfc_supported);
|
||||
}
|
||||
|
||||
bool EmulatedController::AddNfcHandle() {
|
||||
nfc_handles++;
|
||||
return SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::NFC) ==
|
||||
Common::Input::DriverResult::Success;
|
||||
}
|
||||
|
||||
bool EmulatedController::RemoveNfcHandle() {
|
||||
nfc_handles--;
|
||||
if (nfc_handles <= 0) {
|
||||
return SetPollingMode(EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::Active) ==
|
||||
Common::Input::DriverResult::Success;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmulatedController::StartNfcPolling() {
|
||||
auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
|
||||
auto& nfc_virtual_output_device = output_devices[3];
|
||||
|
||||
return nfc_output_device->StartNfcPolling() == Common::Input::NfcState::Success ||
|
||||
nfc_virtual_output_device->StartNfcPolling() == Common::Input::NfcState::Success;
|
||||
}
|
||||
|
||||
bool EmulatedController::StopNfcPolling() {
|
||||
auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
|
||||
auto& nfc_virtual_output_device = output_devices[3];
|
||||
|
||||
return nfc_output_device->StopNfcPolling() == Common::Input::NfcState::Success ||
|
||||
nfc_virtual_output_device->StopNfcPolling() == Common::Input::NfcState::Success;
|
||||
}
|
||||
|
||||
bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) {
|
||||
auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
|
||||
auto& nfc_virtual_output_device = output_devices[3];
|
||||
|
||||
if (nfc_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return nfc_virtual_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success;
|
||||
}
|
||||
|
||||
bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request,
|
||||
Common::Input::MifareRequest& out_data) {
|
||||
auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
|
||||
auto& nfc_virtual_output_device = output_devices[3];
|
||||
|
||||
if (nfc_output_device->ReadMifareData(request, out_data) == Common::Input::NfcState::Success) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return nfc_virtual_output_device->ReadMifareData(request, out_data) ==
|
||||
Common::Input::NfcState::Success;
|
||||
}
|
||||
|
||||
bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) {
|
||||
auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
|
||||
auto& nfc_virtual_output_device = output_devices[3];
|
||||
|
||||
if (nfc_output_device->WriteMifareData(request) == Common::Input::NfcState::Success) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return nfc_virtual_output_device->WriteMifareData(request) == Common::Input::NfcState::Success;
|
||||
}
|
||||
|
||||
bool EmulatedController::WriteNfc(const std::vector<u8>& data) {
|
||||
auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
|
||||
auto& nfc_virtual_output_device = output_devices[3];
|
||||
|
|
|
@ -97,10 +97,7 @@ struct RingSensorForce {
|
|||
f32 force;
|
||||
};
|
||||
|
||||
struct NfcState {
|
||||
Common::Input::NfcState state{};
|
||||
std::vector<u8> data{};
|
||||
};
|
||||
using NfcState = Common::Input::NfcStatus;
|
||||
|
||||
struct ControllerMotion {
|
||||
Common::Vec3f accel{};
|
||||
|
@ -393,9 +390,31 @@ public:
|
|||
/// Returns true if the device has nfc support
|
||||
bool HasNfc() const;
|
||||
|
||||
/// Sets the joycon in nfc mode and increments the handle count
|
||||
bool AddNfcHandle();
|
||||
|
||||
/// Decrements the handle count if zero sets the joycon in active mode
|
||||
bool RemoveNfcHandle();
|
||||
|
||||
/// Start searching for nfc tags
|
||||
bool StartNfcPolling();
|
||||
|
||||
/// Stop searching for nfc tags
|
||||
bool StopNfcPolling();
|
||||
|
||||
/// Returns true if the nfc tag was readable
|
||||
bool ReadAmiiboData(std::vector<u8>& data);
|
||||
|
||||
/// Returns true if the nfc tag was written
|
||||
bool WriteNfc(const std::vector<u8>& data);
|
||||
|
||||
/// Returns true if the nfc tag was readable
|
||||
bool ReadMifareData(const Common::Input::MifareRequest& request,
|
||||
Common::Input::MifareRequest& out_data);
|
||||
|
||||
/// Returns true if the nfc tag was written
|
||||
bool WriteMifareData(const Common::Input::MifareRequest& request);
|
||||
|
||||
/// Returns the led pattern corresponding to this emulated controller
|
||||
LedPattern GetLedPattern() const;
|
||||
|
||||
|
@ -532,6 +551,7 @@ private:
|
|||
bool system_buttons_enabled{true};
|
||||
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
|
||||
u32 turbo_button_state{0};
|
||||
std::size_t nfc_handles{0};
|
||||
|
||||
// Temporary values to avoid doing changes while the controller is in configuring mode
|
||||
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
|
||||
|
|
|
@ -299,11 +299,7 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal
|
|||
Common::Input::NfcStatus nfc{};
|
||||
switch (callback.type) {
|
||||
case Common::Input::InputType::Nfc:
|
||||
nfc = {
|
||||
.state = callback.nfc_status,
|
||||
.data = callback.raw_data,
|
||||
};
|
||||
break;
|
||||
return callback.nfc_status;
|
||||
default:
|
||||
LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type);
|
||||
break;
|
||||
|
|
|
@ -141,7 +141,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
|
|||
applet_output.device_handle = applet_input_common.device_handle;
|
||||
applet_output.result = CabinetResult::Cancel;
|
||||
const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info);
|
||||
const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info, false);
|
||||
const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info);
|
||||
nfp_device->Finalize();
|
||||
|
||||
if (reg_result.IsSuccess()) {
|
||||
|
|
|
@ -93,7 +93,8 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
|
|||
const auto nfc_status = npad_device->GetNfc();
|
||||
switch (nfc_status.state) {
|
||||
case Common::Input::NfcState::NewAmiibo:
|
||||
LoadNfcTag(nfc_status.data);
|
||||
LoadNfcTag(nfc_status.protocol, nfc_status.tag_type, nfc_status.uuid_length,
|
||||
nfc_status.uuid);
|
||||
break;
|
||||
case Common::Input::NfcState::AmiiboRemoved:
|
||||
if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
|
||||
|
@ -108,28 +109,46 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
|
|||
}
|
||||
}
|
||||
|
||||
bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
|
||||
bool NfcDevice::LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid) {
|
||||
if (device_state != DeviceState::SearchingForTag) {
|
||||
LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((protocol & static_cast<u8>(allowed_protocols)) == 0) {
|
||||
LOG_ERROR(Service_NFC, "Protocol not supported {}", protocol);
|
||||
return false;
|
||||
}
|
||||
|
||||
real_tag_info = {
|
||||
.uuid = uuid,
|
||||
.uuid_length = uuid_length,
|
||||
.protocol = static_cast<NfcProtocol>(protocol),
|
||||
.tag_type = static_cast<TagType>(tag_type),
|
||||
};
|
||||
|
||||
device_state = DeviceState::TagFound;
|
||||
deactivate_event->GetReadableEvent().Clear();
|
||||
activate_event->Signal();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NfcDevice::LoadAmiiboData() {
|
||||
std::vector<u8> data{};
|
||||
|
||||
if (!npad_device->ReadAmiiboData(data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
|
||||
LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
mifare_data.resize(data.size());
|
||||
memcpy(mifare_data.data(), data.data(), data.size());
|
||||
|
||||
memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
|
||||
is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data);
|
||||
is_write_protected = false;
|
||||
|
||||
device_state = DeviceState::TagFound;
|
||||
deactivate_event->GetReadableEvent().Clear();
|
||||
activate_event->Signal();
|
||||
|
||||
// Fallback for plain amiibos
|
||||
if (is_plain_amiibo) {
|
||||
LOG_INFO(Service_NFP, "Using plain amiibo");
|
||||
|
@ -147,6 +166,7 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
|
|||
return true;
|
||||
}
|
||||
|
||||
LOG_INFO(Service_NFP, "Using encrypted amiibo");
|
||||
tag_data = {};
|
||||
memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
|
||||
return true;
|
||||
|
@ -162,7 +182,6 @@ void NfcDevice::CloseNfcTag() {
|
|||
device_state = DeviceState::TagRemoved;
|
||||
encrypted_tag_data = {};
|
||||
tag_data = {};
|
||||
mifare_data = {};
|
||||
activate_event->GetReadableEvent().Clear();
|
||||
deactivate_event->Signal();
|
||||
}
|
||||
|
@ -179,8 +198,12 @@ void NfcDevice::Initialize() {
|
|||
device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable;
|
||||
encrypted_tag_data = {};
|
||||
tag_data = {};
|
||||
mifare_data = {};
|
||||
is_initalized = true;
|
||||
|
||||
if (device_state != DeviceState::Initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
is_initalized = npad_device->AddNfcHandle();
|
||||
}
|
||||
|
||||
void NfcDevice::Finalize() {
|
||||
|
@ -190,6 +213,11 @@ void NfcDevice::Finalize() {
|
|||
if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
|
||||
StopDetection();
|
||||
}
|
||||
|
||||
if (device_state != DeviceState::Unavailable) {
|
||||
npad_device->RemoveNfcHandle();
|
||||
}
|
||||
|
||||
device_state = DeviceState::Unavailable;
|
||||
is_initalized = false;
|
||||
}
|
||||
|
@ -200,10 +228,8 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
|
|||
return ResultWrongDeviceState;
|
||||
}
|
||||
|
||||
if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::NFC) !=
|
||||
Common::Input::DriverResult::Success) {
|
||||
LOG_ERROR(Service_NFC, "Nfc not supported");
|
||||
if (!npad_device->StartNfcPolling()) {
|
||||
LOG_ERROR(Service_NFC, "Nfc polling not supported");
|
||||
return ResultNfcDisabled;
|
||||
}
|
||||
|
||||
|
@ -213,9 +239,6 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
|
|||
}
|
||||
|
||||
Result NfcDevice::StopDetection() {
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::Active);
|
||||
|
||||
if (device_state == DeviceState::Initialized) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
@ -225,6 +248,7 @@ Result NfcDevice::StopDetection() {
|
|||
}
|
||||
|
||||
if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
|
||||
npad_device->StopNfcPolling();
|
||||
device_state = DeviceState::Initialized;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
@ -233,7 +257,7 @@ Result NfcDevice::StopDetection() {
|
|||
return ResultWrongDeviceState;
|
||||
}
|
||||
|
||||
Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
|
||||
Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {
|
||||
if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
if (device_state == DeviceState::TagRemoved) {
|
||||
|
@ -242,41 +266,15 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
|
|||
return ResultWrongDeviceState;
|
||||
}
|
||||
|
||||
UniqueSerialNumber uuid{};
|
||||
u8 uuid_length{};
|
||||
NfcProtocol protocol{NfcProtocol::TypeA};
|
||||
TagType tag_type{TagType::Type2};
|
||||
tag_info = real_tag_info;
|
||||
|
||||
if (is_mifare) {
|
||||
tag_type = TagType::Mifare;
|
||||
uuid_length = sizeof(NFP::NtagTagUuid);
|
||||
memcpy(uuid.data(), mifare_data.data(), uuid_length);
|
||||
} else {
|
||||
tag_type = TagType::Type2;
|
||||
uuid_length = sizeof(NFP::NtagTagUuid);
|
||||
NFP::NtagTagUuid nUuid{
|
||||
.part1 = encrypted_tag_data.uuid.part1,
|
||||
.part2 = encrypted_tag_data.uuid.part2,
|
||||
.nintendo_id = encrypted_tag_data.uuid.nintendo_id,
|
||||
};
|
||||
memcpy(uuid.data(), &nUuid, uuid_length);
|
||||
|
||||
// Generate random UUID to bypass amiibo load limits
|
||||
if (Settings::values.random_amiibo_id) {
|
||||
Common::TinyMT rng{};
|
||||
rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
|
||||
rng.GenerateRandomBytes(uuid.data(), uuid_length);
|
||||
}
|
||||
// Generate random UUID to bypass amiibo load limits
|
||||
if (real_tag_info.tag_type == TagType::Type2 && Settings::values.random_amiibo_id) {
|
||||
Common::TinyMT rng{};
|
||||
rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
|
||||
rng.GenerateRandomBytes(tag_info.uuid.data(), tag_info.uuid_length);
|
||||
}
|
||||
|
||||
// Protocol and tag type may change here
|
||||
tag_info = {
|
||||
.uuid = uuid,
|
||||
.uuid_length = uuid_length,
|
||||
.protocol = protocol,
|
||||
.tag_type = tag_type,
|
||||
};
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
|
@ -293,7 +291,7 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter
|
|||
Result result = ResultSuccess;
|
||||
|
||||
TagInfo tag_info{};
|
||||
result = GetTagInfo(tag_info, true);
|
||||
result = GetTagInfo(tag_info);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
|
@ -307,6 +305,8 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter
|
|||
return ResultInvalidArgument;
|
||||
}
|
||||
|
||||
Common::Input::MifareRequest request{};
|
||||
Common::Input::MifareRequest out_data{};
|
||||
const auto unknown = parameters[0].sector_key.unknown;
|
||||
for (std::size_t i = 0; i < parameters.size(); i++) {
|
||||
if (unknown != parameters[i].sector_key.unknown) {
|
||||
|
@ -315,25 +315,29 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter
|
|||
}
|
||||
|
||||
for (std::size_t i = 0; i < parameters.size(); i++) {
|
||||
result = ReadMifare(parameters[i], read_block_data[i]);
|
||||
if (result.IsError()) {
|
||||
break;
|
||||
if (parameters[i].sector_key.command == MifareCmd::None) {
|
||||
continue;
|
||||
}
|
||||
request.data[i].command = static_cast<u8>(parameters[i].sector_key.command);
|
||||
request.data[i].sector = parameters[i].sector_number;
|
||||
memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(),
|
||||
sizeof(KeyData));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
|
||||
MifareReadBlockData& read_block_data) const {
|
||||
const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
|
||||
read_block_data.sector_number = parameter.sector_number;
|
||||
if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
|
||||
if (!npad_device->ReadMifareData(request, out_data)) {
|
||||
return ResultMifareError288;
|
||||
}
|
||||
|
||||
// TODO: Use parameter.sector_key to read encrypted data
|
||||
memcpy(read_block_data.data.data(), mifare_data.data() + sector_index, sizeof(DataBlock));
|
||||
for (std::size_t i = 0; i < read_block_data.size(); i++) {
|
||||
if (static_cast<MifareCmd>(out_data.data[i].command) == MifareCmd::None) {
|
||||
continue;
|
||||
}
|
||||
|
||||
read_block_data[i] = {
|
||||
.data = out_data.data[i].data,
|
||||
.sector_number = out_data.data[i].sector,
|
||||
};
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
@ -342,7 +346,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
|
|||
Result result = ResultSuccess;
|
||||
|
||||
TagInfo tag_info{};
|
||||
result = GetTagInfo(tag_info, true);
|
||||
result = GetTagInfo(tag_info);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
|
@ -363,42 +367,25 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
|
|||
}
|
||||
}
|
||||
|
||||
Common::Input::MifareRequest request{};
|
||||
for (std::size_t i = 0; i < parameters.size(); i++) {
|
||||
result = WriteMifare(parameters[i]);
|
||||
if (result.IsError()) {
|
||||
break;
|
||||
if (parameters[i].sector_key.command == MifareCmd::None) {
|
||||
continue;
|
||||
}
|
||||
request.data[i].command = static_cast<u8>(parameters[i].sector_key.command);
|
||||
request.data[i].sector = parameters[i].sector_number;
|
||||
memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(),
|
||||
sizeof(KeyData));
|
||||
memcpy(request.data[i].data.data(), parameters[i].data.data(), sizeof(KeyData));
|
||||
}
|
||||
|
||||
if (!npad_device->WriteNfc(mifare_data)) {
|
||||
LOG_ERROR(Service_NFP, "Error writing to file");
|
||||
if (!npad_device->WriteMifareData(request)) {
|
||||
return ResultMifareError288;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) {
|
||||
const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
|
||||
|
||||
if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
|
||||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
|
||||
if (device_state == DeviceState::TagRemoved) {
|
||||
return ResultTagRemoved;
|
||||
}
|
||||
return ResultWrongDeviceState;
|
||||
}
|
||||
|
||||
if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
|
||||
return ResultMifareError288;
|
||||
}
|
||||
|
||||
// TODO: Use parameter.sector_key to encrypt the data
|
||||
memcpy(mifare_data.data() + sector_index, parameter.data.data(), sizeof(DataBlock));
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
|
||||
std::span<const u8> command_data,
|
||||
std::span<u8> out_data) {
|
||||
|
@ -412,6 +399,11 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
|
|||
return ResultWrongDeviceState;
|
||||
}
|
||||
|
||||
if (!LoadAmiiboData()) {
|
||||
LOG_ERROR(Service_NFP, "Not an amiibo");
|
||||
return ResultInvalidTagType;
|
||||
}
|
||||
|
||||
if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
|
||||
LOG_ERROR(Service_NFP, "Not an amiibo");
|
||||
return ResultInvalidTagType;
|
||||
|
@ -562,7 +554,7 @@ Result NfcDevice::Restore() {
|
|||
|
||||
NFC::TagInfo tag_info{};
|
||||
std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{};
|
||||
Result result = GetTagInfo(tag_info, false);
|
||||
Result result = GetTagInfo(tag_info);
|
||||
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
|
@ -635,7 +627,7 @@ Result NfcDevice::GetCommonInfo(NFP::CommonInfo& common_info) const {
|
|||
// TODO: Validate this data
|
||||
common_info = {
|
||||
.last_write_date = settings.write_date.GetWriteDate(),
|
||||
.write_counter = tag_data.write_counter,
|
||||
.write_counter = tag_data.application_write_counter,
|
||||
.version = tag_data.amiibo_version,
|
||||
.application_area_size = sizeof(NFP::ApplicationArea),
|
||||
};
|
||||
|
|
|
@ -42,15 +42,12 @@ public:
|
|||
Result StartDetection(NfcProtocol allowed_protocol);
|
||||
Result StopDetection();
|
||||
|
||||
Result GetTagInfo(TagInfo& tag_info, bool is_mifare) const;
|
||||
Result GetTagInfo(TagInfo& tag_info) const;
|
||||
|
||||
Result ReadMifare(std::span<const MifareReadBlockParameter> parameters,
|
||||
std::span<MifareReadBlockData> read_block_data) const;
|
||||
Result ReadMifare(const MifareReadBlockParameter& parameter,
|
||||
MifareReadBlockData& read_block_data) const;
|
||||
|
||||
Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
|
||||
Result WriteMifare(const MifareWriteBlockParameter& parameter);
|
||||
|
||||
Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
|
||||
std::span<const u8> command_data, std::span<u8> out_data);
|
||||
|
@ -105,7 +102,8 @@ public:
|
|||
|
||||
private:
|
||||
void NpadUpdate(Core::HID::ControllerTriggerType type);
|
||||
bool LoadNfcTag(std::span<const u8> data);
|
||||
bool LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid);
|
||||
bool LoadAmiiboData();
|
||||
void CloseNfcTag();
|
||||
|
||||
NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
|
||||
|
@ -140,8 +138,8 @@ private:
|
|||
bool is_write_protected{};
|
||||
NFP::MountTarget mount_target{NFP::MountTarget::None};
|
||||
|
||||
TagInfo real_tag_info{};
|
||||
NFP::NTAG215File tag_data{};
|
||||
std::vector<u8> mifare_data{};
|
||||
NFP::EncryptedNTAG215File encrypted_tag_data{};
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@ DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContex
|
|||
}
|
||||
|
||||
DeviceManager ::~DeviceManager() {
|
||||
if (is_initialized) {
|
||||
Finalize();
|
||||
}
|
||||
service_context.CloseEvent(availability_change_event);
|
||||
}
|
||||
|
||||
|
@ -125,14 +128,14 @@ Result DeviceManager::StopDetection(u64 device_handle) {
|
|||
return result;
|
||||
}
|
||||
|
||||
Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const {
|
||||
Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
std::shared_ptr<NfcDevice> device = nullptr;
|
||||
auto result = GetDeviceHandle(device_handle, device);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetTagInfo(tag_info, is_mifare);
|
||||
result = device->GetTagInfo(tag_info);
|
||||
result = VerifyDeviceResult(device, result);
|
||||
}
|
||||
|
||||
|
@ -546,7 +549,7 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) cons
|
|||
NFC::TagInfo tag_info{};
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetTagInfo(tag_info, false);
|
||||
result = device->GetTagInfo(tag_info);
|
||||
}
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
|
@ -565,7 +568,7 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> dat
|
|||
NFC::TagInfo tag_info{};
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
result = device->GetTagInfo(tag_info, false);
|
||||
result = device->GetTagInfo(tag_info);
|
||||
}
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const;
|
||||
Result StartDetection(u64 device_handle, NfcProtocol tag_protocol);
|
||||
Result StopDetection(u64 device_handle);
|
||||
Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info, bool is_mifare) const;
|
||||
Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info) const;
|
||||
Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const;
|
||||
Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const;
|
||||
Result ReadMifare(u64 device_handle,
|
||||
|
|
|
@ -11,9 +11,10 @@
|
|||
namespace Service::NFC {
|
||||
|
||||
enum class MifareCmd : u8 {
|
||||
None = 0x00,
|
||||
Read = 0x30,
|
||||
AuthA = 0x60,
|
||||
AuthB = 0x61,
|
||||
Read = 0x30,
|
||||
Write = 0xA0,
|
||||
Transfer = 0xB0,
|
||||
Decrement = 0xC0,
|
||||
|
@ -35,17 +36,17 @@ static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
|
|||
|
||||
// This is nn::nfc::MifareReadBlockParameter
|
||||
struct MifareReadBlockParameter {
|
||||
u8 sector_number;
|
||||
u8 sector_number{};
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
SectorKey sector_key;
|
||||
SectorKey sector_key{};
|
||||
};
|
||||
static_assert(sizeof(MifareReadBlockParameter) == 0x18,
|
||||
"MifareReadBlockParameter is an invalid size");
|
||||
|
||||
// This is nn::nfc::MifareReadBlockData
|
||||
struct MifareReadBlockData {
|
||||
DataBlock data;
|
||||
u8 sector_number;
|
||||
DataBlock data{};
|
||||
u8 sector_number{};
|
||||
INSERT_PADDING_BYTES(0x7);
|
||||
};
|
||||
static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
|
||||
|
|
|
@ -174,8 +174,7 @@ void NfcInterface::GetTagInfo(HLERequestContext& ctx) {
|
|||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||
|
||||
TagInfo tag_info{};
|
||||
auto result =
|
||||
GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare);
|
||||
auto result = GetManager()->GetTagInfo(device_handle, tag_info);
|
||||
result = TranslateResultToServiceError(result);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
|
@ -216,8 +215,8 @@ void NfcInterface::ReadMifare(HLERequestContext& ctx) {
|
|||
memcpy(read_commands.data(), buffer.data(),
|
||||
number_of_commands * sizeof(MifareReadBlockParameter));
|
||||
|
||||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
|
||||
device_handle, number_of_commands);
|
||||
LOG_INFO(Service_NFC, "called, device_handle={}, read_commands_size={}", device_handle,
|
||||
number_of_commands);
|
||||
|
||||
std::vector<MifareReadBlockData> out_data(number_of_commands);
|
||||
auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue