diff --git a/libctru/include/3ds/services/nfc.h b/libctru/include/3ds/services/nfc.h new file mode 100644 index 0000000..8f78d62 --- /dev/null +++ b/libctru/include/3ds/services/nfc.h @@ -0,0 +1,79 @@ +/** + * @file nfc.h + * @brief NFC service. + */ +#pragma once + +/** + * @brief Initializes NFC. + */ +Result nfcInit(void); + +/** + * @brief Shuts down NFC. + */ +void nfcExit(void); + +/** + * @brief Gets the NFC service handle. + * @return The NFC service handle. + */ +Handle nfcGetSessionHandle(void); + +/** + * @brief Initialize NFC module. + * @param type Unknown, can be either value 0x1 or 0x2. + */ +Result NFC_Initialize(u8 type); + +/** + * @brief Shutdown NFC module. + * @param type Unknown. + */ +Result NFC_Shutdown(u8 type); + +/** + * @brief O3DS starts communication with the O3DS NFC hardware. N3DS just checks state for this command. + */ +Result NFC_StartCommunication(void); + +/** + * @brief O3DS stops communication with the O3DS NFC hardware. N3DS just uses code used internally by NFC:StopTagScanning for this. + */ +Result NFC_StopCommunication(void); + +/** + * @brief Starts scanning for NFC tags. + * @param unknown Unknown. + */ +Result NFC_StartTagScanning(u16 unknown); + +/** + * @brief Stops scanning for NFC tags. + */ +Result NFC_StopTagScanning(void); + +/** + * @brief Read Amiibo NFC data and load in memory. + */ +Result NFC_LoadAmiiboData(void); + +/** + * @brief If the tagstate is valid, it then sets the current tagstate to 3. + */ +Result NFC_ResetTagScanState(void); + +/** + * @brief Returns the current NFC tag state. + * @param state Pointer to write NFC tag state. + * + * Tag state values: + * - 0: NFC:Initialize was not used yet. + * - 1: Not currently scanning for NFC tags. Set by NFC:StopTagScanning and NFC:Initialize, when successful. + * - 2: Currently scanning for NFC tags. Set by NFC:StartTagScanning when successful. + * - 3: NFC tag is in range. The state automatically changes to this when the state was previous value 3, without using any NFC service commands. + * - 4: NFC tag is now out of range, where the NFC tag was previously in range. This occurs automatically without using any NFC service commands. Once this state is entered, it won't automatically change to anything else when the tag is moved in range again. Hence, if you want to keep doing tag scanning after this, you must stop+start scanning. + * - 5: NFC tag data was successfully loaded. This is set by NFC:LoadAmiiboData when successful. + */ +Result NFC_GetTagState(u8 *state); + diff --git a/libctru/source/services/nfc.c b/libctru/source/services/nfc.c new file mode 100644 index 0000000..ef6300c --- /dev/null +++ b/libctru/source/services/nfc.c @@ -0,0 +1,169 @@ +#include <3ds/types.h> +#include <3ds/result.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/synchronization.h> +#include <3ds/services/nfc.h> +#include <3ds/ipc.h> + +static Handle nfcHandle; +static int nfcRefCount; + +Result nfcInit(void) +{ + Result ret=0; + + if (AtomicPostIncrement(&nfcRefCount)) return 0; + + ret = srvGetServiceHandle(&nfcHandle, "nfc:u"); + if (R_SUCCEEDED(ret)) + { + ret = NFC_Initialize(0x02); + if (R_FAILED(ret)) svcCloseHandle(nfcHandle); + } + if (R_FAILED(ret)) AtomicDecrement(&nfcRefCount); + + return ret; +} + +void nfcExit(void) +{ + if (AtomicDecrement(&nfcRefCount)) return; + svcCloseHandle(nfcHandle); +} + +Handle nfcGetSessionHandle(void) +{ + return nfcHandle; +} + +Result NFC_Initialize(u8 type) +{ + Result ret=0; + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x1,1,0); // 0x10040 + cmdbuf[1]=type; + + if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret; + + ret = (Result)cmdbuf[1]; + + return ret; +} + +Result NFC_Shutdown(u8 type) +{ + Result ret=0; + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x2,1,0); // 0x20040 + cmdbuf[1]=type; + + if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret; + + ret = (Result)cmdbuf[1]; + + return ret; +} + +Result NFC_StartCommunication(void) +{ + Result ret=0; + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x3,0,0); // 0x30000 + + if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret; + + ret = (Result)cmdbuf[1]; + + return ret; +} + +Result NFC_StopCommunication(void) +{ + Result ret=0; + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x4,0,0); // 0x40000 + + if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret; + + ret = (Result)cmdbuf[1]; + + return ret; +} + +Result NFC_StartTagScanning(u16 unknown) +{ + Result ret=0; + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x5,1,0); // 0x50040 + cmdbuf[1]=unknown; + + if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret; + + ret = (Result)cmdbuf[1]; + + return ret; +} + +Result NFC_StopTagScanning(void) +{ + Result ret=0; + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x6,0,0); // 0x60000 + + if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret; + + ret = (Result)cmdbuf[1]; + + return ret; +} + +Result NFC_LoadAmiiboData(void) +{ + Result ret=0; + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x7,0,0); // 0x70000 + + if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret; + + ret = (Result)cmdbuf[1]; + + return ret; +} + +Result NFC_ResetTagScanState(void) +{ + Result ret=0; + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x8,0,0); // 0x80000 + + if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret; + + ret = (Result)cmdbuf[1]; + + return ret; +} + +Result NFC_GetTagState(u8 *state) +{ + Result ret=0; + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0xD,0,0); // 0xD0000 + + if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret; + + ret = (Result)cmdbuf[1]; + *state = cmdbuf[2]; + + return ret; +} +