Merge branch 'refactor' of github.com:smealum/ctrulib into refactor
This commit is contained in:
commit
40d35ee420
@ -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.
|
||||
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
139
examples/mic/Makefile
Normal 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
5
examples/mic/README.md
Normal 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.
|
||||
|
95
examples/mic/source/main.c
Normal file
95
examples/mic/source/main.c
Normal 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;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ include $(DEVKITARM)/base_rules
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := ctru
|
||||
BUILD := build
|
||||
SOURCES := source source/services source/gpu
|
||||
SOURCES := source source/services source/gpu source/allocator
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
|
||||
|
@ -23,6 +23,7 @@ extern "C" {
|
||||
#include <3ds/services/ir.h>
|
||||
#include <3ds/services/ptm.h>
|
||||
#include <3ds/services/soc.h>
|
||||
#include <3ds/services/mic.h>
|
||||
|
||||
#include <3ds/gpu/gx.h>
|
||||
#include <3ds/gpu/gpu.h>
|
||||
|
@ -9,6 +9,13 @@ void GPUCMD_Add(u32 cmd, u32* param, u32 paramlength);
|
||||
void GPUCMD_AddSingleParam(u32 cmd, u32 param);
|
||||
void GPUCMD_Finalize();
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GPU_TEXUNIT0 = 0x1,
|
||||
GPU_TEXUNIT1 = 0x2,
|
||||
GPU_TEXUNIT2 = 0x4
|
||||
} GPU_TEXUNIT;
|
||||
|
||||
typedef enum{
|
||||
GPU_RGBA8=0x0,
|
||||
GPU_RGB8=0x1,
|
||||
@ -37,6 +44,54 @@ typedef enum
|
||||
GPU_GEQUAL = 7
|
||||
}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{
|
||||
GPU_BYTE = 0,
|
||||
GPU_UNSIGNED_BYTE = 1,
|
||||
@ -84,14 +139,28 @@ typedef enum{
|
||||
}GPU_Primitive_t;
|
||||
|
||||
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_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_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref);
|
||||
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_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_DrawArray(GPU_Primitive_t primitive, u32 n);
|
||||
void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n);
|
||||
|
||||
void GPU_FinishDrawing();
|
||||
|
@ -7,3 +7,4 @@ u32 osConvertVirtToPhys(u32 vaddr);
|
||||
const char* osStrError(u32 error);
|
||||
u32 osGetFirmVersion();
|
||||
u32 osGetKernelVersion();
|
||||
u64 osGetTime();
|
||||
|
@ -48,6 +48,7 @@ u32 aptGetStatusPower();//This can be used when the status is APP_SUSPEND* to ch
|
||||
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 aptWaitStatusEvent();
|
||||
void aptSignalReadyForSleep();
|
||||
NS_APPID aptGetMenuAppID();
|
||||
|
||||
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_PrepareToCloseApplication(Handle* handle, u8 a);
|
||||
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);
|
||||
|
@ -37,12 +37,12 @@ typedef struct
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GSPEVENT_PSC0 = 0,
|
||||
GSPEVENT_PSC0 = 0, // memory fill completed
|
||||
GSPEVENT_PSC1,
|
||||
GSPEVENT_VBlank0,
|
||||
GSPEVENT_VBlank1,
|
||||
GSPEVENT_PPF,
|
||||
GSPEVENT_P3D,
|
||||
GSPEVENT_PPF, // display transfer finished
|
||||
GSPEVENT_P3D, // command list processing finished
|
||||
GSPEVENT_DMA,
|
||||
|
||||
GSPEVENT_MAX, // used to know how many events there are
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
//See also: http://3dbrew.org/wiki/HID_Services http://3dbrew.org/wiki/HID_Shared_Memory
|
||||
|
||||
#define HID_SHAREDMEM_DEFAULT (0x10000000)
|
||||
|
||||
typedef enum
|
||||
@ -39,6 +41,31 @@ typedef struct
|
||||
s16 dx, dy;
|
||||
} 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 vu32* hidSharedMem;
|
||||
|
||||
@ -51,6 +78,10 @@ u32 hidKeysDown();
|
||||
u32 hidKeysUp();
|
||||
void hidTouchRead(touchPosition* pos);
|
||||
void hidCircleRead(circlePosition* pos);
|
||||
void hidAccelRead(accelVector* vector);
|
||||
void hidGyroRead(angularRate* rate);
|
||||
|
||||
void hidWaitForEvent(HID_Event id, bool nextEvent);
|
||||
|
||||
// libnds compatibility defines
|
||||
#define scanKeys hidScanInput
|
||||
@ -60,8 +91,9 @@ void hidCircleRead(circlePosition* pos);
|
||||
#define touchRead hidTouchRead
|
||||
#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_DisableAccelerometer();
|
||||
Result HIDUSER_EnableGyroscope();
|
||||
Result HIDUSER_DisableGyroscope();
|
||||
|
||||
|
20
libctru/include/3ds/services/mic.h
Normal file
20
libctru/include/3ds/services/mic.h
Normal 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);
|
||||
|
50
libctru/source/allocator/linear.cpp
Normal file
50
libctru/source/allocator/linear.cpp
Normal 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);
|
||||
}
|
125
libctru/source/allocator/mem_pool.cpp
Normal file
125
libctru/source/allocator/mem_pool.cpp
Normal 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);
|
||||
}
|
||||
*/
|
88
libctru/source/allocator/mem_pool.h
Normal file
88
libctru/source/allocator/mem_pool.h
Normal 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);
|
||||
};
|
@ -65,6 +65,9 @@ void GPUCMD_AddSingleParam(u32 cmd, u32 param)
|
||||
|
||||
void GPUCMD_Finalize()
|
||||
{
|
||||
GPUCMD_AddSingleParam(0x0008025E, 0x00000000);
|
||||
GPUCMD_AddSingleParam(0x000F0111, 0x00000001);
|
||||
GPUCMD_AddSingleParam(0x000F0110, 0x00000001);
|
||||
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);
|
||||
|
||||
//enable depth buffer
|
||||
param[0x0]=0x00000000;
|
||||
param[0x0]=0x0000000F;
|
||||
param[0x1]=0x0000000F;
|
||||
param[0x2]=0x00000002;
|
||||
param[0x3]=0x00000002;
|
||||
@ -286,6 +289,11 @@ void GPU_DepthRange(float nearVal, float 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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
GPUCMD_AddSingleParam(0x000F0085, ((u32)data)>>3);
|
||||
GPUCMD_AddSingleParam(0x000F0082, (width)|(height<<16));
|
||||
GPUCMD_AddSingleParam(0x000F0083, param);
|
||||
// TODO: fixed color
|
||||
// it is controlled by command 0103 but I haven't found were to place said command without freezing the GPU
|
||||
|
||||
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};
|
||||
@ -385,7 +435,6 @@ void GPU_DrawArray(GPU_Primitive_t primitive, u32 n)
|
||||
GPUCMD_AddSingleParam(0x000F0231, 0x00000001);
|
||||
|
||||
GPUCMD_AddSingleParam(0x000F0111, 0x00000001);
|
||||
GPUCMD_AddSingleParam(0x000F0110, 0x00000001);
|
||||
}
|
||||
|
||||
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(0x00010245, 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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -1,5 +1,21 @@
|
||||
#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)
|
||||
{
|
||||
if(vaddr >= 0x14000000 && vaddr < 0x1c000000)
|
||||
@ -13,6 +29,21 @@ u32 osConvertVirtToPhys(u32 vaddr)
|
||||
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() {
|
||||
return (*(u32*)0x1FF80000) & ~0xFF;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ Handle aptStatusEvent = 0;
|
||||
APP_STATUS aptStatus = APP_NOTINITIALIZED;
|
||||
APP_STATUS aptStatusBeforeSleep = APP_NOTINITIALIZED;
|
||||
u32 aptStatusPower = 0;
|
||||
Handle aptSleepSync = 0;
|
||||
|
||||
u32 aptParameters[0x1000/4]; //TEMP
|
||||
|
||||
@ -204,21 +205,24 @@ static void __handle_notification() {
|
||||
case APTSIGNAL_PREPARESLEEP:
|
||||
// Reply to sleep-request.
|
||||
aptStatusBeforeSleep = aptGetStatus();
|
||||
aptSetStatus(APP_PREPARE_SLEEPMODE);
|
||||
svcWaitSynchronization(aptSleepSync, U64_MAX);
|
||||
svcClearEvent(aptSleepSync);
|
||||
|
||||
aptOpenSession();
|
||||
APT_ReplySleepQuery(NULL, currentAppId, 0x1);
|
||||
aptCloseSession();
|
||||
|
||||
aptSetStatus(APP_PREPARE_SLEEPMODE);
|
||||
break;
|
||||
|
||||
case APTSIGNAL_ENTERSLEEP:
|
||||
if(aptGetStatus() == APP_PREPARE_SLEEPMODE)
|
||||
{
|
||||
// Report into sleep-mode.
|
||||
aptSetStatus(APP_SLEEPMODE);
|
||||
|
||||
aptOpenSession();
|
||||
APT_ReplySleepNotificationComplete(NULL, currentAppId);
|
||||
aptCloseSession();
|
||||
aptSetStatus(APP_SLEEPMODE);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -319,6 +323,7 @@ Result aptInit(void)
|
||||
}
|
||||
|
||||
svcCreateEvent(&aptStatusEvent, 0);
|
||||
svcCreateEvent(&aptSleepSync, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -344,6 +349,8 @@ void aptExit()
|
||||
APT_CloseApplication(NULL, 0x0, 0x0, 0x0);
|
||||
aptCloseSession();
|
||||
}
|
||||
|
||||
svcCloseHandle(aptSleepSync);
|
||||
|
||||
svcCloseHandle(aptStatusMutex);
|
||||
//svcCloseHandle(aptLockHandle);
|
||||
@ -421,7 +428,7 @@ void aptSetStatus(APP_STATUS status)
|
||||
|
||||
svcWaitSynchronization(aptStatusMutex, U64_MAX);
|
||||
|
||||
prevstatus = status;
|
||||
prevstatus = aptStatus;
|
||||
aptStatus = status;
|
||||
|
||||
if(prevstatus != APP_NOTINITIALIZED)
|
||||
@ -461,6 +468,11 @@ void aptCloseSession()
|
||||
svcReleaseMutex(aptLockHandle);
|
||||
}
|
||||
|
||||
void aptSignalReadyForSleep()
|
||||
{
|
||||
svcSignalEvent(aptSleepSync);
|
||||
}
|
||||
|
||||
Result APT_GetLockHandle(Handle* handle, u16 flags, Handle* lockHandle)
|
||||
{
|
||||
if(!handle)handle=&aptuHandle;
|
||||
@ -743,3 +755,35 @@ Result APT_CloseApplication(Handle* handle, u32 a, u32 b, u32 c)
|
||||
|
||||
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];
|
||||
}
|
||||
|
@ -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_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_cmd9(channel, 0xffff);
|
||||
CSND_setchannel_playbackstate(channel, 1);
|
||||
|
@ -68,7 +68,7 @@ FSUSER_Initialize(Handle* handle)
|
||||
{
|
||||
// don't run command if we got handle from the list
|
||||
handle = &fsuHandle;
|
||||
if(fsuHandle != 0 && __get_handle_from_list("fs:USER")==0)
|
||||
if(fsuHandle != 0 && __get_handle_from_list("fs:USER")!=0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,8 @@ void gspExitEventHandler()
|
||||
|
||||
void gspWaitForEvent(GSP_Event id, bool nextEvent)
|
||||
{
|
||||
if(id>=GSPEVENT_MAX)return;
|
||||
|
||||
if (nextEvent)
|
||||
svcClearEvent(gspEvents[id]);
|
||||
svcWaitSynchronization(gspEvents[id], U64_MAX);
|
||||
@ -83,15 +85,15 @@ void gspEventThreadMain(u32 arg)
|
||||
svcClearEvent(gspEvent);
|
||||
|
||||
int count = gspEventData[1];
|
||||
int last = gspEventData[0] + count;
|
||||
int cur = gspEventData[0];
|
||||
int last = cur + count;
|
||||
while (last >= 0x34) last -= 0x34;
|
||||
int cur = last;
|
||||
int i;
|
||||
for (i = 0; i < count; i ++)
|
||||
{
|
||||
int curEvt = gspEventData[0xC + cur];
|
||||
cur --;
|
||||
if (cur < 0) cur += 0x34;
|
||||
cur ++;
|
||||
if (cur >= 0x34) cur -= 0x34;
|
||||
if (curEvt >= GSPEVENT_MAX) continue;
|
||||
svcSignalEvent(gspEvents[curEvt]);
|
||||
}
|
||||
|
@ -8,11 +8,15 @@
|
||||
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;
|
||||
|
||||
|
||||
Result hidInit(u32* sharedMem)
|
||||
@ -24,7 +28,7 @@ Result hidInit(u32* sharedMem)
|
||||
if((ret=srvGetServiceHandle(&hidHandle, "hid:USER")))return ret;
|
||||
|
||||
// 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".
|
||||
hidSharedMem=sharedMem;
|
||||
@ -49,23 +53,77 @@ void hidExit()
|
||||
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()
|
||||
{
|
||||
u32 Id=0;
|
||||
|
||||
kOld = kHeld;
|
||||
|
||||
u32 padId = hidSharedMem[4];
|
||||
if(padId>7)padId=7;
|
||||
kHeld = hidSharedMem[10 + padId*4];
|
||||
cPos = *(circlePosition*)&hidSharedMem[10 + padId*4 + 3];
|
||||
kHeld = 0;
|
||||
memset(&cPos, 0, sizeof(circlePosition));
|
||||
memset(&tPos, 0, sizeof(touchPosition));
|
||||
memset(&aVec, 0, sizeof(accelVector));
|
||||
memset(&gRate, 0, sizeof(angularRate));
|
||||
|
||||
u32 touchId = hidSharedMem[42 + 4];
|
||||
if(touchId>7)touchId=7;
|
||||
tPos = *(touchPosition*)&hidSharedMem[42 + 8 + touchId*2];
|
||||
if (hidSharedMem[42 + 8 + touchId*2 + 1])
|
||||
kHeld |= KEY_TOUCH;
|
||||
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;
|
||||
}
|
||||
|
||||
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*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()
|
||||
@ -93,7 +151,17 @@ void hidCircleRead(circlePosition* pos)
|
||||
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();
|
||||
cmdbuf[0]=0xa0000; //request header code
|
||||
@ -103,6 +171,12 @@ Result HIDUSER_GetSharedMem(Handle* outMemHandle)
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
@ -149,3 +223,4 @@ Result HIDUSER_DisableGyroscope()
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
|
270
libctru/source/services/mic.c
Normal file
270
libctru/source/services/mic.c
Normal 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];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user