diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/nfp/nfp.cpp | 115 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp.h | 71 |
2 files changed, 145 insertions, 41 deletions
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 7f1fb3a71..1e91aa340 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -108,7 +108,7 @@ void IUser::StartDetection(Kernel::HLERequestContext& ctx) { | |||
| 108 | 108 | ||
| 109 | // TODO(german77): Loop through all interfaces | 109 | // TODO(german77): Loop through all interfaces |
| 110 | if (device_handle == nfp_interface.GetHandle()) { | 110 | if (device_handle == nfp_interface.GetHandle()) { |
| 111 | const auto result = nfp_interface.StartDetection(); | 111 | const auto result = nfp_interface.StartDetection(nfp_protocol); |
| 112 | IPC::ResponseBuilder rb{ctx, 2}; | 112 | IPC::ResponseBuilder rb{ctx, 2}; |
| 113 | rb.Push(result); | 113 | rb.Push(result); |
| 114 | return; | 114 | return; |
| @@ -209,7 +209,6 @@ void IUser::GetApplicationArea(Kernel::HLERequestContext& ctx) { | |||
| 209 | if (device_handle == nfp_interface.GetHandle()) { | 209 | if (device_handle == nfp_interface.GetHandle()) { |
| 210 | std::vector<u8> data{}; | 210 | std::vector<u8> data{}; |
| 211 | const auto result = nfp_interface.GetApplicationArea(data); | 211 | const auto result = nfp_interface.GetApplicationArea(data); |
| 212 | |||
| 213 | ctx.WriteBuffer(data); | 212 | ctx.WriteBuffer(data); |
| 214 | IPC::ResponseBuilder rb{ctx, 3}; | 213 | IPC::ResponseBuilder rb{ctx, 3}; |
| 215 | rb.Push(result); | 214 | rb.Push(result); |
| @@ -232,7 +231,6 @@ void IUser::SetApplicationArea(Kernel::HLERequestContext& ctx) { | |||
| 232 | // TODO(german77): Loop through all interfaces | 231 | // TODO(german77): Loop through all interfaces |
| 233 | if (device_handle == nfp_interface.GetHandle()) { | 232 | if (device_handle == nfp_interface.GetHandle()) { |
| 234 | const auto result = nfp_interface.SetApplicationArea(data); | 233 | const auto result = nfp_interface.SetApplicationArea(data); |
| 235 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 2}; | 234 | IPC::ResponseBuilder rb{ctx, 2}; |
| 237 | rb.Push(result); | 235 | rb.Push(result); |
| 238 | return; | 236 | return; |
| @@ -255,7 +253,6 @@ void IUser::CreateApplicationArea(Kernel::HLERequestContext& ctx) { | |||
| 255 | // TODO(german77): Loop through all interfaces | 253 | // TODO(german77): Loop through all interfaces |
| 256 | if (device_handle == nfp_interface.GetHandle()) { | 254 | if (device_handle == nfp_interface.GetHandle()) { |
| 257 | const auto result = nfp_interface.CreateApplicationArea(access_id, data); | 255 | const auto result = nfp_interface.CreateApplicationArea(access_id, data); |
| 258 | |||
| 259 | IPC::ResponseBuilder rb{ctx, 2}; | 256 | IPC::ResponseBuilder rb{ctx, 2}; |
| 260 | rb.Push(result); | 257 | rb.Push(result); |
| 261 | return; | 258 | return; |
| @@ -390,7 +387,7 @@ void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { | |||
| 390 | } | 387 | } |
| 391 | 388 | ||
| 392 | void IUser::GetState(Kernel::HLERequestContext& ctx) { | 389 | void IUser::GetState(Kernel::HLERequestContext& ctx) { |
| 393 | LOG_INFO(Service_NFC, "called"); | 390 | LOG_DEBUG(Service_NFC, "called"); |
| 394 | 391 | ||
| 395 | IPC::ResponseBuilder rb{ctx, 3, 0}; | 392 | IPC::ResponseBuilder rb{ctx, 3, 0}; |
| 396 | rb.Push(ResultSuccess); | 393 | rb.Push(ResultSuccess); |
| @@ -400,7 +397,7 @@ void IUser::GetState(Kernel::HLERequestContext& ctx) { | |||
| 400 | void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) { | 397 | void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) { |
| 401 | IPC::RequestParser rp{ctx}; | 398 | IPC::RequestParser rp{ctx}; |
| 402 | const auto device_handle{rp.Pop<u64>()}; | 399 | const auto device_handle{rp.Pop<u64>()}; |
| 403 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | 400 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); |
| 404 | 401 | ||
| 405 | // TODO(german77): Loop through all interfaces | 402 | // TODO(german77): Loop through all interfaces |
| 406 | if (device_handle == nfp_interface.GetHandle()) { | 403 | if (device_handle == nfp_interface.GetHandle()) { |
| @@ -419,7 +416,7 @@ void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) { | |||
| 419 | void IUser::GetNpadId(Kernel::HLERequestContext& ctx) { | 416 | void IUser::GetNpadId(Kernel::HLERequestContext& ctx) { |
| 420 | IPC::RequestParser rp{ctx}; | 417 | IPC::RequestParser rp{ctx}; |
| 421 | const auto device_handle{rp.Pop<u64>()}; | 418 | const auto device_handle{rp.Pop<u64>()}; |
| 422 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | 419 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); |
| 423 | 420 | ||
| 424 | // TODO(german77): Loop through all interfaces | 421 | // TODO(german77): Loop through all interfaces |
| 425 | if (device_handle == nfp_interface.GetHandle()) { | 422 | if (device_handle == nfp_interface.GetHandle()) { |
| @@ -438,7 +435,7 @@ void IUser::GetNpadId(Kernel::HLERequestContext& ctx) { | |||
| 438 | void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) { | 435 | void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) { |
| 439 | IPC::RequestParser rp{ctx}; | 436 | IPC::RequestParser rp{ctx}; |
| 440 | const auto device_handle{rp.Pop<u64>()}; | 437 | const auto device_handle{rp.Pop<u64>()}; |
| 441 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | 438 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); |
| 442 | 439 | ||
| 443 | // TODO(german77): Loop through all interfaces | 440 | // TODO(german77): Loop through all interfaces |
| 444 | if (device_handle == nfp_interface.GetHandle()) { | 441 | if (device_handle == nfp_interface.GetHandle()) { |
| @@ -493,6 +490,11 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | |||
| 493 | 490 | ||
| 494 | LOG_INFO(Service_NFP, "New Amiibo detected"); | 491 | LOG_INFO(Service_NFP, "New Amiibo detected"); |
| 495 | std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); | 492 | std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); |
| 493 | |||
| 494 | if (!IsAmiiboValid()) { | ||
| 495 | return false; | ||
| 496 | } | ||
| 497 | |||
| 496 | device_state = DeviceState::TagFound; | 498 | device_state = DeviceState::TagFound; |
| 497 | activate_event->GetWritableEvent().Signal(); | 499 | activate_event->GetWritableEvent().Signal(); |
| 498 | return true; | 500 | return true; |
| @@ -501,13 +503,54 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | |||
| 501 | void Module::Interface::CloseAmiibo() { | 503 | void Module::Interface::CloseAmiibo() { |
| 502 | LOG_INFO(Service_NFP, "Remove amiibo"); | 504 | LOG_INFO(Service_NFP, "Remove amiibo"); |
| 503 | device_state = DeviceState::TagRemoved; | 505 | device_state = DeviceState::TagRemoved; |
| 504 | write_counter = 0; | ||
| 505 | is_application_area_initialized = false; | 506 | is_application_area_initialized = false; |
| 506 | application_area_id = 0; | 507 | application_area_id = 0; |
| 507 | application_area_data.clear(); | 508 | application_area_data.clear(); |
| 508 | deactivate_event->GetWritableEvent().Signal(); | 509 | deactivate_event->GetWritableEvent().Signal(); |
| 509 | } | 510 | } |
| 510 | 511 | ||
| 512 | bool Module::Interface::IsAmiiboValid() const { | ||
| 513 | LOG_INFO(Service_NFP, "uuid_lock=0x{0:x}", amiibo.uuid_lock); | ||
| 514 | LOG_INFO(Service_NFP, "compability_container=0x{0:x}", amiibo.compability_container); | ||
| 515 | LOG_INFO(Service_NFP, "crypto_init=0x{0:x}", amiibo.crypto_init); | ||
| 516 | LOG_INFO(Service_NFP, "write_count={}", amiibo.write_count); | ||
| 517 | |||
| 518 | LOG_INFO(Service_NFP, "character_id=0x{0:x}", amiibo.model_info.character_id); | ||
| 519 | LOG_INFO(Service_NFP, "character_variant={}", amiibo.model_info.character_variant); | ||
| 520 | LOG_INFO(Service_NFP, "amiibo_type={}", amiibo.model_info.amiibo_type); | ||
| 521 | LOG_INFO(Service_NFP, "model_number=0x{0:x}", amiibo.model_info.model_number); | ||
| 522 | LOG_INFO(Service_NFP, "series={}", amiibo.model_info.series); | ||
| 523 | LOG_INFO(Service_NFP, "fixed_value=0x{0:x}", amiibo.model_info.fixed); | ||
| 524 | |||
| 525 | LOG_INFO(Service_NFP, "tag_dynamic_lock=0x{0:x}", amiibo.tag_dynamic_lock); | ||
| 526 | LOG_INFO(Service_NFP, "tag_CFG0=0x{0:x}", amiibo.tag_CFG0); | ||
| 527 | LOG_INFO(Service_NFP, "tag_CFG1=0x{0:x}", amiibo.tag_CFG1); | ||
| 528 | |||
| 529 | // Check against all know constants on an amiibo binary | ||
| 530 | if (amiibo.uuid_lock != 0xE00F) { | ||
| 531 | return false; | ||
| 532 | } | ||
| 533 | if (amiibo.compability_container != 0xEEFF10F1UL) { | ||
| 534 | return false; | ||
| 535 | } | ||
| 536 | if ((amiibo.crypto_init & 0xFF) != 0xA5) { | ||
| 537 | return false; | ||
| 538 | } | ||
| 539 | if (amiibo.model_info.fixed != 0x02) { | ||
| 540 | return false; | ||
| 541 | } | ||
| 542 | if ((amiibo.tag_dynamic_lock & 0xFFFFFF) != 0x0F0001) { | ||
| 543 | return false; | ||
| 544 | } | ||
| 545 | if (amiibo.tag_CFG0 != 0x04000000UL) { | ||
| 546 | return false; | ||
| 547 | } | ||
| 548 | if (amiibo.tag_CFG1 != 0x5F) { | ||
| 549 | return false; | ||
| 550 | } | ||
| 551 | return true; | ||
| 552 | } | ||
| 553 | |||
| 511 | Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const { | 554 | Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const { |
| 512 | return activate_event->GetReadableEvent(); | 555 | return activate_event->GetReadableEvent(); |
| 513 | } | 556 | } |
| @@ -522,13 +565,12 @@ void Module::Interface::Initialize() { | |||
| 522 | 565 | ||
| 523 | void Module::Interface::Finalize() { | 566 | void Module::Interface::Finalize() { |
| 524 | device_state = DeviceState::Unaviable; | 567 | device_state = DeviceState::Unaviable; |
| 525 | write_counter = 0; | ||
| 526 | is_application_area_initialized = false; | 568 | is_application_area_initialized = false; |
| 527 | application_area_id = 0; | 569 | application_area_id = 0; |
| 528 | application_area_data.clear(); | 570 | application_area_data.clear(); |
| 529 | } | 571 | } |
| 530 | 572 | ||
| 531 | ResultCode Module::Interface::StartDetection() { | 573 | ResultCode Module::Interface::StartDetection(s32 protocol_) { |
| 532 | auto npad_device = system.HIDCore().GetEmulatedController(npad_id); | 574 | auto npad_device = system.HIDCore().GetEmulatedController(npad_id); |
| 533 | 575 | ||
| 534 | // TODO(german77): Add callback for when nfc data is available | 576 | // TODO(german77): Add callback for when nfc data is available |
| @@ -536,6 +578,7 @@ ResultCode Module::Interface::StartDetection() { | |||
| 536 | if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { | 578 | if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { |
| 537 | npad_device->SetPollingMode(Common::Input::PollingMode::NFC); | 579 | npad_device->SetPollingMode(Common::Input::PollingMode::NFC); |
| 538 | device_state = DeviceState::SearchingForTag; | 580 | device_state = DeviceState::SearchingForTag; |
| 581 | protocol = protocol_; | ||
| 539 | return ResultSuccess; | 582 | return ResultSuccess; |
| 540 | } | 583 | } |
| 541 | 584 | ||
| @@ -589,8 +632,8 @@ ResultCode Module::Interface::GetTagInfo(TagInfo& tag_info) const { | |||
| 589 | tag_info = { | 632 | tag_info = { |
| 590 | .uuid = amiibo.uuid, | 633 | .uuid = amiibo.uuid, |
| 591 | .uuid_length = static_cast<u8>(amiibo.uuid.size()), | 634 | .uuid_length = static_cast<u8>(amiibo.uuid.size()), |
| 592 | .protocol = 0xFFFFFFFF, // TODO(ogniK): Figure out actual values | 635 | .protocol = protocol, |
| 593 | .tag_type = 0xFFFFFFFF, | 636 | .tag_type = static_cast<u32>(amiibo.model_info.amiibo_type), |
| 594 | }; | 637 | }; |
| 595 | return ResultSuccess; | 638 | return ResultSuccess; |
| 596 | } | 639 | } |
| @@ -610,7 +653,7 @@ ResultCode Module::Interface::GetCommonInfo(CommonInfo& common_info) const { | |||
| 610 | .last_write_year = 2022, | 653 | .last_write_year = 2022, |
| 611 | .last_write_month = 2, | 654 | .last_write_month = 2, |
| 612 | .last_write_day = 7, | 655 | .last_write_day = 7, |
| 613 | .write_counter = write_counter, | 656 | .write_counter = amiibo.write_count, |
| 614 | .version = 1, | 657 | .version = 1, |
| 615 | .application_area_size = ApplicationAreaSize, | 658 | .application_area_size = ApplicationAreaSize, |
| 616 | }; | 659 | }; |
| @@ -652,11 +695,11 @@ ResultCode Module::Interface::OpenApplicationArea(u32 access_id) { | |||
| 652 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | 695 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); |
| 653 | return ErrCodes::WrongDeviceState; | 696 | return ErrCodes::WrongDeviceState; |
| 654 | } | 697 | } |
| 655 | // if (AmiiboApplicationDataExist(access_id)) { | 698 | if (AmiiboApplicationDataExist(access_id)) { |
| 656 | // application_area_data = LoadAmiiboApplicationData(access_id); | 699 | application_area_data = LoadAmiiboApplicationData(access_id); |
| 657 | // application_area_id = access_id; | 700 | application_area_id = access_id; |
| 658 | // is_application_area_initialized = true; | 701 | is_application_area_initialized = true; |
| 659 | // } | 702 | } |
| 660 | if (!is_application_area_initialized) { | 703 | if (!is_application_area_initialized) { |
| 661 | LOG_ERROR(Service_NFP, "Application area is not initialized"); | 704 | LOG_ERROR(Service_NFP, "Application area is not initialized"); |
| 662 | return ErrCodes::ApplicationAreaIsNotInitialized; | 705 | return ErrCodes::ApplicationAreaIsNotInitialized; |
| @@ -689,8 +732,7 @@ ResultCode Module::Interface::SetApplicationArea(const std::vector<u8>& data) { | |||
| 689 | return ErrCodes::ApplicationAreaIsNotInitialized; | 732 | return ErrCodes::ApplicationAreaIsNotInitialized; |
| 690 | } | 733 | } |
| 691 | application_area_data = data; | 734 | application_area_data = data; |
| 692 | write_counter++; | 735 | SaveAmiiboApplicationData(application_area_id, application_area_data); |
| 693 | // SaveAmiiboApplicationData(application_area_id,application_area_data); | ||
| 694 | return ResultSuccess; | 736 | return ResultSuccess; |
| 695 | } | 737 | } |
| 696 | 738 | ||
| @@ -699,21 +741,32 @@ ResultCode Module::Interface::CreateApplicationArea(u32 access_id, const std::ve | |||
| 699 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | 741 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); |
| 700 | return ErrCodes::WrongDeviceState; | 742 | return ErrCodes::WrongDeviceState; |
| 701 | } | 743 | } |
| 702 | // if (AmiiboApplicationDataExist(access_id)) { | 744 | if (AmiiboApplicationDataExist(access_id)) { |
| 703 | // LOG_ERROR(Service_NFP, "Application area already exist"); | 745 | LOG_ERROR(Service_NFP, "Application area already exist"); |
| 704 | // return ErrCodes::ApplicationAreaExist; | 746 | return ErrCodes::ApplicationAreaExist; |
| 705 | // } | 747 | } |
| 706 | // if (LoadAmiiboApplicationData(access_id,data)) { | ||
| 707 | // is_application_area_initialized = true; | ||
| 708 | // application_area_id = access_id; | ||
| 709 | // } | ||
| 710 | application_area_data = data; | 748 | application_area_data = data; |
| 711 | application_area_id = access_id; | 749 | application_area_id = access_id; |
| 712 | write_counter = 0; | 750 | SaveAmiiboApplicationData(application_area_id, application_area_data); |
| 713 | // SaveAmiiboApplicationData(application_area_id,application_area_data); | ||
| 714 | return ResultSuccess; | 751 | return ResultSuccess; |
| 715 | } | 752 | } |
| 716 | 753 | ||
| 754 | bool Module::Interface::AmiiboApplicationDataExist(u32 access_id) const { | ||
| 755 | // TODO(german77): Check if file exist | ||
| 756 | return false; | ||
| 757 | } | ||
| 758 | |||
| 759 | const std::vector<u8> Module::Interface::LoadAmiiboApplicationData(u32 access_id) const { | ||
| 760 | // TODO(german77): Read file | ||
| 761 | std::vector<u8> data(ApplicationAreaSize); | ||
| 762 | return data; | ||
| 763 | } | ||
| 764 | |||
| 765 | void Module::Interface::SaveAmiiboApplicationData(u32 access_id, | ||
| 766 | const std::vector<u8>& data) const { | ||
| 767 | // TODO(german77): Save file | ||
| 768 | } | ||
| 769 | |||
| 717 | u64 Module::Interface::GetHandle() const { | 770 | u64 Module::Interface::GetHandle() const { |
| 718 | // Generate a handle based of the npad id | 771 | // Generate a handle based of the npad id |
| 719 | return static_cast<u64>(npad_id); | 772 | return static_cast<u64>(npad_id); |
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 4642ed634..633539dcc 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h | |||
| @@ -53,11 +53,43 @@ enum class MountTarget : u32 { | |||
| 53 | All, | 53 | All, |
| 54 | }; | 54 | }; |
| 55 | 55 | ||
| 56 | enum class AmiiboType : u8 { | ||
| 57 | Figure, | ||
| 58 | Card, | ||
| 59 | Yarn, | ||
| 60 | }; | ||
| 61 | |||
| 62 | enum class AmiiboSeries : u8 { | ||
| 63 | SuperSmashBros, | ||
| 64 | SuperMario, | ||
| 65 | ChibiRobo, | ||
| 66 | YoshiWoollyWorld, | ||
| 67 | Splatoon, | ||
| 68 | AnimalCrossing, | ||
| 69 | EightBitMario, | ||
| 70 | Skylanders, | ||
| 71 | Unknown8, | ||
| 72 | TheLegendOfZelda, | ||
| 73 | ShovelKnight, | ||
| 74 | Unknown11, | ||
| 75 | Kiby, | ||
| 76 | Pokemon, | ||
| 77 | MarioSportsSuperstars, | ||
| 78 | MonsterHunter, | ||
| 79 | BoxBoy, | ||
| 80 | Pikmin, | ||
| 81 | FireEmblem, | ||
| 82 | Metroid, | ||
| 83 | Others, | ||
| 84 | MegaMan, | ||
| 85 | Diablo | ||
| 86 | }; | ||
| 87 | |||
| 56 | struct TagInfo { | 88 | struct TagInfo { |
| 57 | std::array<u8, 10> uuid; | 89 | std::array<u8, 10> uuid; |
| 58 | u8 uuid_length; | 90 | u8 uuid_length; |
| 59 | INSERT_PADDING_BYTES(0x15); | 91 | INSERT_PADDING_BYTES(0x15); |
| 60 | u32 protocol; | 92 | s32 protocol; |
| 61 | u32 tag_type; | 93 | u32 tag_type; |
| 62 | INSERT_PADDING_BYTES(0x30); | 94 | INSERT_PADDING_BYTES(0x30); |
| 63 | }; | 95 | }; |
| @@ -77,10 +109,13 @@ static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); | |||
| 77 | struct ModelInfo { | 109 | struct ModelInfo { |
| 78 | u16 character_id; | 110 | u16 character_id; |
| 79 | u8 character_variant; | 111 | u8 character_variant; |
| 80 | u8 figure_type; | 112 | AmiiboType amiibo_type; |
| 81 | u16 model_number; | 113 | u16 model_number; |
| 82 | u8 series; | 114 | AmiiboSeries series; |
| 83 | INSERT_PADDING_BYTES(0x39); | 115 | u8 fixed; // Must be 02 |
| 116 | INSERT_PADDING_BYTES(0x4); // Unknown | ||
| 117 | INSERT_PADDING_BYTES(0x20); // Probably a SHA256-(HMAC?) hash | ||
| 118 | INSERT_PADDING_BYTES(0x14); // SHA256-HMAC | ||
| 84 | }; | 119 | }; |
| 85 | static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); | 120 | static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); |
| 86 | 121 | ||
| @@ -105,11 +140,21 @@ public: | |||
| 105 | 140 | ||
| 106 | struct AmiiboFile { | 141 | struct AmiiboFile { |
| 107 | std::array<u8, 10> uuid; | 142 | std::array<u8, 10> uuid; |
| 108 | INSERT_PADDING_BYTES(0x4); // Compability container | 143 | u16 uuid_lock; // Must be 0F E0 |
| 109 | INSERT_PADDING_BYTES(0x46); | 144 | u32 compability_container; // Must be F1 10 FF EE |
| 110 | ModelInfo model_info; | 145 | u16 crypto_init; // Must be A5 XX |
| 146 | u16 write_count; // Number of times the amiibo has been written? | ||
| 147 | INSERT_PADDING_BYTES(0x20); // System crypts | ||
| 148 | INSERT_PADDING_BYTES(0x20); // SHA256-(HMAC?) hash | ||
| 149 | ModelInfo model_info; // This struct is bigger than documentation | ||
| 150 | INSERT_PADDING_BYTES(0xC); // SHA256-HMAC | ||
| 151 | INSERT_PADDING_BYTES(0x114); // section 1 encrypted buffer | ||
| 152 | INSERT_PADDING_BYTES(0x54); // section 2 encrypted buffer | ||
| 153 | u32 tag_dynamic_lock; // Must be 01 00 0F XX | ||
| 154 | u32 tag_CFG0; // Must be 00 00 00 04 | ||
| 155 | u32 tag_CFG1; // Must be 50 00 00 00 | ||
| 111 | }; | 156 | }; |
| 112 | static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); | 157 | static_assert(sizeof(AmiiboFile) == 0x214, "AmiiboFile is an invalid size"); |
| 113 | 158 | ||
| 114 | void CreateUserInterface(Kernel::HLERequestContext& ctx); | 159 | void CreateUserInterface(Kernel::HLERequestContext& ctx); |
| 115 | bool LoadAmiibo(const std::vector<u8>& buffer); | 160 | bool LoadAmiibo(const std::vector<u8>& buffer); |
| @@ -118,7 +163,7 @@ public: | |||
| 118 | void Initialize(); | 163 | void Initialize(); |
| 119 | void Finalize(); | 164 | void Finalize(); |
| 120 | 165 | ||
| 121 | ResultCode StartDetection(); | 166 | ResultCode StartDetection(s32 protocol_); |
| 122 | ResultCode StopDetection(); | 167 | ResultCode StopDetection(); |
| 123 | ResultCode Mount(); | 168 | ResultCode Mount(); |
| 124 | ResultCode Unmount(); | 169 | ResultCode Unmount(); |
| @@ -144,6 +189,12 @@ public: | |||
| 144 | std::shared_ptr<Module> module; | 189 | std::shared_ptr<Module> module; |
| 145 | 190 | ||
| 146 | private: | 191 | private: |
| 192 | /// Validates that the amiibo file is not corrupted | ||
| 193 | bool IsAmiiboValid() const; | ||
| 194 | bool AmiiboApplicationDataExist(u32 access_id) const; | ||
| 195 | const std::vector<u8> LoadAmiiboApplicationData(u32 access_id) const; | ||
| 196 | void SaveAmiiboApplicationData(u32 access_id, const std::vector<u8>& data) const; | ||
| 197 | |||
| 147 | const Core::HID::NpadIdType npad_id; | 198 | const Core::HID::NpadIdType npad_id; |
| 148 | 199 | ||
| 149 | DeviceState device_state{DeviceState::Unaviable}; | 200 | DeviceState device_state{DeviceState::Unaviable}; |
| @@ -151,7 +202,7 @@ public: | |||
| 151 | Kernel::KEvent* activate_event; | 202 | Kernel::KEvent* activate_event; |
| 152 | Kernel::KEvent* deactivate_event; | 203 | Kernel::KEvent* deactivate_event; |
| 153 | AmiiboFile amiibo{}; | 204 | AmiiboFile amiibo{}; |
| 154 | u16 write_counter{}; | 205 | s32 protocol; |
| 155 | bool is_application_area_initialized{}; | 206 | bool is_application_area_initialized{}; |
| 156 | u32 application_area_id; | 207 | u32 application_area_id; |
| 157 | std::vector<u8> application_area_data; | 208 | std::vector<u8> application_area_data; |