diff --git a/nx/include/switch.h b/nx/include/switch.h index 62a4f60b..fab2a134 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -135,6 +135,7 @@ extern "C" { #include "switch/applets/album_la.h" #include "switch/applets/friends_la.h" #include "switch/applets/hid_la.h" +#include "switch/applets/nfp_la.h" #include "switch/applets/pctlauth.h" #include "switch/applets/psel.h" #include "switch/applets/error.h" diff --git a/nx/include/switch/applets/nfp_la.h b/nx/include/switch/applets/nfp_la.h new file mode 100644 index 00000000..cf8e6457 --- /dev/null +++ b/nx/include/switch/applets/nfp_la.h @@ -0,0 +1,89 @@ +/** + * @file nfp_la.h + * @brief Wrapper for using the cabinet (amiibo) LibraryApplet. + * @author yellows8 + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../services/nfc.h" + +/// Values for NfpLaStartParamForAmiiboSettings::type. +typedef enum { + NfpLaStartParamTypeForAmiiboSettings_NicknameAndOwnerSettings = 0, ///< NicknameAndOwnerSettings + NfpLaStartParamTypeForAmiiboSettings_GameDataEraser = 1, ///< GameDataEraser + NfpLaStartParamTypeForAmiiboSettings_Restorer = 2, ///< Restorer + NfpLaStartParamTypeForAmiiboSettings_Formatter = 3, ///< Formatter +} NfpLaStartParamTypeForAmiiboSettings; + +/// AmiiboSettingsStartParam +typedef struct { + u8 unk_x0[0x8]; ///< Unknown + u8 unk_x8[0x20]; ///< Unknown + u8 unk_x28; ///< Unknown +} NfpLaAmiiboSettingsStartParam; + +/// StartParamForAmiiboSettings +typedef struct { + u8 unk_x0; ///< Unknown + u8 type; ///< \ref NfpLaStartParamTypeForAmiiboSettings + u8 flags; ///< Flags + u8 unk_x3; ///< NfpLaAmiiboSettingsStartParam::unk_x28 + u8 unk_x4[0x8]; ///< NfpLaAmiiboSettingsStartParam::unk_x0 + NfpTagInfo tag_info; ///< \ref NfpTagInfo, only enabled when flags bit1 is set. + NfpRegisterInfo register_info; ///< \ref NfpRegisterInfo, only enabled when flags bit2 is set. + u8 unk_x164[0x20]; ///< NfpLaAmiiboSettingsStartParam::unk_x8 + u8 unk_x184[0x24]; ///< Unknown +} NfpLaStartParamForAmiiboSettings; + +/// ReturnValueForAmiiboSettings +typedef struct { + u8 flags; ///< 0 = error, non-zero = success. + u8 pad[3]; ///< Padding + NfcDeviceHandle handle; ///< \ref NfcDeviceHandle + NfpTagInfo tag_info; ///< \ref NfpTagInfo + NfpRegisterInfo register_info; ///< \ref NfpRegisterInfo, only available when flags bit2 is set. + u8 unk_x164[0x24]; ///< Unknown +} NfpLaReturnValueForAmiiboSettings; + +/** + * @brief Launches the applet for NicknameAndOwnerSettings. + * @note Official sw does not expose functionality for using input/output \ref NfpTagInfo at the same time. + * @param[in] in_param \ref NfpLaAmiiboSettingsStartParam + * @param[in] in_tag_info \ref NfpTagInfo. Optional, can be NULL. If specified, this must match the scanned amiibo. + * @param[in] in_reg_info \ref NfpRegisterInfo. Optional, can be NULL. If specified, this sets the \ref NfpRegisterInfo which will be used for writing, with an option for the user to change it. + * @param[out] out_tag_info \ref NfpTagInfo. Optional, can be NULL. + * @param[out] handle \ref NfcDeviceHandle + * @param[out] reg_info_flag Flag indicating whether the data for out_reg_info is set. Optional, can be NULL. + * @param[out] out_reg_info \ref NfpRegisterInfo, see reg_info_flag. Optional, can be NULL. + */ +Result nfpLaStartNicknameAndOwnerSettings(const NfpLaAmiiboSettingsStartParam *in_param, const NfpTagInfo *in_tag_info, const NfpRegisterInfo *in_reg_info, NfpTagInfo *out_tag_info, NfcDeviceHandle *handle, bool *reg_info_flag, NfpRegisterInfo *out_reg_info); + +/** + * @brief Launches the applet for GameDataEraser. + * @note Official sw does not expose functionality for using input/output \ref NfpTagInfo at the same time. + * @param[in] in_param \ref NfpLaAmiiboSettingsStartParam + * @param[in] in_tag_info \ref NfpTagInfo. Optional, can be NULL. If specified, this must match the scanned amiibo. + * @param[out] out_tag_info \ref NfpTagInfo. Optional, can be NULL. + * @param[out] handle \ref NfcDeviceHandle + */ +Result nfpLaStartGameDataEraser(const NfpLaAmiiboSettingsStartParam *in_param, const NfpTagInfo *in_tag_info, NfpTagInfo *out_tag_info, NfcDeviceHandle *handle); + +/** + * @brief Launches the applet for Restorer. + * @note Official sw does not expose functionality for using input/output \ref NfpTagInfo at the same time. + * @param[in] in_param \ref NfpLaAmiiboSettingsStartParam + * @param[in] in_tag_info \ref NfpTagInfo. Optional, can be NULL. If specified, this must match the scanned amiibo. + * @param[out] out_tag_info \ref NfpTagInfo. Optional, can be NULL. + * @param[out] handle \ref NfcDeviceHandle + */ +Result nfpLaStartRestorer(const NfpLaAmiiboSettingsStartParam *in_param, const NfpTagInfo *in_tag_info, NfpTagInfo *out_tag_info, NfcDeviceHandle *handle); + +/** + * @brief Launches the applet for Formatter. + * @param[in] in_param \ref NfpLaAmiiboSettingsStartParam + * @param[out] out_tag_info \ref NfpTagInfo + * @param[out] handle \ref NfcDeviceHandle + */ +Result nfpLaStartFormatter(const NfpLaAmiiboSettingsStartParam *in_param, NfpTagInfo *out_tag_info, NfcDeviceHandle *handle); + diff --git a/nx/source/applets/nfp_la.c b/nx/source/applets/nfp_la.c new file mode 100644 index 00000000..379c34d4 --- /dev/null +++ b/nx/source/applets/nfp_la.c @@ -0,0 +1,70 @@ +#include +#include "libapplet_internal.h" +#include "applets/nfp_la.h" + +static Result _nfpLaShow(const NfpLaStartParamForAmiiboSettings *param, NfpLaReturnValueForAmiiboSettings *reply) { + Result rc=0; + size_t out_reply_size=0; + u32 ver=1; + LibAppletArgs commonargs; + + libappletArgsCreate(&commonargs, ver); + + rc = libappletLaunch(AppletId_cabinet, &commonargs, param, sizeof(*param), reply, sizeof(*reply), &out_reply_size); + if (R_SUCCEEDED(rc)) { // sdknso doesn't validate out_reply_size. + if (!reply->flags) rc = MAKERESULT(Module_Libnx, LibnxError_LibAppletBadExit); + } + else + reply->flags = 0; + + return rc; +} + +static Result _nfpLaStartSettings(NfpLaStartParamTypeForAmiiboSettings type, const NfpLaAmiiboSettingsStartParam *in_param, const NfpTagInfo *in_tag_info, const NfpRegisterInfo *in_reg_info, NfpTagInfo *out_tag_info, NfcDeviceHandle *handle, bool *reg_info_flag, NfpRegisterInfo *out_reg_info) { + Result rc=0; + NfpLaStartParamForAmiiboSettings param={0}; + NfpLaReturnValueForAmiiboSettings reply={0}; + + param.type = type; + param.flags = 0x1; + if (in_tag_info) param.flags |= BIT(1); + if (in_reg_info) param.flags |= BIT(2); + param.unk_x3 = in_param->unk_x28; + memcpy(param.unk_x4, in_param->unk_x0, sizeof(in_param->unk_x0)); + + if (in_tag_info) memcpy(¶m.tag_info, in_tag_info, sizeof(NfpTagInfo)); + if (in_reg_info) memcpy(¶m.register_info, in_reg_info, sizeof(NfpRegisterInfo)); + + memcpy(param.unk_x164, in_param->unk_x8, sizeof(in_param->unk_x8)); + + rc = _nfpLaShow(¶m, &reply); + + if (R_SUCCEEDED(rc)) { + if (out_tag_info) memcpy(out_tag_info, &reply.tag_info, sizeof(NfpTagInfo)); + *handle = reply.handle; + if (reg_info_flag || out_reg_info) { + bool tmpflag = (reply.flags & BIT(2)) != 0; + if (reg_info_flag) *reg_info_flag = tmpflag; + if (tmpflag && out_reg_info) memcpy(out_reg_info, &reply.register_info, sizeof(NfpRegisterInfo)); + } + } + + return rc; +} + +Result nfpLaStartNicknameAndOwnerSettings(const NfpLaAmiiboSettingsStartParam *in_param, const NfpTagInfo *in_tag_info, const NfpRegisterInfo *in_reg_info, NfpTagInfo *out_tag_info, NfcDeviceHandle *handle, bool *reg_info_flag, NfpRegisterInfo *out_reg_info) { + return _nfpLaStartSettings(NfpLaStartParamTypeForAmiiboSettings_NicknameAndOwnerSettings, in_param, in_tag_info, in_reg_info, out_tag_info, handle, reg_info_flag, out_reg_info); +} + +Result nfpLaStartGameDataEraser(const NfpLaAmiiboSettingsStartParam *in_param, const NfpTagInfo *in_tag_info, NfpTagInfo *out_tag_info, NfcDeviceHandle *handle) { + return _nfpLaStartSettings(NfpLaStartParamTypeForAmiiboSettings_GameDataEraser, in_param, in_tag_info, NULL, out_tag_info, handle, NULL, NULL); +} + +Result nfpLaStartRestorer(const NfpLaAmiiboSettingsStartParam *in_param, const NfpTagInfo *in_tag_info, NfpTagInfo *out_tag_info, NfcDeviceHandle *handle) { + return _nfpLaStartSettings(NfpLaStartParamTypeForAmiiboSettings_Restorer, in_param, in_tag_info, NULL, out_tag_info, handle, NULL, NULL); +} + +Result nfpLaStartFormatter(const NfpLaAmiiboSettingsStartParam *in_param, NfpTagInfo *out_tag_info, NfcDeviceHandle *handle) { + return _nfpLaStartSettings(NfpLaStartParamTypeForAmiiboSettings_Formatter, in_param, NULL, NULL, out_tag_info, handle, NULL, NULL); +} +