Merge branch 'refactor' of github.com:smealum/ctrulib into refactor

This commit is contained in:
smea 2014-10-23 22:12:08 -07:00
commit 40d35ee420
24 changed files with 1151 additions and 66 deletions

View File

@ -6,3 +6,8 @@ library for writing user mode arm11 code for the 3DS (CTR)
the goal with this is to create a very straightforward interface with the 3DS's OS. the goal with this is to create a very straightforward interface with the 3DS's OS.
it is not meant to provide higher level functions; to put things in perspective, the purpose of ctrulib would be to sit between the OS and a possible port of SDL rather than replace it. it is not meant to provide higher level functions; to put things in perspective, the purpose of ctrulib would be to sit between the OS and a possible port of SDL rather than replace it.
license
=======
you may do whatever the hell you want with ctrulib as long as you give proper credit to its authors. that includes making commercial games/apps that use ctrulib. i'd personally rather you didn't sell ctrulib itself, because that would not be nice of you, but i'm not a lawyer and it's not like i'm going to sue you.

139
examples/mic/Makefile Normal file
View File

@ -0,0 +1,139 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
ifeq ($(strip $(CTRULIB)),)
# THIS IS TEMPORARY - in the future it should be at $(DEVKITPRO)/libctru
$(error "Please set CTRULIB in your environment. export CTRULIB=<path to>libctru")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/3ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# SPECS is the directory containing the important build and link files
#---------------------------------------------------------------------------------
export TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore
CFLAGS := -g -Wall -O2 -mword-relocations -save-temps \
-fomit-frame-pointer -ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) \
-Wl,-Map,$(TARGET).map
LIBS := -lctru -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CTRULIB)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).3dsx $(TARGET).elf
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).3dsx : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

5
examples/mic/README.md Normal file
View File

@ -0,0 +1,5 @@
mic
=======
Example for using the microphone with ctrulib. Hold down the A button to record, the app will then play the recorded audio once the A button is released. Roughly 32 seconds of audio can be recorded with the default audiobuf size in this app.

View File

@ -0,0 +1,95 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <3ds.h>
int main()
{
u8 *framebuf;
u32 *sharedmem = NULL, sharedmem_size = 0x30000;
u8 *audiobuf;
u32 audiobuf_size = 0x100000, audiobuf_pos = 0;
u8 control=0x40;
srvInit();
aptInit();
gfxInit();
hidInit(NULL);
aptSetupEventHandler();
CSND_initialize(NULL);
sharedmem = (u32*)memalign(0x1000, sharedmem_size);
audiobuf = linearAlloc(audiobuf_size);
MIC_Initialize(sharedmem, sharedmem_size, control, 0, 3, 1, 1);//See mic.h.
APP_STATUS status;
while((status=aptGetStatus())!=APP_EXITING)
{
if(status==APP_RUNNING)
{
framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL);
hidScanInput();
if(hidKeysDown() & KEY_A)
{
audiobuf_pos = 0;
CSND_setchannel_playbackstate(0x8, 0);//Stop audio playback.
CSND_sharedmemtype0_cmdupdatestate(0);
MIC_SetRecording(1);
memset(framebuf, 0x20, 0x46500);
}
if((hidKeysHeld() & KEY_A) && audiobuf_pos < audiobuf_size)
{
audiobuf_pos+= MIC_ReadAudioData(&audiobuf[audiobuf_pos], audiobuf_size-audiobuf_pos, 1);
if(audiobuf_pos > audiobuf_size)audiobuf_pos = audiobuf_size;
memset(framebuf, 0x60, 0x46500);
}
if(hidKeysUp() & KEY_A)
{
MIC_SetRecording(0);
GSPGPU_FlushDataCache(NULL, audiobuf, audiobuf_pos);
CSND_playsound(0x8, CSND_LOOP_DISABLE, CSND_ENCODING_PCM16, 16000, (u32*)audiobuf, NULL, audiobuf_pos, 2, 0);
memset(framebuf, 0xe0, 0x46500);
gfxFlushBuffers();
gfxSwapBuffers();
framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL);
memset(framebuf, 0xe0, 0x46500);
}
gfxFlushBuffers();
gfxSwapBuffers();
}
else if(status == APP_SUSPENDING)
{
aptReturnToMenu();
}
else if(status == APP_SLEEPMODE)
{
aptWaitStatusEvent();
}
gspWaitForVBlank();
}
MIC_Shutdown();
CSND_shutdown();
hidExit();
gfxExit();
aptExit();
srvExit();
return 0;
}

View File

@ -17,7 +17,7 @@ include $(DEVKITARM)/base_rules
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
TARGET := ctru TARGET := ctru
BUILD := build BUILD := build
SOURCES := source source/services source/gpu SOURCES := source source/services source/gpu source/allocator
DATA := data DATA := data
INCLUDES := include INCLUDES := include

View File

@ -23,6 +23,7 @@ extern "C" {
#include <3ds/services/ir.h> #include <3ds/services/ir.h>
#include <3ds/services/ptm.h> #include <3ds/services/ptm.h>
#include <3ds/services/soc.h> #include <3ds/services/soc.h>
#include <3ds/services/mic.h>
#include <3ds/gpu/gx.h> #include <3ds/gpu/gx.h>
#include <3ds/gpu/gpu.h> #include <3ds/gpu/gpu.h>

View File

@ -9,6 +9,13 @@ void GPUCMD_Add(u32 cmd, u32* param, u32 paramlength);
void GPUCMD_AddSingleParam(u32 cmd, u32 param); void GPUCMD_AddSingleParam(u32 cmd, u32 param);
void GPUCMD_Finalize(); void GPUCMD_Finalize();
typedef enum
{
GPU_TEXUNIT0 = 0x1,
GPU_TEXUNIT1 = 0x2,
GPU_TEXUNIT2 = 0x4
} GPU_TEXUNIT;
typedef enum{ typedef enum{
GPU_RGBA8=0x0, GPU_RGBA8=0x0,
GPU_RGB8=0x1, GPU_RGB8=0x1,
@ -37,6 +44,54 @@ typedef enum
GPU_GEQUAL = 7 GPU_GEQUAL = 7
}GPU_TESTFUNC; }GPU_TESTFUNC;
typedef enum
{
GPU_BLEND_ADD = 0,
GPU_BLEND_SUBTRACT = 1,
GPU_BLEND_REVERSE_SUBTRACT = 2,
GPU_BLEND_MIN = 3,
GPU_BLEND_MAX = 4
} GPU_BLENDEQUATION;
typedef enum
{
GPU_ZERO = 0,
GPU_ONE = 1,
GPU_SRC_COLOR = 2,
GPU_ONE_MINUS_SRC_COLOR = 3,
GPU_DST_COLOR = 4,
GPU_ONE_MINUS_DST_COLOR = 5,
GPU_SRC_ALPHA = 6,
GPU_ONE_MINUS_SRC_ALPHA = 7,
GPU_DST_ALPHA = 8,
GPU_ONE_MINUS_DST_ALPHA = 9,
GPU_CONSTANT_COLOR = 10,
GPU_ONE_MINUS_CONSTANT_COLOR = 11,
GPU_CONSTANT_ALPHA = 12,
GPU_ONE_MINUS_CONSTANT_ALPHA = 13,
GPU_SRC_ALPHA_SATURATE = 14
} GPU_BLENDFACTOR;
typedef enum
{
GPU_LOGICOP_CLEAR = 0,
GPU_LOGICOP_AND = 1,
GPU_LOGICOP_AND_REVERSE = 2,
GPU_LOGICOP_COPY = 3,
GPU_LOGICOP_SET = 4,
GPU_LOGICOP_COPY_INVERTED = 5,
GPU_LOGICOP_NOOP = 6,
GPU_LOGICOP_INVERT = 7,
GPU_LOGICOP_NAND = 8,
GPU_LOGICOP_OR = 9,
GPU_LOGICOP_NOR = 10,
GPU_LOGICOP_XOR = 11,
GPU_LOGICOP_EQUIV = 12,
GPU_LOGICOP_AND_INVERTED = 13,
GPU_LOGICOP_OR_REVERSE = 14,
GPU_LOGICOP_OR_INVERTED = 15
} GPU_LOGICOP;
typedef enum{ typedef enum{
GPU_BYTE = 0, GPU_BYTE = 0,
GPU_UNSIGNED_BYTE = 1, GPU_UNSIGNED_BYTE = 1,
@ -84,14 +139,28 @@ typedef enum{
}GPU_Primitive_t; }GPU_Primitive_t;
void GPU_SetUniform(u32 startreg, u32* data, u32 numreg); void GPU_SetUniform(u32 startreg, u32* data, u32 numreg);
void GPU_SetViewport(u32* depthBuffer, u32* colorBuffer, u32 x, u32 y, u32 w, u32 h); void GPU_SetViewport(u32* depthBuffer, u32* colorBuffer, u32 x, u32 y, u32 w, u32 h);
void GPU_DepthRange(float nearVal, float farVal); void GPU_DepthRange(float nearVal, float farVal);
void GPU_SetAlphaTest(bool enable, GPU_TESTFUNC function, u8 ref);
void GPU_SetDepthTest(bool enable, GPU_TESTFUNC function, u8 ref); void GPU_SetDepthTest(bool enable, GPU_TESTFUNC function, u8 ref);
void GPU_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref); void GPU_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref);
void GPU_SetFaceCulling(GPU_CULLMODE mode); void GPU_SetFaceCulling(GPU_CULLMODE mode);
// these two can't be used together
void GPU_SetAlphaBlending(GPU_BLENDEQUATION colorEquation, GPU_BLENDEQUATION alphaEquation,
GPU_BLENDFACTOR colorSrc, GPU_BLENDFACTOR colorDst,
GPU_BLENDFACTOR alphaSrc, GPU_BLENDFACTOR alphaDst);
void GPU_SetColorLogicOp(GPU_LOGICOP op);
void GPU_SetAttributeBuffers(u8 totalAttributes, u32* baseAddress, u64 attributeFormats, u16 attributeMask, u64 attributePermutation, u8 numBuffers, u32 bufferOffsets[], u64 bufferPermutations[], u8 bufferNumAttributes[]); void GPU_SetAttributeBuffers(u8 totalAttributes, u32* baseAddress, u64 attributeFormats, u16 attributeMask, u64 attributePermutation, u8 numBuffers, u32 bufferOffsets[], u64 bufferPermutations[], u8 bufferNumAttributes[]);
void GPU_SetTexture(u32* data, u16 width, u16 height, u32 param, GPU_TEXCOLOR colorType);
void GPU_SetTextureEnable(GPU_TEXUNIT units); // GPU_TEXUNITx values can be ORed together to enable multiple texture units
void GPU_SetTexture(GPU_TEXUNIT unit, u32* data, u16 width, u16 height, u32 param, GPU_TEXCOLOR colorType);
void GPU_SetTexEnv(u8 id, u16 rgbSources, u16 alphaSources, u16 rgbOperands, u16 alphaOperands, GPU_COMBINEFUNC rgbCombine, GPU_COMBINEFUNC alphaCombine, u32 constantColor); void GPU_SetTexEnv(u8 id, u16 rgbSources, u16 alphaSources, u16 rgbOperands, u16 alphaOperands, GPU_COMBINEFUNC rgbCombine, GPU_COMBINEFUNC alphaCombine, u32 constantColor);
void GPU_DrawArray(GPU_Primitive_t primitive, u32 n); void GPU_DrawArray(GPU_Primitive_t primitive, u32 n);
void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n); void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n);
void GPU_FinishDrawing();

View File

@ -7,3 +7,4 @@ u32 osConvertVirtToPhys(u32 vaddr);
const char* osStrError(u32 error); const char* osStrError(u32 error);
u32 osGetFirmVersion(); u32 osGetFirmVersion();
u32 osGetKernelVersion(); u32 osGetKernelVersion();
u64 osGetTime();

View File

@ -48,6 +48,7 @@ u32 aptGetStatusPower();//This can be used when the status is APP_SUSPEND* to ch
void aptSetStatusPower(u32 status); void aptSetStatusPower(u32 status);
void aptReturnToMenu();//This should be called by the user application when aptGetStatus() returns APP_SUSPENDING, not calling this will result in return-to-menu being disabled with the status left at APP_SUSPENDING. This function will not return until the system returns to the application, or when the status was changed to APP_EXITING. void aptReturnToMenu();//This should be called by the user application when aptGetStatus() returns APP_SUSPENDING, not calling this will result in return-to-menu being disabled with the status left at APP_SUSPENDING. This function will not return until the system returns to the application, or when the status was changed to APP_EXITING.
void aptWaitStatusEvent(); void aptWaitStatusEvent();
void aptSignalReadyForSleep();
NS_APPID aptGetMenuAppID(); NS_APPID aptGetMenuAppID();
Result APT_GetLockHandle(Handle* handle, u16 flags, Handle* lockHandle); Result APT_GetLockHandle(Handle* handle, u16 flags, Handle* lockHandle);
@ -67,3 +68,5 @@ Result APT_ReplySleepQuery(Handle* handle, NS_APPID appID, u32 a);
Result APT_ReplySleepNotificationComplete(Handle* handle, NS_APPID appID); Result APT_ReplySleepNotificationComplete(Handle* handle, NS_APPID appID);
Result APT_PrepareToCloseApplication(Handle* handle, u8 a); Result APT_PrepareToCloseApplication(Handle* handle, u8 a);
Result APT_CloseApplication(Handle* handle, u32 a, u32 b, u32 c); Result APT_CloseApplication(Handle* handle, u32 a, u32 b, u32 c);
Result APT_SetAppCpuTimeLimit(Handle* handle, u32 percent);
Result APT_GetAppCpuTimeLimit(Handle* handle, u32 *percent);

View File

@ -37,12 +37,12 @@ typedef struct
typedef enum typedef enum
{ {
GSPEVENT_PSC0 = 0, GSPEVENT_PSC0 = 0, // memory fill completed
GSPEVENT_PSC1, GSPEVENT_PSC1,
GSPEVENT_VBlank0, GSPEVENT_VBlank0,
GSPEVENT_VBlank1, GSPEVENT_VBlank1,
GSPEVENT_PPF, GSPEVENT_PPF, // display transfer finished
GSPEVENT_P3D, GSPEVENT_P3D, // command list processing finished
GSPEVENT_DMA, GSPEVENT_DMA,
GSPEVENT_MAX, // used to know how many events there are GSPEVENT_MAX, // used to know how many events there are

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
//See also: http://3dbrew.org/wiki/HID_Services http://3dbrew.org/wiki/HID_Shared_Memory
#define HID_SHAREDMEM_DEFAULT (0x10000000) #define HID_SHAREDMEM_DEFAULT (0x10000000)
typedef enum typedef enum
@ -39,6 +41,31 @@ typedef struct
s16 dx, dy; s16 dx, dy;
} circlePosition; } circlePosition;
typedef struct
{
s16 x;
s16 y;
s16 z;
} accelVector;
typedef struct
{
s16 x;//roll
s16 z;//yaw
s16 y;//pitch
} angularRate;
typedef enum
{
HIDEVENT_PAD0 = 0, //"Event signaled by HID-module, when the sharedmem+0(PAD/circle-pad)/+0xA8(touch-screen) region was updated."
HIDEVENT_PAD1, //"Event signaled by HID-module, when the sharedmem+0(PAD/circle-pad)/+0xA8(touch-screen) region was updated."
HIDEVENT_Accel, //"Event signaled by HID-module, when the sharedmem accelerometer state was updated."
HIDEVENT_Gyro, //"Event signaled by HID-module, when the sharedmem gyroscope state was updated."
HIDEVENT_DebugPad, //"Event signaled by HID-module, when the sharedmem DebugPad state was updated."
HIDEVENT_MAX, // used to know how many events there are
} HID_Event;
extern Handle hidMemHandle; extern Handle hidMemHandle;
extern vu32* hidSharedMem; extern vu32* hidSharedMem;
@ -51,6 +78,10 @@ u32 hidKeysDown();
u32 hidKeysUp(); u32 hidKeysUp();
void hidTouchRead(touchPosition* pos); void hidTouchRead(touchPosition* pos);
void hidCircleRead(circlePosition* pos); void hidCircleRead(circlePosition* pos);
void hidAccelRead(accelVector* vector);
void hidGyroRead(angularRate* rate);
void hidWaitForEvent(HID_Event id, bool nextEvent);
// libnds compatibility defines // libnds compatibility defines
#define scanKeys hidScanInput #define scanKeys hidScanInput
@ -60,8 +91,9 @@ void hidCircleRead(circlePosition* pos);
#define touchRead hidTouchRead #define touchRead hidTouchRead
#define circleRead hidCircleRead #define circleRead hidCircleRead
Result HIDUSER_GetSharedMem(Handle* outMemHandle); Result HIDUSER_GetHandles(Handle* outMemHandle, Handle *eventpad0, Handle *eventpad1, Handle *eventaccel, Handle *eventgyro, Handle *eventdebugpad);
Result HIDUSER_EnableAccelerometer(); Result HIDUSER_EnableAccelerometer();
Result HIDUSER_DisableAccelerometer(); Result HIDUSER_DisableAccelerometer();
Result HIDUSER_EnableGyroscope(); Result HIDUSER_EnableGyroscope();
Result HIDUSER_DisableGyroscope(); Result HIDUSER_DisableGyroscope();

View File

@ -0,0 +1,20 @@
#pragma once
//See also: http://3dbrew.org/wiki/MIC_Services
Result MIC_Initialize(u32 *sharedmem, u32 sharedmem_size, u8 control, u8 recording, u8 unk0, u8 unk1, u8 unk2);//sharedmem_size = audiodata size + 4, aligned to 0x1000-bytes. The sharedmem ptr must be 0x1000-bytes aligned. The offical 3ds-sound app uses the following values for unk0-unk2: 3, 1, and 1.
Result MIC_Shutdown();
u32 MIC_GetSharedMemOffsetValue();
u32 MIC_ReadAudioData(u8 *outbuf, u32 readsize, u32 waitforevent);//Reads MIC audio data. When waitforevent is non-zero, this clears the event, then waits for MIC-module to signal it again when audio data is written to shared-mem. The return value is the actual byte-size of the read data.
Result MIC_MapSharedMem(Handle handle, u32 size);
Result MIC_UnmapSharedMem();
Result MIC_cmd3_Initialize(u8 unk0, u8 unk1, u32 sharedmem_baseoffset, u32 sharedmem_endoffset, u8 unk2);
Result MIC_cmd5();
Result MIC_GetCNTBit15(u8 *out);
Result MIC_GetEventHandle(Handle *handle);
Result MIC_SetControl(u8 value);//See here: http://3dbrew.org/wiki/MIC_Services
Result MIC_GetControl(u8 *value);
Result MIC_SetRecording(u8 value);
Result MIC_IsRecoding(u8 *value);

View File

@ -0,0 +1,50 @@
#include <3ds.h>
#include "mem_pool.h"
extern u32 __linear_heap, __linear_heap_size;
static MemPool sLinearPool;
static bool linearInit()
{
auto blk = MemBlock::Create((u8*)__linear_heap, __linear_heap_size);
if (blk)
{
sLinearPool.AddBlock(blk);
return true;
}
return false;
}
void* linearAlloc(size_t size)
{
// Initialize the pool if it is not ready
if (!sLinearPool.Ready() && !linearInit())
return nullptr;
// Reserve memory for MemChunk structure
size += 16;
// Allocate the chunk
MemChunk chunk;
if (!sLinearPool.Allocate(chunk, size, 4)) // 16-byte alignment
return nullptr;
// Copy the MemChunk structure and return memory
auto addr = chunk.addr;
*(MemChunk*)addr = chunk;
return addr + 16;
}
void* linearRealloc(void* mem, size_t size)
{
// TODO
return NULL;
}
void linearFree(void* mem)
{
// Find MemChunk structure and free the chunk
auto pChunk = (MemChunk*)((u8*)mem - 16);
sLinearPool.Deallocate(*pChunk);
}

View File

@ -0,0 +1,125 @@
#include "mem_pool.h"
/*
// This method is currently unused
void MemPool::CoalesceLeft(MemBlock* b)
{
auto curPtr = b->base;
for (auto p = b->prev; p; p = p->prev)
{
if ((p->base + p->size) != curPtr) break;
curPtr = p->base;
p->size += b->size;
DelBlock(b);
b = p;
}
}
*/
void MemPool::CoalesceRight(MemBlock* b)
{
auto curPtr = b->base + b->size;
auto next = b->next;
for (auto n = next; n; n = next)
{
next = n->next;
if (n->base != curPtr) break;
b->size += n->size;
curPtr += n->size;
DelBlock(n);
}
}
bool MemPool::Allocate(MemChunk& chunk, u32 size, int align)
{
int alignM = (1 << align) - 1;
size = (size + alignM) &~ alignM; // Round the size
// Find the first suitable block
for (auto b = first; b; b = b->next)
{
auto addr = b->base;
u32 begWaste = (u32)addr & alignM;
addr += begWaste;
u32 bSize = b->size - begWaste;
if (bSize < size) continue;
// Found space!
chunk.addr = addr;
chunk.size = size;
// Resize the block
if (!begWaste)
{
b->base += size;
b->size -= size;
if (!b->size)
DelBlock(b);
} else
{
auto nAddr = addr + size;
auto nSize = bSize - size;
b->size = begWaste;
if (nSize)
{
// We need to add the tail chunk that wasn't used to the list
auto n = MemBlock::Create(nAddr, nSize);
if (n) InsertAfter(b, n);
else chunk.size += nSize; // we have no choice but to waste the space.
}
}
return true;
}
return false;
}
void MemPool::Deallocate(const MemChunk& chunk)
{
u8* cAddr = chunk.addr;
auto cSize = chunk.size;
bool done = false;
// Try to merge the chunk somewhere into the list
for (auto b = first; !done && b; b = b->next)
{
auto addr = b->base;
if (addr > cAddr)
{
if ((cAddr + cSize) == addr)
{
// Merge the chunk to the left of the block
b->base = cAddr;
b->size += cSize;
} else
{
// We need to insert a new block
auto c = MemBlock::Create(cAddr, cSize);
if (c) InsertBefore(b, c);
}
done = true;
} else if ((b->base + b->size) == cAddr)
{
// Coalesce to the right
b->size += cSize;
CoalesceRight(b);
done = true;
}
}
if (!done)
{
// Either the list is empty or the chunk address is past the end
// address of the last block -- let's add a new block at the end
auto b = MemBlock::Create(cAddr, cSize);
if (b) AddBlock(b);
}
}
/*
void MemPool::Dump(const char* title)
{
printf("<%s> VRAM Pool Dump\n", title);
for (auto b = first; b; b = b->next)
printf(" - %p (%u bytes)\n", b->base, b->size);
}
*/

View File

@ -0,0 +1,88 @@
#pragma once
#include <3ds.h>
struct MemChunk
{
u8* addr;
u32 size;
};
struct MemBlock
{
MemBlock *prev, *next;
u8* base;
u32 size;
static MemBlock* Create(u8* base, u32 size)
{
auto b = (MemBlock*)malloc(sizeof(MemBlock));
if (!b) return nullptr;
b->prev = nullptr;
b->next = nullptr;
b->base = base;
b->size = size;
return b;
}
};
struct MemPool
{
MemBlock *first, *last;
bool Ready() { return first != nullptr; }
void AddBlock(MemBlock* blk)
{
blk->prev = last;
if (last) last->next = blk;
if (!first) first = blk;
last = blk;
}
void DelBlock(MemBlock* b)
{
auto prev = b->prev, &pNext = prev ? prev->next : first;
auto next = b->next, &nPrev = next ? next->prev : last;
pNext = next;
nPrev = prev;
free(b);
}
void InsertBefore(MemBlock* b, MemBlock* p)
{
auto prev = b->prev, &pNext = prev ? prev->next : first;
b->prev = p;
p->next = b;
p->prev = prev;
pNext = p;
}
void InsertAfter(MemBlock* b, MemBlock* n)
{
auto next = b->next, &nPrev = next ? next->prev : last;
b->next = n;
n->prev = b;
n->next = next;
nPrev = n;
}
//void CoalesceLeft(MemBlock* b);
void CoalesceRight(MemBlock* b);
bool Allocate(MemChunk& chunk, u32 size, int align);
void Deallocate(const MemChunk& chunk);
void Destroy()
{
MemBlock* next = nullptr;
for (auto b = first; b; b = next)
{
next = b->next;
free(b);
}
first = nullptr;
last = nullptr;
}
//void Dump(const char* title);
};

View File

@ -65,6 +65,9 @@ void GPUCMD_AddSingleParam(u32 cmd, u32 param)
void GPUCMD_Finalize() void GPUCMD_Finalize()
{ {
GPUCMD_AddSingleParam(0x0008025E, 0x00000000);
GPUCMD_AddSingleParam(0x000F0111, 0x00000001);
GPUCMD_AddSingleParam(0x000F0110, 0x00000001);
GPUCMD_AddSingleParam(0x000F0010, 0x12345678); GPUCMD_AddSingleParam(0x000F0010, 0x12345678);
} }
@ -272,7 +275,7 @@ void GPU_SetViewport(u32* depthBuffer, u32* colorBuffer, u32 x, u32 y, u32 w, u3
GPUCMD_Add(0x800F0065, param, 0x00000003); GPUCMD_Add(0x800F0065, param, 0x00000003);
//enable depth buffer //enable depth buffer
param[0x0]=0x00000000; param[0x0]=0x0000000F;
param[0x1]=0x0000000F; param[0x1]=0x0000000F;
param[0x2]=0x00000002; param[0x2]=0x00000002;
param[0x3]=0x00000002; param[0x3]=0x00000002;
@ -286,6 +289,11 @@ void GPU_DepthRange(float nearVal, float farVal)
GPUCMD_AddSingleParam(0x000F004E, f32tof24(farVal)); GPUCMD_AddSingleParam(0x000F004E, f32tof24(farVal));
} }
void GPU_SetAlphaTest(bool enable, GPU_TESTFUNC function, u8 ref)
{
GPUCMD_AddSingleParam(0x000F0104, (enable&1)|((function&7)<<4)|(ref<<8));
}
void GPU_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref) void GPU_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref)
{ {
GPUCMD_AddSingleParam(0x000F0105, (enable&1)|((function&7)<<4)|(ref<<8)); GPUCMD_AddSingleParam(0x000F0105, (enable&1)|((function&7)<<4)|(ref<<8));
@ -296,12 +304,54 @@ void GPU_SetDepthTest(bool enable, GPU_TESTFUNC function, u8 ref)
GPUCMD_AddSingleParam(0x000F0107, (enable&1)|((function&7)<<4)|(ref<<8)); GPUCMD_AddSingleParam(0x000F0107, (enable&1)|((function&7)<<4)|(ref<<8));
} }
void GPU_SetTexture(u32* data, u16 width, u16 height, u32 param, GPU_TEXCOLOR colorType) void GPU_SetAlphaBlending(GPU_BLENDEQUATION colorEquation, GPU_BLENDEQUATION alphaEquation,
GPU_BLENDFACTOR colorSrc, GPU_BLENDFACTOR colorDst,
GPU_BLENDFACTOR alphaSrc, GPU_BLENDFACTOR alphaDst)
{ {
GPUCMD_AddSingleParam(0x000F008E, colorType); // TODO: fixed color
GPUCMD_AddSingleParam(0x000F0085, ((u32)data)>>3); // it is controlled by command 0103 but I haven't found were to place said command without freezing the GPU
GPUCMD_AddSingleParam(0x000F0082, (width)|(height<<16));
GPUCMD_AddSingleParam(0x000F0083, param); GPUCMD_AddSingleParam(0x000F0101, colorEquation | (alphaEquation<<8) | (colorSrc<<16) | (colorDst<<20) | (alphaSrc<<24) | (alphaDst<<28));
GPUCMD_AddSingleParam(0x00020100, 0x00000100);
}
void GPU_SetColorLogicOp(GPU_LOGICOP op)
{
GPUCMD_AddSingleParam(0x000F0102, op);
GPUCMD_AddSingleParam(0x00020100, 0x00000000);
}
void GPU_SetTextureEnable(GPU_TEXUNIT units)
{
GPUCMD_AddSingleParam(0x0002006F, units<<8); // enables texcoord outputs
GPUCMD_AddSingleParam(0x000F0080, 0x00011000|units); // enables texture units
}
void GPU_SetTexture(GPU_TEXUNIT unit, u32* data, u16 width, u16 height, u32 param, GPU_TEXCOLOR colorType)
{
switch (unit)
{
case GPU_TEXUNIT0:
GPUCMD_AddSingleParam(0x000F008E, colorType);
GPUCMD_AddSingleParam(0x000F0085, ((u32)data)>>3);
GPUCMD_AddSingleParam(0x000F0082, (width)|(height<<16));
GPUCMD_AddSingleParam(0x000F0083, param);
break;
case GPU_TEXUNIT1:
GPUCMD_AddSingleParam(0x000F0096, colorType);
GPUCMD_AddSingleParam(0x000F0095, ((u32)data)>>3);
GPUCMD_AddSingleParam(0x000F0092, (width)|(height<<16));
GPUCMD_AddSingleParam(0x000F0093, param);
break;
case GPU_TEXUNIT2:
GPUCMD_AddSingleParam(0x000F009E, colorType);
GPUCMD_AddSingleParam(0x000F009D, ((u32)data)>>3);
GPUCMD_AddSingleParam(0x000F009A, (width)|(height<<16));
GPUCMD_AddSingleParam(0x000F009B, param);
break;
}
} }
const u8 GPU_FORMATSIZE[4]={1,1,2,4}; const u8 GPU_FORMATSIZE[4]={1,1,2,4};
@ -385,7 +435,6 @@ void GPU_DrawArray(GPU_Primitive_t primitive, u32 n)
GPUCMD_AddSingleParam(0x000F0231, 0x00000001); GPUCMD_AddSingleParam(0x000F0231, 0x00000001);
GPUCMD_AddSingleParam(0x000F0111, 0x00000001); GPUCMD_AddSingleParam(0x000F0111, 0x00000001);
GPUCMD_AddSingleParam(0x000F0110, 0x00000001);
} }
void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n) void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n)
@ -405,4 +454,13 @@ void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n)
GPUCMD_AddSingleParam(0x000F022F, 0x00000001); GPUCMD_AddSingleParam(0x000F022F, 0x00000001);
GPUCMD_AddSingleParam(0x00010245, 0x00000001); GPUCMD_AddSingleParam(0x00010245, 0x00000001);
GPUCMD_AddSingleParam(0x000F0231, 0x00000001); GPUCMD_AddSingleParam(0x000F0231, 0x00000001);
// CHECKME: does this one also require command 0x0111 at the end?
}
void GPU_FinishDrawing()
{
GPUCMD_AddSingleParam(0x000F0111, 0x00000001);
GPUCMD_AddSingleParam(0x000F0110, 0x00000001);
GPUCMD_AddSingleParam(0x000F0063, 0x00000001);
} }

View File

@ -1,32 +0,0 @@
#include <3ds.h>
extern u32 __linear_heap, __linear_heap_size;
// TODO: this allocator sucks! It is not thread-safe and you cannot 'free' this memory.
void* linearAlloc(size_t size)
{
static size_t currentOffset = 0;
size_t free = __linear_heap_size - currentOffset;
// Enforce 8-byte alignment
size = (size + 7) &~ 7;
void* mem = NULL;
if (free >= size)
{
mem = (void*)(__linear_heap + currentOffset);
currentOffset += size;
}
return mem;
}
void* linearRealloc(void* mem, size_t size)
{
return NULL; // TODO
}
void linearFree(void* mem)
{
// TODO
}

View File

@ -1,5 +1,21 @@
#include <3ds.h> #include <3ds.h>
#define TICKS_PER_MSEC 268123.480
typedef struct {
u64 date_time;
u64 update_tick;
//...
} datetime_t;
static volatile u32* __datetime_selector =
(u32*) 0x1FF81000;
static volatile datetime_t* __datetime1 =
(datetime_t*) 0x1FF81020;
static volatile datetime_t* __datetime2 =
(datetime_t*) 0x1FF81040;
u32 osConvertVirtToPhys(u32 vaddr) u32 osConvertVirtToPhys(u32 vaddr)
{ {
if(vaddr >= 0x14000000 && vaddr < 0x1c000000) if(vaddr >= 0x14000000 && vaddr < 0x1c000000)
@ -13,6 +29,21 @@ u32 osConvertVirtToPhys(u32 vaddr)
return 0; return 0;
} }
// Returns number of milliseconds since 1st Jan 1900 00:00.
u64 osGetTime() {
volatile datetime_t* dt;
switch(*__datetime_selector & 1) {
case 0:
dt = __datetime1;
case 1:
dt = __datetime2;
}
u64 offset = (svcGetSystemTick() - dt->update_tick) / TICKS_PER_MSEC;
return dt->date_time + offset;
}
u32 osGetFirmVersion() { u32 osGetFirmVersion() {
return (*(u32*)0x1FF80000) & ~0xFF; return (*(u32*)0x1FF80000) & ~0xFF;
} }

View File

@ -26,6 +26,7 @@ Handle aptStatusEvent = 0;
APP_STATUS aptStatus = APP_NOTINITIALIZED; APP_STATUS aptStatus = APP_NOTINITIALIZED;
APP_STATUS aptStatusBeforeSleep = APP_NOTINITIALIZED; APP_STATUS aptStatusBeforeSleep = APP_NOTINITIALIZED;
u32 aptStatusPower = 0; u32 aptStatusPower = 0;
Handle aptSleepSync = 0;
u32 aptParameters[0x1000/4]; //TEMP u32 aptParameters[0x1000/4]; //TEMP
@ -204,21 +205,24 @@ static void __handle_notification() {
case APTSIGNAL_PREPARESLEEP: case APTSIGNAL_PREPARESLEEP:
// Reply to sleep-request. // Reply to sleep-request.
aptStatusBeforeSleep = aptGetStatus(); aptStatusBeforeSleep = aptGetStatus();
aptSetStatus(APP_PREPARE_SLEEPMODE);
svcWaitSynchronization(aptSleepSync, U64_MAX);
svcClearEvent(aptSleepSync);
aptOpenSession(); aptOpenSession();
APT_ReplySleepQuery(NULL, currentAppId, 0x1); APT_ReplySleepQuery(NULL, currentAppId, 0x1);
aptCloseSession(); aptCloseSession();
aptSetStatus(APP_PREPARE_SLEEPMODE);
break; break;
case APTSIGNAL_ENTERSLEEP: case APTSIGNAL_ENTERSLEEP:
if(aptGetStatus() == APP_PREPARE_SLEEPMODE) if(aptGetStatus() == APP_PREPARE_SLEEPMODE)
{ {
// Report into sleep-mode. // Report into sleep-mode.
aptSetStatus(APP_SLEEPMODE);
aptOpenSession(); aptOpenSession();
APT_ReplySleepNotificationComplete(NULL, currentAppId); APT_ReplySleepNotificationComplete(NULL, currentAppId);
aptCloseSession(); aptCloseSession();
aptSetStatus(APP_SLEEPMODE);
} }
break; break;
@ -319,6 +323,7 @@ Result aptInit(void)
} }
svcCreateEvent(&aptStatusEvent, 0); svcCreateEvent(&aptStatusEvent, 0);
svcCreateEvent(&aptSleepSync, 0);
return 0; return 0;
} }
@ -345,6 +350,8 @@ void aptExit()
aptCloseSession(); aptCloseSession();
} }
svcCloseHandle(aptSleepSync);
svcCloseHandle(aptStatusMutex); svcCloseHandle(aptStatusMutex);
//svcCloseHandle(aptLockHandle); //svcCloseHandle(aptLockHandle);
svcCloseHandle(aptStatusEvent); svcCloseHandle(aptStatusEvent);
@ -421,7 +428,7 @@ void aptSetStatus(APP_STATUS status)
svcWaitSynchronization(aptStatusMutex, U64_MAX); svcWaitSynchronization(aptStatusMutex, U64_MAX);
prevstatus = status; prevstatus = aptStatus;
aptStatus = status; aptStatus = status;
if(prevstatus != APP_NOTINITIALIZED) if(prevstatus != APP_NOTINITIALIZED)
@ -461,6 +468,11 @@ void aptCloseSession()
svcReleaseMutex(aptLockHandle); svcReleaseMutex(aptLockHandle);
} }
void aptSignalReadyForSleep()
{
svcSignalEvent(aptSleepSync);
}
Result APT_GetLockHandle(Handle* handle, u16 flags, Handle* lockHandle) Result APT_GetLockHandle(Handle* handle, u16 flags, Handle* lockHandle)
{ {
if(!handle)handle=&aptuHandle; if(!handle)handle=&aptuHandle;
@ -743,3 +755,35 @@ Result APT_CloseApplication(Handle* handle, u32 a, u32 b, u32 c)
return cmdbuf[1]; return cmdbuf[1];
} }
//See http://3dbrew.org/APT:SetApplicationCpuTimeLimit
Result APT_SetAppCpuTimeLimit(Handle* handle, u32 percent)
{
if(!handle)handle=&aptuHandle;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=0x4F0080;
cmdbuf[1]=1;
cmdbuf[2]=percent;
Result ret=0;
if((ret=svcSendSyncRequest(*handle)))return ret;
return cmdbuf[1];
}
Result APT_GetAppCpuTimeLimit(Handle* handle, u32 *percent)
{
if(!handle)handle=&aptuHandle;
u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=0x500040;
cmdbuf[1]=1;
Result ret=0;
if((ret=svcSendSyncRequest(*handle)))return ret;
if(percent)*percent=cmdbuf[2];
return cmdbuf[1];
}

View File

@ -285,7 +285,11 @@ Result CSND_playsound(u32 channel, u32 looping, u32 encoding, u32 samplerate, u3
CSND_sharedmemtype0_cmde(channel, looping, encoding, samplerate, unk0, unk1, physaddr0, physaddr1, totalbytesize); CSND_sharedmemtype0_cmde(channel, looping, encoding, samplerate, unk0, unk1, physaddr0, physaddr1, totalbytesize);
CSND_sharedmemtype0_cmd8(channel, samplerate); CSND_sharedmemtype0_cmd8(channel, samplerate);
if(looping)CSND_sharedmemtype0_cmd3(channel, physaddr0, totalbytesize); if(looping)
{
if(physaddr1>physaddr0)totalbytesize-= (u32)physaddr1 - (u32)physaddr0;
CSND_sharedmemtype0_cmd3(channel, physaddr1, totalbytesize);
}
CSND_sharedmemtype0_cmd8(channel, samplerate); CSND_sharedmemtype0_cmd8(channel, samplerate);
CSND_sharedmemtype0_cmd9(channel, 0xffff); CSND_sharedmemtype0_cmd9(channel, 0xffff);
CSND_setchannel_playbackstate(channel, 1); CSND_setchannel_playbackstate(channel, 1);

View File

@ -68,7 +68,7 @@ FSUSER_Initialize(Handle* handle)
{ {
// don't run command if we got handle from the list // don't run command if we got handle from the list
handle = &fsuHandle; handle = &fsuHandle;
if(fsuHandle != 0 && __get_handle_from_list("fs:USER")==0) if(fsuHandle != 0 && __get_handle_from_list("fs:USER")!=0)
return 0; return 0;
} }

View File

@ -68,6 +68,8 @@ void gspExitEventHandler()
void gspWaitForEvent(GSP_Event id, bool nextEvent) void gspWaitForEvent(GSP_Event id, bool nextEvent)
{ {
if(id>=GSPEVENT_MAX)return;
if (nextEvent) if (nextEvent)
svcClearEvent(gspEvents[id]); svcClearEvent(gspEvents[id]);
svcWaitSynchronization(gspEvents[id], U64_MAX); svcWaitSynchronization(gspEvents[id], U64_MAX);
@ -83,15 +85,15 @@ void gspEventThreadMain(u32 arg)
svcClearEvent(gspEvent); svcClearEvent(gspEvent);
int count = gspEventData[1]; int count = gspEventData[1];
int last = gspEventData[0] + count; int cur = gspEventData[0];
int last = cur + count;
while (last >= 0x34) last -= 0x34; while (last >= 0x34) last -= 0x34;
int cur = last;
int i; int i;
for (i = 0; i < count; i ++) for (i = 0; i < count; i ++)
{ {
int curEvt = gspEventData[0xC + cur]; int curEvt = gspEventData[0xC + cur];
cur --; cur ++;
if (cur < 0) cur += 0x34; if (cur >= 0x34) cur -= 0x34;
if (curEvt >= GSPEVENT_MAX) continue; if (curEvt >= GSPEVENT_MAX) continue;
svcSignalEvent(gspEvents[curEvt]); svcSignalEvent(gspEvents[curEvt]);
} }

View File

@ -8,11 +8,15 @@
Handle hidHandle; Handle hidHandle;
Handle hidMemHandle; Handle hidMemHandle;
Handle hidEvents[5];
vu32* hidSharedMem; vu32* hidSharedMem;
static u32 kOld, kHeld, kDown, kUp; static u32 kOld, kHeld, kDown, kUp;
static touchPosition tPos; static touchPosition tPos;
static circlePosition cPos; static circlePosition cPos;
static accelVector aVec;
static angularRate gRate;
Result hidInit(u32* sharedMem) Result hidInit(u32* sharedMem)
@ -24,7 +28,7 @@ Result hidInit(u32* sharedMem)
if((ret=srvGetServiceHandle(&hidHandle, "hid:USER")))return ret; if((ret=srvGetServiceHandle(&hidHandle, "hid:USER")))return ret;
// Get sharedmem handle. // Get sharedmem handle.
if((ret=HIDUSER_GetSharedMem(&hidMemHandle))) goto cleanup1; if((ret=HIDUSER_GetHandles(&hidMemHandle, &hidEvents[HIDEVENT_PAD0], &hidEvents[HIDEVENT_PAD1], &hidEvents[HIDEVENT_Accel], &hidEvents[HIDEVENT_Gyro], &hidEvents[HIDEVENT_DebugPad]))) goto cleanup1;
// Map HID shared memory at addr "sharedMem". // Map HID shared memory at addr "sharedMem".
hidSharedMem=sharedMem; hidSharedMem=sharedMem;
@ -49,23 +53,77 @@ void hidExit()
svcCloseHandle(hidHandle); svcCloseHandle(hidHandle);
} }
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 hidScanInput()
{ {
u32 Id=0;
kOld = kHeld; kOld = kHeld;
u32 padId = hidSharedMem[4]; kHeld = 0;
if(padId>7)padId=7; memset(&cPos, 0, sizeof(circlePosition));
kHeld = hidSharedMem[10 + padId*4]; memset(&tPos, 0, sizeof(touchPosition));
cPos = *(circlePosition*)&hidSharedMem[10 + padId*4 + 3]; memset(&aVec, 0, sizeof(accelVector));
memset(&gRate, 0, sizeof(angularRate));
u32 touchId = hidSharedMem[42 + 4]; Id = hidSharedMem[4];//PAD / circle-pad
if(touchId>7)touchId=7; if(Id>7)Id=7;
tPos = *(touchPosition*)&hidSharedMem[42 + 8 + touchId*2]; if(hidCheckSectionUpdateTime(hidSharedMem, Id)==0)
if (hidSharedMem[42 + 8 + touchId*2 + 1]) {
kHeld |= KEY_TOUCH; 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;
}
kDown = (~kOld) & kHeld; kDown = (~kOld) & kHeld;
kUp = 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*2];
}
Id = hidSharedMem[86 + 4];//Gyroscope
if(Id>31)Id=31;
if(hidCheckSectionUpdateTime(&hidSharedMem[86], Id)==0)
{
gRate = *(angularRate*)&hidSharedMem[86 + 8 + Id*2];
}
} }
u32 hidKeysHeld() u32 hidKeysHeld()
@ -93,7 +151,17 @@ void hidCircleRead(circlePosition* pos)
if (pos) *pos = cPos; if (pos) *pos = cPos;
} }
Result HIDUSER_GetSharedMem(Handle* outMemHandle) 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)
{ {
u32* cmdbuf=getThreadCommandBuffer(); u32* cmdbuf=getThreadCommandBuffer();
cmdbuf[0]=0xa0000; //request header code cmdbuf[0]=0xa0000; //request header code
@ -103,6 +171,12 @@ Result HIDUSER_GetSharedMem(Handle* outMemHandle)
if(outMemHandle)*outMemHandle=cmdbuf[3]; 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];
return cmdbuf[1]; return cmdbuf[1];
} }
@ -149,3 +223,4 @@ Result HIDUSER_DisableGyroscope()
return cmdbuf[1]; return cmdbuf[1];
} }

View File

@ -0,0 +1,270 @@
#include <stdlib.h>
#include <string.h>
#include <3ds.h>
//See also: http://3dbrew.org/wiki/MIC_Services
Handle MIC_handle;
static u8 *MIC_sharedmem;
static u32 MIC_sharedmem_size;
static u32 *MIC_sharedmem_offsetfield, MIC_sharedmem_offsetfield_location;
static Handle MIC_sharedmem_handle;
static Handle MIC_event;
static u32 MIC_prev_endpos, MIC_cur_endpos;
Result MIC_Initialize(u32 *sharedmem, u32 sharedmem_size, u8 control, u8 recording, u8 unk0, u8 unk1, u8 unk2)
{
Result ret=0;
MIC_sharedmem = (u8*)sharedmem;
MIC_sharedmem_size = sharedmem_size;
MIC_sharedmem_offsetfield_location = MIC_sharedmem_size - 4;
MIC_sharedmem_offsetfield = (u32*)&MIC_sharedmem[MIC_sharedmem_offsetfield_location];
MIC_event = 0;
MIC_prev_endpos = 0;
MIC_cur_endpos = 0;
ret = srvGetServiceHandle(&MIC_handle, "mic:u");
if(ret!=0)return ret;
ret = svcCreateMemoryBlock(&MIC_sharedmem_handle, (u32)MIC_sharedmem, MIC_sharedmem_size, 3, 3);
if(ret!=0)return ret;
ret = MIC_SetControl(control);
if(ret!=0)return ret;
ret = MIC_MapSharedMem(MIC_sharedmem_handle, sharedmem_size);
if(ret!=0)return ret;
ret = MIC_SetRecording(recording);
if(ret!=0)return ret;
ret = MIC_cmd3_Initialize(unk0, unk1, 0, MIC_sharedmem_size-4, unk2);
if(ret!=0)return ret;
ret = MIC_GetEventHandle(&MIC_event);
if(ret!=0)return ret;
svcClearEvent(MIC_event);
return 0;
}
Result MIC_Shutdown()
{
Result ret=0;
MIC_cmd5();
MIC_SetRecording(0);
ret = MIC_UnmapSharedMem();
if(ret!=0)return ret;
MIC_cmd5();
ret = svcUnmapMemoryBlock(MIC_sharedmem_handle, (u32)MIC_sharedmem);
if(ret!=0)return ret;
ret = svcCloseHandle(MIC_sharedmem_handle);
if(ret!=0)return ret;
ret = svcCloseHandle(MIC_event);
if(ret!=0)return ret;
ret = svcCloseHandle(MIC_handle);
if(ret!=0)return ret;
MIC_sharedmem_offsetfield = NULL;
MIC_sharedmem = NULL;
MIC_sharedmem_size = 0;
MIC_handle = 0;
MIC_event = 0;
return 0;
}
u32 MIC_GetSharedMemOffsetValue()
{
u32 pos = 0;
if(MIC_sharedmem_offsetfield==NULL)return pos;
pos = *MIC_sharedmem_offsetfield;
if(pos > MIC_sharedmem_offsetfield_location)pos = MIC_sharedmem_offsetfield_location;
return pos;
}
u32 MIC_ReadAudioData(u8 *outbuf, u32 readsize, u32 waitforevent)
{
u32 pos = 0, bufpos = 0;
if(waitforevent)
{
svcClearEvent(MIC_event);
svcWaitSynchronization(MIC_event, U64_MAX);
}
MIC_prev_endpos = MIC_cur_endpos;
MIC_cur_endpos = MIC_GetSharedMemOffsetValue();
pos = MIC_prev_endpos;
while(pos != MIC_cur_endpos)
{
if(pos >= MIC_sharedmem_offsetfield_location)pos = 0;
if(bufpos>=readsize)break;
outbuf[bufpos] = MIC_sharedmem[pos];
bufpos++;
pos++;
}
return bufpos;
}
Result MIC_MapSharedMem(Handle handle, u32 size)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = 0x00010042;
cmdbuf[1] = size;
cmdbuf[2] = 0;
cmdbuf[3] = handle;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
return (Result)cmdbuf[1];
}
Result MIC_UnmapSharedMem()
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = 0x00020000;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
return (Result)cmdbuf[1];
}
Result MIC_cmd3_Initialize(u8 unk0, u8 unk1, u32 sharedmem_baseoffset, u32 sharedmem_endoffset, u8 unk2)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = 0x00030140;
cmdbuf[1] = unk0;
cmdbuf[2] = unk1;
cmdbuf[3] = sharedmem_baseoffset;
cmdbuf[4] = sharedmem_endoffset;
cmdbuf[5] = unk2;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
return (Result)cmdbuf[1];
}
Result MIC_cmd5()
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = 0x00050000;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
return (Result)cmdbuf[1];
}
Result MIC_GetCNTBit15(u8 *out)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = 0x00060000;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
if(out)*out = cmdbuf[2];
return (Result)cmdbuf[1];
}
Result MIC_GetEventHandle(Handle *handle)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
if(MIC_event)
{
*handle = MIC_event;
return 0;
}
cmdbuf[0] = 0x00070000;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
if(handle)*handle = cmdbuf[2];
return (Result)cmdbuf[1];
}
Result MIC_SetControl(u8 value)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = 0x00080040;
cmdbuf[1] = value;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
return (Result)cmdbuf[1];
}
Result MIC_GetControl(u8 *value)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = 0x00090000;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
if(value)*value = cmdbuf[2];
return (Result)cmdbuf[1];
}
Result MIC_SetRecording(u8 value)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = 0x000A0040;
cmdbuf[1] = value;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
if(value==1)MIC_cur_endpos = MIC_GetSharedMemOffsetValue();
return (Result)cmdbuf[1];
}
Result MIC_IsRecoding(u8 *value)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = 0x000B0000;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
if(value)*value = cmdbuf[2];
return (Result)cmdbuf[1];
}