nfp_device.cpp 23 KB

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