nfp_device.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <array>
  4. #include "common/input.h"
  5. #include "common/logging/log.h"
  6. #include "common/string_util.h"
  7. #include "common/tiny_mt.h"
  8. #include "core/core.h"
  9. #include "core/hid/emulated_controller.h"
  10. #include "core/hid/hid_core.h"
  11. #include "core/hid/hid_types.h"
  12. #include "core/hle/ipc_helpers.h"
  13. #include "core/hle/kernel/k_event.h"
  14. #include "core/hle/service/mii/mii_manager.h"
  15. #include "core/hle/service/mii/types.h"
  16. #include "core/hle/service/nfp/amiibo_crypto.h"
  17. #include "core/hle/service/nfp/nfp_device.h"
  18. #include "core/hle/service/nfp/nfp_result.h"
  19. #include "core/hle/service/nfp/nfp_user.h"
  20. #include "core/hle/service/time/time_manager.h"
  21. #include "core/hle/service/time/time_zone_content_manager.h"
  22. #include "core/hle/service/time/time_zone_types.h"
  23. namespace Service::NFP {
  24. NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
  25. KernelHelpers::ServiceContext& service_context_,
  26. Kernel::KEvent* availability_change_event_)
  27. : npad_id{npad_id_}, system{system_}, service_context{service_context_},
  28. availability_change_event{availability_change_event_} {
  29. activate_event = service_context.CreateEvent("IUser:NFPActivateEvent");
  30. deactivate_event = service_context.CreateEvent("IUser:NFPDeactivateEvent");
  31. npad_device = system.HIDCore().GetEmulatedController(npad_id);
  32. Core::HID::ControllerUpdateCallback engine_callback{
  33. .on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); },
  34. .is_npad_service = false,
  35. };
  36. is_controller_set = true;
  37. callback_key = npad_device->SetCallback(engine_callback);
  38. auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
  39. current_posix_time = standard_steady_clock.GetCurrentTimePoint(system).time_point;
  40. }
  41. NfpDevice::~NfpDevice() {
  42. activate_event->Close();
  43. deactivate_event->Close();
  44. if (!is_controller_set) {
  45. return;
  46. }
  47. npad_device->DeleteCallback(callback_key);
  48. is_controller_set = false;
  49. };
  50. void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
  51. if (type == Core::HID::ControllerTriggerType::Connected ||
  52. type == Core::HID::ControllerTriggerType::Disconnected) {
  53. availability_change_event->Signal();
  54. return;
  55. }
  56. if (type != Core::HID::ControllerTriggerType::Nfc) {
  57. return;
  58. }
  59. if (!npad_device->IsConnected()) {
  60. return;
  61. }
  62. const auto nfc_status = npad_device->GetNfc();
  63. switch (nfc_status.state) {
  64. case Common::Input::NfcState::NewAmiibo:
  65. LoadAmiibo(nfc_status.data);
  66. break;
  67. case Common::Input::NfcState::AmiiboRemoved:
  68. if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
  69. break;
  70. }
  71. if (device_state != DeviceState::SearchingForTag) {
  72. CloseAmiibo();
  73. }
  74. break;
  75. default:
  76. break;
  77. }
  78. }
  79. bool NfpDevice::LoadAmiibo(std::span<const u8> data) {
  80. if (device_state != DeviceState::SearchingForTag) {
  81. LOG_ERROR(Service_NFP, "Game is not looking for amiibos, current state {}", device_state);
  82. return false;
  83. }
  84. if (data.size() != sizeof(EncryptedNTAG215File)) {
  85. LOG_ERROR(Service_NFP, "Not an amiibo, size={}", data.size());
  86. return false;
  87. }
  88. // TODO: Filter by allowed_protocols here
  89. memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File));
  90. device_state = DeviceState::TagFound;
  91. deactivate_event->GetReadableEvent().Clear();
  92. activate_event->Signal();
  93. return true;
  94. }
  95. void NfpDevice::CloseAmiibo() {
  96. LOG_INFO(Service_NFP, "Remove amiibo");
  97. if (device_state == DeviceState::TagMounted) {
  98. Unmount();
  99. }
  100. device_state = DeviceState::TagRemoved;
  101. encrypted_tag_data = {};
  102. tag_data = {};
  103. activate_event->GetReadableEvent().Clear();
  104. deactivate_event->Signal();
  105. }
  106. Kernel::KReadableEvent& NfpDevice::GetActivateEvent() const {
  107. return activate_event->GetReadableEvent();
  108. }
  109. Kernel::KReadableEvent& NfpDevice::GetDeactivateEvent() const {
  110. return deactivate_event->GetReadableEvent();
  111. }
  112. void NfpDevice::Initialize() {
  113. device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable;
  114. encrypted_tag_data = {};
  115. tag_data = {};
  116. }
  117. void NfpDevice::Finalize() {
  118. if (device_state == DeviceState::TagMounted) {
  119. Unmount();
  120. }
  121. if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
  122. StopDetection();
  123. }
  124. device_state = DeviceState::Unavailable;
  125. }
  126. Result NfpDevice::StartDetection(TagProtocol allowed_protocol) {
  127. if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) {
  128. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  129. return WrongDeviceState;
  130. }
  131. if (npad_device->SetPollingMode(Common::Input::PollingMode::NFC) !=
  132. Common::Input::DriverResult::Success) {
  133. LOG_ERROR(Service_NFP, "Nfc not supported");
  134. return NfcDisabled;
  135. }
  136. device_state = DeviceState::SearchingForTag;
  137. allowed_protocols = allowed_protocol;
  138. return ResultSuccess;
  139. }
  140. Result NfpDevice::StopDetection() {
  141. npad_device->SetPollingMode(Common::Input::PollingMode::Active);
  142. if (device_state == DeviceState::Initialized) {
  143. return ResultSuccess;
  144. }
  145. if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) {
  146. CloseAmiibo();
  147. return ResultSuccess;
  148. }
  149. if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
  150. device_state = DeviceState::Initialized;
  151. return ResultSuccess;
  152. }
  153. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  154. return WrongDeviceState;
  155. }
  156. Result NfpDevice::Flush() {
  157. if (device_state != DeviceState::TagMounted) {
  158. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  159. if (device_state == DeviceState::TagRemoved) {
  160. return TagRemoved;
  161. }
  162. return WrongDeviceState;
  163. }
  164. if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
  165. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  166. return WrongDeviceState;
  167. }
  168. auto& settings = tag_data.settings;
  169. const auto& current_date = GetAmiiboDate(current_posix_time);
  170. if (settings.write_date.raw_date != current_date.raw_date) {
  171. settings.write_date = current_date;
  172. settings.crc_counter++;
  173. // TODO: Find how to calculate the crc check
  174. // settings.crc = CalculateCRC(settings);
  175. }
  176. tag_data.write_counter++;
  177. if (!AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
  178. LOG_ERROR(Service_NFP, "Failed to encode data");
  179. return WriteAmiiboFailed;
  180. }
  181. std::vector<u8> data(sizeof(encrypted_tag_data));
  182. memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
  183. if (!npad_device->WriteNfc(data)) {
  184. LOG_ERROR(Service_NFP, "Error writing to file");
  185. return WriteAmiiboFailed;
  186. }
  187. is_data_moddified = false;
  188. return ResultSuccess;
  189. }
  190. Result NfpDevice::Mount(MountTarget mount_target_) {
  191. if (device_state != DeviceState::TagFound) {
  192. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  193. return WrongDeviceState;
  194. }
  195. if (!AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
  196. LOG_ERROR(Service_NFP, "Not an amiibo");
  197. return NotAnAmiibo;
  198. }
  199. // Mark amiibos as read only when keys are missing
  200. if (!AmiiboCrypto::IsKeyAvailable()) {
  201. LOG_ERROR(Service_NFP, "No keys detected");
  202. device_state = DeviceState::TagMounted;
  203. mount_target = MountTarget::Rom;
  204. return ResultSuccess;
  205. }
  206. if (!AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
  207. LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state);
  208. return CorruptedData;
  209. }
  210. device_state = DeviceState::TagMounted;
  211. mount_target = mount_target_;
  212. return ResultSuccess;
  213. }
  214. Result NfpDevice::Unmount() {
  215. if (device_state != DeviceState::TagMounted) {
  216. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  217. if (device_state == DeviceState::TagRemoved) {
  218. return TagRemoved;
  219. }
  220. return WrongDeviceState;
  221. }
  222. // Save data before unloading the amiibo
  223. if (is_data_moddified) {
  224. Flush();
  225. }
  226. device_state = DeviceState::TagFound;
  227. mount_target = MountTarget::None;
  228. is_app_area_open = false;
  229. return ResultSuccess;
  230. }
  231. Result NfpDevice::GetTagInfo(TagInfo& tag_info) const {
  232. if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
  233. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  234. if (device_state == DeviceState::TagRemoved) {
  235. return TagRemoved;
  236. }
  237. return WrongDeviceState;
  238. }
  239. tag_info = {
  240. .uuid = encrypted_tag_data.uuid.uid,
  241. .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
  242. .protocol = TagProtocol::TypeA,
  243. .tag_type = TagType::Type2,
  244. };
  245. return ResultSuccess;
  246. }
  247. Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const {
  248. if (device_state != DeviceState::TagMounted) {
  249. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  250. if (device_state == DeviceState::TagRemoved) {
  251. return TagRemoved;
  252. }
  253. return WrongDeviceState;
  254. }
  255. if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
  256. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  257. return WrongDeviceState;
  258. }
  259. const auto& settings = tag_data.settings;
  260. // TODO: Validate this data
  261. common_info = {
  262. .last_write_date = settings.write_date.GetWriteDate(),
  263. .write_counter = tag_data.write_counter,
  264. .version = 0,
  265. .application_area_size = sizeof(ApplicationArea),
  266. };
  267. return ResultSuccess;
  268. }
  269. Result NfpDevice::GetModelInfo(ModelInfo& model_info) const {
  270. if (device_state != DeviceState::TagMounted) {
  271. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  272. if (device_state == DeviceState::TagRemoved) {
  273. return TagRemoved;
  274. }
  275. return WrongDeviceState;
  276. }
  277. const auto& model_info_data = encrypted_tag_data.user_memory.model_info;
  278. model_info = {
  279. .character_id = model_info_data.character_id,
  280. .character_variant = model_info_data.character_variant,
  281. .amiibo_type = model_info_data.amiibo_type,
  282. .model_number = model_info_data.model_number,
  283. .series = model_info_data.series,
  284. };
  285. return ResultSuccess;
  286. }
  287. Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const {
  288. if (device_state != DeviceState::TagMounted) {
  289. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  290. if (device_state == DeviceState::TagRemoved) {
  291. return TagRemoved;
  292. }
  293. return WrongDeviceState;
  294. }
  295. if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
  296. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  297. return WrongDeviceState;
  298. }
  299. if (tag_data.settings.settings.amiibo_initialized == 0) {
  300. return RegistrationIsNotInitialized;
  301. }
  302. Service::Mii::MiiManager manager;
  303. const auto& settings = tag_data.settings;
  304. // TODO: Validate this data
  305. register_info = {
  306. .mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii),
  307. .creation_date = settings.init_date.GetWriteDate(),
  308. .amiibo_name = GetAmiiboName(settings),
  309. .font_region = {},
  310. };
  311. return ResultSuccess;
  312. }
  313. Result NfpDevice::SetNicknameAndOwner(const AmiiboName& amiibo_name) {
  314. if (device_state != DeviceState::TagMounted) {
  315. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  316. if (device_state == DeviceState::TagRemoved) {
  317. return TagRemoved;
  318. }
  319. return WrongDeviceState;
  320. }
  321. if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
  322. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  323. return WrongDeviceState;
  324. }
  325. Service::Mii::MiiManager manager;
  326. auto& settings = tag_data.settings;
  327. settings.init_date = GetAmiiboDate(current_posix_time);
  328. settings.write_date = GetAmiiboDate(current_posix_time);
  329. settings.crc_counter++;
  330. // TODO: Find how to calculate the crc check
  331. // settings.crc = CalculateCRC(settings);
  332. SetAmiiboName(settings, amiibo_name);
  333. tag_data.owner_mii = manager.ConvertCharInfoToV3(manager.BuildDefault(0));
  334. settings.settings.amiibo_initialized.Assign(1);
  335. return Flush();
  336. }
  337. Result NfpDevice::RestoreAmiibo() {
  338. if (device_state != DeviceState::TagMounted) {
  339. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  340. if (device_state == DeviceState::TagRemoved) {
  341. return TagRemoved;
  342. }
  343. return WrongDeviceState;
  344. }
  345. if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
  346. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  347. return WrongDeviceState;
  348. }
  349. // TODO: Load amiibo from backup on system
  350. LOG_ERROR(Service_NFP, "Not Implemented");
  351. return ResultSuccess;
  352. }
  353. Result NfpDevice::DeleteAllData() {
  354. const auto result = DeleteApplicationArea();
  355. if (result.IsError()) {
  356. return result;
  357. }
  358. if (device_state != DeviceState::TagMounted) {
  359. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  360. if (device_state == DeviceState::TagRemoved) {
  361. return TagRemoved;
  362. }
  363. return WrongDeviceState;
  364. }
  365. Common::TinyMT rng{};
  366. rng.GenerateRandomBytes(&tag_data.owner_mii, sizeof(tag_data.owner_mii));
  367. tag_data.settings.settings.amiibo_initialized.Assign(0);
  368. return Flush();
  369. }
  370. Result NfpDevice::OpenApplicationArea(u32 access_id) {
  371. if (device_state != DeviceState::TagMounted) {
  372. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  373. if (device_state == DeviceState::TagRemoved) {
  374. return TagRemoved;
  375. }
  376. return WrongDeviceState;
  377. }
  378. if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
  379. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  380. return WrongDeviceState;
  381. }
  382. if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
  383. LOG_WARNING(Service_NFP, "Application area is not initialized");
  384. return ApplicationAreaIsNotInitialized;
  385. }
  386. if (tag_data.application_area_id != access_id) {
  387. LOG_WARNING(Service_NFP, "Wrong application area id");
  388. return WrongApplicationAreaId;
  389. }
  390. is_app_area_open = true;
  391. return ResultSuccess;
  392. }
  393. Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const {
  394. application_area_id = {};
  395. if (device_state != DeviceState::TagMounted) {
  396. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  397. if (device_state == DeviceState::TagRemoved) {
  398. return TagRemoved;
  399. }
  400. return WrongDeviceState;
  401. }
  402. if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
  403. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  404. return WrongDeviceState;
  405. }
  406. if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
  407. LOG_WARNING(Service_NFP, "Application area is not initialized");
  408. return ApplicationAreaIsNotInitialized;
  409. }
  410. application_area_id = tag_data.application_area_id;
  411. return ResultSuccess;
  412. }
  413. Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const {
  414. if (device_state != DeviceState::TagMounted) {
  415. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  416. if (device_state == DeviceState::TagRemoved) {
  417. return TagRemoved;
  418. }
  419. return WrongDeviceState;
  420. }
  421. if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
  422. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  423. return WrongDeviceState;
  424. }
  425. if (!is_app_area_open) {
  426. LOG_ERROR(Service_NFP, "Application area is not open");
  427. return WrongDeviceState;
  428. }
  429. if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
  430. LOG_ERROR(Service_NFP, "Application area is not initialized");
  431. return ApplicationAreaIsNotInitialized;
  432. }
  433. if (data.size() > sizeof(ApplicationArea)) {
  434. data.resize(sizeof(ApplicationArea));
  435. }
  436. memcpy(data.data(), tag_data.application_area.data(), data.size());
  437. return ResultSuccess;
  438. }
  439. Result NfpDevice::SetApplicationArea(std::span<const u8> data) {
  440. if (device_state != DeviceState::TagMounted) {
  441. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  442. if (device_state == DeviceState::TagRemoved) {
  443. return TagRemoved;
  444. }
  445. return WrongDeviceState;
  446. }
  447. if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
  448. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  449. return WrongDeviceState;
  450. }
  451. if (!is_app_area_open) {
  452. LOG_ERROR(Service_NFP, "Application area is not open");
  453. return WrongDeviceState;
  454. }
  455. if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
  456. LOG_ERROR(Service_NFP, "Application area is not initialized");
  457. return ApplicationAreaIsNotInitialized;
  458. }
  459. if (data.size() > sizeof(ApplicationArea)) {
  460. LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
  461. return ResultUnknown;
  462. }
  463. Common::TinyMT rng{};
  464. std::memcpy(tag_data.application_area.data(), data.data(), data.size());
  465. // Fill remaining data with random numbers
  466. rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
  467. sizeof(ApplicationArea) - data.size());
  468. tag_data.applicaton_write_counter++;
  469. is_data_moddified = true;
  470. return ResultSuccess;
  471. }
  472. Result NfpDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) {
  473. if (device_state != DeviceState::TagMounted) {
  474. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  475. if (device_state == DeviceState::TagRemoved) {
  476. return TagRemoved;
  477. }
  478. return WrongDeviceState;
  479. }
  480. if (tag_data.settings.settings.appdata_initialized.Value() != 0) {
  481. LOG_ERROR(Service_NFP, "Application area already exist");
  482. return ApplicationAreaExist;
  483. }
  484. return RecreateApplicationArea(access_id, data);
  485. }
  486. Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) {
  487. if (device_state != DeviceState::TagMounted) {
  488. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  489. if (device_state == DeviceState::TagRemoved) {
  490. return TagRemoved;
  491. }
  492. return WrongDeviceState;
  493. }
  494. if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
  495. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  496. return WrongDeviceState;
  497. }
  498. if (data.size() > sizeof(ApplicationArea)) {
  499. LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
  500. return WrongApplicationAreaSize;
  501. }
  502. Common::TinyMT rng{};
  503. std::memcpy(tag_data.application_area.data(), data.data(), data.size());
  504. // Fill remaining data with random numbers
  505. rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
  506. sizeof(ApplicationArea) - data.size());
  507. // TODO: Investigate why the title id needs to be moddified
  508. tag_data.title_id = system.GetCurrentProcessProgramID();
  509. tag_data.title_id = tag_data.title_id | 0x30000000ULL;
  510. tag_data.settings.settings.appdata_initialized.Assign(1);
  511. tag_data.application_area_id = access_id;
  512. tag_data.applicaton_write_counter++;
  513. tag_data.unknown = {};
  514. return Flush();
  515. }
  516. Result NfpDevice::DeleteApplicationArea() {
  517. if (device_state != DeviceState::TagMounted) {
  518. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  519. if (device_state == DeviceState::TagRemoved) {
  520. return TagRemoved;
  521. }
  522. return WrongDeviceState;
  523. }
  524. if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
  525. LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
  526. return WrongDeviceState;
  527. }
  528. Common::TinyMT rng{};
  529. rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(ApplicationArea));
  530. rng.GenerateRandomBytes(&tag_data.title_id, sizeof(u64));
  531. rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32));
  532. tag_data.settings.settings.appdata_initialized.Assign(0);
  533. tag_data.applicaton_write_counter++;
  534. tag_data.unknown = {};
  535. return Flush();
  536. }
  537. u64 NfpDevice::GetHandle() const {
  538. // Generate a handle based of the npad id
  539. return static_cast<u64>(npad_id);
  540. }
  541. u32 NfpDevice::GetApplicationAreaSize() const {
  542. return sizeof(ApplicationArea);
  543. }
  544. DeviceState NfpDevice::GetCurrentState() const {
  545. return device_state;
  546. }
  547. Core::HID::NpadIdType NfpDevice::GetNpadId() const {
  548. return npad_id;
  549. }
  550. AmiiboName NfpDevice::GetAmiiboName(const AmiiboSettings& settings) const {
  551. std::array<char16_t, amiibo_name_length> settings_amiibo_name{};
  552. AmiiboName amiibo_name{};
  553. // Convert from big endian to little endian
  554. for (std::size_t i = 0; i < amiibo_name_length; i++) {
  555. settings_amiibo_name[i] = static_cast<u16>(settings.amiibo_name[i]);
  556. }
  557. // Convert from utf16 to utf8
  558. const auto amiibo_name_utf8 = Common::UTF16ToUTF8(settings_amiibo_name.data());
  559. memcpy(amiibo_name.data(), amiibo_name_utf8.data(), amiibo_name_utf8.size());
  560. return amiibo_name;
  561. }
  562. void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name) {
  563. std::array<char16_t, amiibo_name_length> settings_amiibo_name{};
  564. // Convert from utf8 to utf16
  565. const auto amiibo_name_utf16 = Common::UTF8ToUTF16(amiibo_name.data());
  566. memcpy(settings_amiibo_name.data(), amiibo_name_utf16.data(),
  567. amiibo_name_utf16.size() * sizeof(char16_t));
  568. // Convert from little endian to big endian
  569. for (std::size_t i = 0; i < amiibo_name_length; i++) {
  570. settings.amiibo_name[i] = static_cast<u16_be>(settings_amiibo_name[i]);
  571. }
  572. }
  573. AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const {
  574. const auto& time_zone_manager =
  575. system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
  576. Time::TimeZone::CalendarInfo calendar_info{};
  577. AmiiboDate amiibo_date{};
  578. amiibo_date.SetYear(2000);
  579. amiibo_date.SetMonth(1);
  580. amiibo_date.SetDay(1);
  581. if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) {
  582. amiibo_date.SetYear(calendar_info.time.year);
  583. amiibo_date.SetMonth(calendar_info.time.month);
  584. amiibo_date.SetDay(calendar_info.time.day);
  585. }
  586. return amiibo_date;
  587. }
  588. } // namespace Service::NFP