nfp_device.cpp 22 KB

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