libctru/libctru/source/services/nfc.c
2017-07-10 18:16:54 +01:00

535 lines
11 KiB
C

#include <string.h>
#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/services/apt.h>
#include <3ds/ipc.h>
static Handle nfcHandle;
static int nfcRefCount;
static NFC_OpType nfc_optype = NFC_OpType_NFCTag;
static Result NFC_Initialize(NFC_OpType type);
static Result NFC_Shutdown(NFC_OpType type);
static Result NFC_StartCommsAdapter(void);
static Result NFC_StartCommunication(void);
static Result NFC_StopCommunication(void);
static Result NFC_CommunicationGetStatus(u8 *out);
static Result NFC_CommunicationGetResult(Result *out);
static Result NFC_StartTagScanning(u16 unknown);
static Result NFC_StartOtherTagScanning(u16 unk0, u32 unk1);
static Result NFC_StopTagScanning(void);
static Result NFC_InitializeWriteAppData(u32 amiibo_appid, NFC_AppDataInitStruct *initstruct, const void *buf, size_t size);
static Result NFC_GetAppDataInitStruct(NFC_AppDataInitStruct *out);
Result nfcInit(NFC_OpType type)
{
Result ret=0;
if (AtomicPostIncrement(&nfcRefCount)) return 0;
ret = srvGetServiceHandle(&nfcHandle, "nfc:m");
if (R_FAILED(ret))ret = srvGetServiceHandle(&nfcHandle, "nfc:u");
if (R_SUCCEEDED(ret))
{
nfc_optype = type;
for (;;)
{
ret = NFC_Initialize(type);
if (ret != 0xd0a17480)
break;
svcSleepThread(500000);
}
if (R_FAILED(ret)) svcCloseHandle(nfcHandle);
}
if (R_FAILED(ret)) AtomicDecrement(&nfcRefCount);
return ret;
}
void nfcExit(void)
{
if (AtomicDecrement(&nfcRefCount)) return;
NFC_Shutdown(nfc_optype);
svcCloseHandle(nfcHandle);
}
Handle nfcGetSessionHandle(void)
{
return nfcHandle;
}
static Result NFC_StartCommsAdapter(void)
{
Result ret, ret2;
bool new3ds_flag = false;
u8 status;
APT_CheckNew3DS(&new3ds_flag);
if(new3ds_flag) return 0;
ret = NFC_StartCommunication();
if(R_FAILED(ret))return ret;
while(1)
{
status = 0;
ret = NFC_CommunicationGetStatus(&status);
if(R_FAILED(ret))break;
if(status==1)//"Attempting to initialize Old3DS NFC adapter communication."
{
svcSleepThread(1000000*100);
continue;
}
else if(status==2)//"Old3DS NFC adapter communication initialization successfully finished."
{
break;
}
//An error occured with Old3DS NFC-adapter communication initialization.
ret = NFC_CommunicationGetResult(&ret2);
if(R_FAILED(ret))break;
return ret2;
}
return ret;
}
Result nfcStartScanning(u16 inval)
{
Result ret = NFC_StartCommsAdapter();
if(R_FAILED(ret)) return ret;
return NFC_StartTagScanning(inval);
}
Result nfcStartOtherTagScanning(u16 unk0, u32 unk1)
{
Result ret = NFC_StartCommsAdapter();
if(R_FAILED(ret)) return ret;
return NFC_StartOtherTagScanning(unk0, unk1);
}
void nfcStopScanning(void)
{
bool new3ds_flag = false;
APT_CheckNew3DS(&new3ds_flag);
NFC_StopTagScanning();
if(!new3ds_flag)
{
NFC_StopCommunication();
}
}
static Result NFC_Initialize(NFC_OpType type)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x1,1,0); // 0x10040
cmdbuf[1]=type & 0xff;
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
return ret;
}
static Result NFC_Shutdown(NFC_OpType type)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x2,1,0); // 0x20040
cmdbuf[1]=type & 0xff;
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
return ret;
}
static 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 = cmdbuf[1];
return ret;
}
static 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 = cmdbuf[1];
return ret;
}
static 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 = cmdbuf[1];
return ret;
}
static 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 = cmdbuf[1];
return ret;
}
Result nfcLoadAmiiboData(void)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x7,0,0); // 0x70000
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
return ret;
}
Result nfcResetTagScanState(void)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x8,0,0); // 0x80000
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
return ret;
}
Result nfcUpdateStoredAmiiboData(void)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x9,0,2); // 0x90002
cmdbuf[1]=IPC_Desc_CurProcessHandle();
if(R_FAILED(ret=svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
return ret;
}
Result nfcGetTagState(NFC_TagState *state)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0xD,0,0); // 0xD0000
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
if(R_SUCCEEDED(ret) && state)*state = cmdbuf[2] & 0xff;
return ret;
}
static Result NFC_CommunicationGetStatus(u8 *out)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0xF,0,0); // 0xF0000
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
if(R_SUCCEEDED(ret) && out)*out = cmdbuf[2];
return ret;
}
Result nfcGetTagInfo(NFC_TagInfo *out)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x11,0,0); // 0x110000
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
if(R_SUCCEEDED(ret) && out)memcpy(out, &cmdbuf[2], sizeof(NFC_TagInfo));
return ret;
}
static Result NFC_CommunicationGetResult(Result *out)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x12,0,0); // 0x120000
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
if(R_SUCCEEDED(ret) && out)*out = cmdbuf[2];
return ret;
}
Result nfcOpenAppData(u32 amiibo_appid)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x13,1,0); // 0x130040
cmdbuf[1]=amiibo_appid;
if(R_FAILED(ret=svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
return ret;
}
Result nfcInitializeWriteAppData(u32 amiibo_appid, const void *buf, size_t size)
{
Result ret=0;
NFC_AppDataInitStruct initstruct;
ret = NFC_GetAppDataInitStruct(&initstruct);
if(R_FAILED(ret))return ret;
return NFC_InitializeWriteAppData(amiibo_appid, &initstruct, buf, size);
}
static Result NFC_InitializeWriteAppData(u32 amiibo_appid, NFC_AppDataInitStruct *initstruct, const void *buf, size_t size)
{
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x14,14,4); // 0x140384
cmdbuf[1]=amiibo_appid;
cmdbuf[2]=size;
memcpy(&cmdbuf[3], initstruct->data_xc, sizeof(initstruct->data_xc));
cmdbuf[15]=IPC_Desc_CurProcessHandle();
cmdbuf[17]=IPC_Desc_StaticBuffer(size, 0);
cmdbuf[18]=(u32)buf;
Result ret=0;
if(R_FAILED(ret=svcSendSyncRequest(nfcHandle)))return ret;
return cmdbuf[1];
}
Result nfcReadAppData(void *buf, size_t size)
{
u32* cmdbuf=getThreadCommandBuffer();
u32 saved_threadstorage[2];
cmdbuf[0]=IPC_MakeHeader(0x15,1,0); // 0x150040
cmdbuf[1]=size;
u32 * staticbufs = getThreadStaticBuffers();
saved_threadstorage[0] = staticbufs[0];
saved_threadstorage[1] = staticbufs[1];
staticbufs[0] = IPC_Desc_StaticBuffer(size,0);
staticbufs[1] = (u32)buf;
Result ret=0;
ret=svcSendSyncRequest(nfcHandle);
staticbufs[0] = saved_threadstorage[0];
staticbufs[1] = saved_threadstorage[1];
if(R_FAILED(ret))return ret;
ret = cmdbuf[1];
return ret;
}
Result nfcWriteAppData(const void *buf, size_t size, NFC_TagInfo *taginfo)
{
u32* cmdbuf=getThreadCommandBuffer();
NFC_AppDataWriteStruct writestruct;
cmdbuf[0]=IPC_MakeHeader(0x16,9,2); // 0x160242
cmdbuf[1]=size;
cmdbuf[10]=IPC_Desc_StaticBuffer(size, 0);
cmdbuf[11]=(u32)buf;
if(taginfo==NULL)return -1;
if(taginfo->id_offset_size>10)return -2;
memset(&writestruct, 0, sizeof(NFC_AppDataWriteStruct));
writestruct.id_size = taginfo->id_offset_size;
memcpy(writestruct.id, taginfo->id, sizeof(writestruct.id));
memcpy(&cmdbuf[2], &writestruct, sizeof(NFC_AppDataWriteStruct));
Result ret=0;
if(R_FAILED(ret=svcSendSyncRequest(nfcHandle)))return ret;
return cmdbuf[1];
}
Result nfcGetAmiiboSettings(NFC_AmiiboSettings *out)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x17,0,0); // 0x170000
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
if(R_SUCCEEDED(ret) && out)memcpy(out, &cmdbuf[2], sizeof(NFC_AmiiboSettings));
return ret;
}
Result nfcGetAmiiboConfig(NFC_AmiiboConfig *out)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x18,0,0); // 0x180000
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
if(R_SUCCEEDED(ret) && out)memcpy(out, &cmdbuf[2], sizeof(NFC_AmiiboConfig));
return ret;
}
static Result NFC_GetAppDataInitStruct(NFC_AppDataInitStruct *out)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x19,0,0); // 0x190000
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
if(R_SUCCEEDED(ret) && out)memcpy(out, &cmdbuf[2], sizeof(NFC_AppDataInitStruct));
return ret;
}
static Result NFC_StartOtherTagScanning(u16 unk0, u32 unk1)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x1F,2,0); // 0x1F0080
cmdbuf[1] = unk0;
cmdbuf[2] = unk1;
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
return ret;
}
Result nfcSendTagCommand(const void *inbuf, size_t insize, void *outbuf, size_t outsize, size_t *actual_transfer_size, u64 microseconds)
{
u32* cmdbuf=getThreadCommandBuffer();
u32 saved_threadstorage[2];
cmdbuf[0]=IPC_MakeHeader(0x20,4,2); // 0x200102
cmdbuf[1]=insize;
cmdbuf[2]=outsize;
cmdbuf[3]=(u32)(microseconds);
cmdbuf[4]=(u32)(microseconds>>32);
cmdbuf[5]=IPC_Desc_StaticBuffer(insize,0);
cmdbuf[6]=(u32)inbuf;
u32 * staticbufs = getThreadStaticBuffers();
saved_threadstorage[0] = staticbufs[0];
saved_threadstorage[1] = staticbufs[1];
staticbufs[0] = IPC_Desc_StaticBuffer(outsize,0);
staticbufs[1] = (u32)outbuf;
Result ret=0;
ret=svcSendSyncRequest(nfcHandle);
staticbufs[0] = saved_threadstorage[0];
staticbufs[1] = saved_threadstorage[1];
if(R_FAILED(ret))return ret;
ret = cmdbuf[1];
if(actual_transfer_size)*actual_transfer_size = cmdbuf[2];
return ret;
}
Result nfcCmd21(void)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x21,0,0); // 0x210000
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
return ret;
}
Result nfcCmd22(void)
{
Result ret=0;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=IPC_MakeHeader(0x22,0,0); // 0x220000
if(R_FAILED(ret = svcSendSyncRequest(nfcHandle)))return ret;
ret = cmdbuf[1];
return ret;
}