libctru/libctru/source/services/hid.c

306 lines
6.1 KiB
C
Raw Normal View History

/*
_hid.c - Touch screen, buttons, gyroscope, accelerometer etc.
*/
2014-01-19 13:33:28 +01:00
#include <stdlib.h>
2014-08-16 23:48:05 +02:00
#include <string.h>
#include <3ds/types.h>
#include <3ds/result.h>
#include <3ds/svc.h>
#include <3ds/srv.h>
2015-11-11 05:33:37 +01:00
#include <3ds/allocator/mappable.h>
#include <3ds/synchronization.h>
#include <3ds/services/apt.h>
#include <3ds/services/hid.h>
#include <3ds/services/irrst.h>
2015-09-09 21:15:02 +02:00
#include <3ds/ipc.h>
2014-01-19 13:33:28 +01:00
Handle hidHandle;
Handle hidMemHandle;
Handle hidEvents[5];
vu32* hidSharedMem;
static u32 kOld, kHeld, kDown, kUp;
static touchPosition tPos;
static circlePosition cPos;
static accelVector aVec;
static angularRate gRate;
static int hidRefCount;
Result hidInit(void)
{
bool val=false;
Result ret=0;
if (AtomicPostIncrement(&hidRefCount)) return 0;
2014-08-21 22:59:42 +02:00
// Request service.
ret = srvGetServiceHandle(&hidHandle, "hid:USER");
if (R_FAILED(ret)) ret = srvGetServiceHandle(&hidHandle, "hid:SPVR");
if (R_FAILED(ret)) goto cleanup0;
2014-08-21 22:59:42 +02:00
// Get sharedmem handle.
if(R_FAILED(ret=HIDUSER_GetHandles(&hidMemHandle, &hidEvents[HIDEVENT_PAD0], &hidEvents[HIDEVENT_PAD1], &hidEvents[HIDEVENT_Accel], &hidEvents[HIDEVENT_Gyro], &hidEvents[HIDEVENT_DebugPad]))) goto cleanup1;
2015-10-04 01:33:48 +02:00
// Map HID shared memory.
hidSharedMem=(vu32*)mappableAlloc(0x2b0);
if(!hidSharedMem)
{
ret = -1;
goto cleanup1;
}
if(R_FAILED(ret=svcMapMemoryBlock(hidMemHandle, (u32)hidSharedMem, MEMPERM_READ, 0x10000000)))goto cleanup2;
APT_CheckNew3DS(&val);
if(val)
{
2015-10-04 01:33:48 +02:00
ret = irrstInit();
}
2014-08-21 22:59:42 +02:00
// Reset internal state.
kOld = kHeld = kDown = kUp = 0;
return ret;
cleanup2:
2014-08-21 22:59:42 +02:00
svcCloseHandle(hidMemHandle);
2015-10-04 01:33:48 +02:00
if(hidSharedMem != NULL)
{
mappableFree((void*) hidSharedMem);
hidSharedMem = NULL;
}
cleanup1:
2014-08-21 22:59:42 +02:00
svcCloseHandle(hidHandle);
cleanup0:
AtomicDecrement(&hidRefCount);
2014-08-21 22:59:42 +02:00
return ret;
}
void hidExit(void)
{
if (AtomicDecrement(&hidRefCount)) return;
2014-08-21 22:59:42 +02:00
// Unmap HID sharedmem and close handles.
bool val=false;
2014-10-30 05:26:58 +01:00
int i; for(i=0; i<5; i++)svcCloseHandle(hidEvents[i]);
2014-08-21 22:59:42 +02:00
svcUnmapMemoryBlock(hidMemHandle, (u32)hidSharedMem);
svcCloseHandle(hidMemHandle);
svcCloseHandle(hidHandle);
APT_CheckNew3DS(&val);
if(val)
{
irrstExit();
}
2015-10-04 01:33:48 +02:00
if(hidSharedMem != NULL)
{
mappableFree((void*) hidSharedMem);
hidSharedMem = NULL;
}
}
void hidWaitForEvent(HID_Event id, bool nextEvent)
{
if(id>=HIDEVENT_MAX)return;
if (nextEvent)
svcClearEvent(hidEvents[id]);
svcWaitSynchronization(hidEvents[id], U64_MAX);
if (!nextEvent)
svcClearEvent(hidEvents[id]);
}
u32 hidCheckSectionUpdateTime(vu32 *sharedmem_section, u32 id)
{
s64 tick0=0, tick1=0;
if(id==0)
{
tick0 = *((u64*)&sharedmem_section[0]);
tick1 = *((u64*)&sharedmem_section[2]);
if(tick0==tick1 || tick0<0 || tick1<0)return 1;
}
return 0;
}
void hidScanInput(void)
{
u32 Id=0;
kOld = kHeld;
irrstScanInput();
kHeld = 0;
memset(&cPos, 0, sizeof(circlePosition));
memset(&tPos, 0, sizeof(touchPosition));
memset(&aVec, 0, sizeof(accelVector));
memset(&gRate, 0, sizeof(angularRate));
Id = hidSharedMem[4];//PAD / circle-pad
if(Id>7)Id=7;
if(hidCheckSectionUpdateTime(hidSharedMem, Id)==0)
{
kHeld = hidSharedMem[10 + Id*4];
cPos = *(circlePosition*)&hidSharedMem[10 + Id*4 + 3];
}
Id = hidSharedMem[42 + 4];//Touch-screen
if(Id>7)Id=7;
if(hidCheckSectionUpdateTime(&hidSharedMem[42], Id)==0)
{
tPos = *(touchPosition*)&hidSharedMem[42 + 8 + Id*2];
if (hidSharedMem[42 + 8 + Id*2 + 1])
kHeld |= KEY_TOUCH;
}
kHeld |= irrstKeysHeld();
2014-08-21 22:59:42 +02:00
kDown = (~kOld) & kHeld;
kUp = kOld & (~kHeld);
Id = hidSharedMem[66 + 4];//Accelerometer
if(Id>7)Id=7;
if(hidCheckSectionUpdateTime(&hidSharedMem[66], Id)==0)
{
aVec = ((accelVector*)&hidSharedMem[66 + 8])[Id];
}
Id = hidSharedMem[86 + 4];//Gyroscope
if(Id>31)Id=31;
if(hidCheckSectionUpdateTime(&hidSharedMem[86], Id)==0)
{
gRate = ((angularRate*)&hidSharedMem[86 + 8])[Id];
}
}
u32 hidKeysHeld(void)
{
2014-08-21 22:59:42 +02:00
return kHeld;
}
u32 hidKeysDown(void)
{
2014-08-21 22:59:42 +02:00
return kDown;
}
u32 hidKeysUp(void)
{
2014-08-21 22:59:42 +02:00
return kUp;
}
void hidTouchRead(touchPosition* pos)
{
2014-08-21 22:59:42 +02:00
if (pos) *pos = tPos;
}
void hidCircleRead(circlePosition* pos)
{
2014-08-21 22:59:42 +02:00
if (pos) *pos = cPos;
}
void hidAccelRead(accelVector* vector)
{
if (vector) *vector = aVec;
}
void hidGyroRead(angularRate* rate)
{
if (rate) *rate = gRate;
}
Result HIDUSER_GetHandles(Handle* outMemHandle, Handle *eventpad0, Handle *eventpad1, Handle *eventaccel, Handle *eventgyro, Handle *eventdebugpad)
2014-01-19 13:33:28 +01:00
{
2014-08-21 22:59:42 +02:00
u32* cmdbuf=getThreadCommandBuffer();
2015-09-09 21:15:02 +02:00
cmdbuf[0]=IPC_MakeHeader(0xA,0,0); // 0xA0000
2014-08-21 22:59:42 +02:00
Result ret=0;
if(R_FAILED(ret=svcSendSyncRequest(hidHandle)))return ret;
2014-08-21 22:59:42 +02:00
if(outMemHandle)*outMemHandle=cmdbuf[3];
if(eventpad0)*eventpad0=cmdbuf[4];
if(eventpad1)*eventpad1=cmdbuf[5];
if(eventaccel)*eventaccel=cmdbuf[6];
if(eventgyro)*eventgyro=cmdbuf[7];
if(eventdebugpad)*eventdebugpad=cmdbuf[8];
2014-08-21 22:59:42 +02:00
return cmdbuf[1];
}
Result HIDUSER_EnableAccelerometer(void)
{
2014-08-21 22:59:42 +02:00
u32* cmdbuf=getThreadCommandBuffer();
2015-09-09 21:15:02 +02:00
cmdbuf[0]=IPC_MakeHeader(0x11,0,0); // 0x110000
2014-08-21 22:59:42 +02:00
Result ret=0;
if(R_FAILED(ret=svcSendSyncRequest(hidHandle)))return ret;
2014-08-21 22:59:42 +02:00
return cmdbuf[1];
}
Result HIDUSER_DisableAccelerometer(void)
{
2014-08-21 22:59:42 +02:00
u32* cmdbuf=getThreadCommandBuffer();
2015-09-09 21:15:02 +02:00
cmdbuf[0]=IPC_MakeHeader(0x12,0,0); // 0x120000
2014-08-21 22:59:42 +02:00
Result ret=0;
if(R_FAILED(ret=svcSendSyncRequest(hidHandle)))return ret;
2014-08-21 22:59:42 +02:00
return cmdbuf[1];
}
Result HIDUSER_EnableGyroscope(void)
{
2014-08-21 22:59:42 +02:00
u32* cmdbuf=getThreadCommandBuffer();
2015-09-09 21:15:02 +02:00
cmdbuf[0]=IPC_MakeHeader(0x13,0,0); // 0x130000
2014-08-21 22:59:42 +02:00
Result ret=0;
if(R_FAILED(ret=svcSendSyncRequest(hidHandle)))return ret;
2014-08-21 22:59:42 +02:00
return cmdbuf[1];
2014-01-19 13:33:28 +01:00
}
Result HIDUSER_DisableGyroscope(void)
2014-01-19 13:33:28 +01:00
{
2014-08-21 22:59:42 +02:00
u32* cmdbuf=getThreadCommandBuffer();
2015-09-09 21:15:02 +02:00
cmdbuf[0]=IPC_MakeHeader(0x14,0,0); // 0x140000
2014-08-21 22:59:42 +02:00
Result ret=0;
if(R_FAILED(ret=svcSendSyncRequest(hidHandle)))return ret;
2014-08-21 22:59:42 +02:00
return cmdbuf[1];
2014-01-19 13:33:28 +01:00
}
Result HIDUSER_GetGyroscopeRawToDpsCoefficient(float *coeff)
{
u32* cmdbuf=getThreadCommandBuffer();
2015-09-09 21:15:02 +02:00
cmdbuf[0]=IPC_MakeHeader(0x15,0,0); // 0x150000
Result ret=0;
if(R_FAILED(ret=svcSendSyncRequest(hidHandle)))return ret;
*coeff = *(float*)(cmdbuf+2);
return cmdbuf[1];
}
Result HIDUSER_GetSoundVolume(u8 *volume)
{
u32* cmdbuf=getThreadCommandBuffer();
2015-09-09 21:15:02 +02:00
cmdbuf[0]=IPC_MakeHeader(0x17,0,0); // 0x170000
Result ret=0;
if(R_FAILED(ret=svcSendSyncRequest(hidHandle)))return ret;
2015-11-11 05:33:37 +01:00
*volume = (u8)cmdbuf[2] & 0xFF;
return cmdbuf[1];
}