Merge pull request #205 from Steveice10/great-refactor

Rewrite MIC service code, clean up microphone example.
This commit is contained in:
fincs 2015-11-08 00:22:47 +01:00
commit 7440ca7901
3 changed files with 283 additions and 291 deletions

View File

@ -6,26 +6,37 @@
int main()
{
u8 *framebuf;
u32 *sharedmem = NULL, sharedmem_size = 0x30000;
u8 *audiobuf;
u32 audiobuf_size = 0x100000, audiobuf_pos = 0;
u8 control=0x40;
u32 audio_initialized = 0;
gfxInitDefault();
consoleInit(GFX_BOTTOM, NULL);
if(csndInit()==0)
bool initialized = true;
u32 micbuf_size = 0x30000;
u32 micbuf_pos = 0;
u8* micbuf = memalign(micbuf_size, 0x1000);
printf("Initializing CSND...\n");
if(R_FAILED(csndInit()))
{
printf("Init success\n");
audio_initialized = 1;
}
initialized = false;
printf("Could not initialize CSND.\n");
} else printf("CSND initialized.\n");
sharedmem = (u32*)memalign(0x1000, sharedmem_size);
audiobuf = linearAlloc(audiobuf_size);
printf("Initializing MIC...\n");
if(R_FAILED(micInit(micbuf, micbuf_size)))
{
initialized = false;
printf("Could not initialize MIC.\n");
} else printf("MIC initialized.\n");
MIC_Initialize(sharedmem, sharedmem_size, control, 0, 3, 1, 1);//See mic.h.
u32 micbuf_datasize = micGetSampleDataSize();
u32 audiobuf_size = 0x100000;
u32 audiobuf_pos = 0;
u8* audiobuf = linearAlloc(audiobuf_size);
if(initialized) printf("Hold A to record, release to play.\n");
printf("Press START to exit.\n");
while(aptMainLoop())
{
@ -36,45 +47,42 @@ int main()
if (kDown & KEY_START)
break; // break in order to return to hbmenu
if(audio_initialized)
if(initialized)
{
framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL);
if(kDown & KEY_A)
{
audiobuf_pos = 0;
printf("Stopping audio playback\n");
CSND_SetPlayState(0x8, 0);//Stop audio playback.
CSND_UpdateInfo(0);
micbuf_pos = 0;
MIC_SetRecording(1);
printf("Stopping audio playback...\n");
CSND_SetPlayState(0x8, 0);
if(R_FAILED(CSND_UpdateInfo(0))) printf("Failed to stop audio playback.\n");
memset(framebuf, 0x20, 0x46500);
printf("Now recording\n");
printf("Starting sampling...\n");
if(R_SUCCEEDED(MICU_SetPower(true)) && R_SUCCEEDED(MICU_StartSampling(MICU_ENCODING_PCM16_SIGNED, MICU_SAMPLE_RATE_16360, 0, micbuf_datasize, true))) printf("Now recording.\n");
else printf("Failed to start sampling.\n");
}
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);
u32 micbuf_readpos = micbuf_pos;
micbuf_pos = micGetLastSampleOffset();
while(audiobuf_pos < audiobuf_size && micbuf_readpos != micbuf_pos)
{
audiobuf[audiobuf_pos] = micbuf[micbuf_readpos];
audiobuf_pos++;
micbuf_readpos = (micbuf_readpos + 1) % micbuf_datasize;
}
}
if(hidKeysUp() & KEY_A)
{
printf("Playing the recorded sample\n");
MIC_SetRecording(0);
GSPGPU_FlushDataCache(NULL, audiobuf, audiobuf_pos);
csndPlaySound(0x8, SOUND_ONE_SHOT | SOUND_FORMAT_16BIT, 16000, 1.0, 0.0, (u32*)audiobuf, NULL, audiobuf_pos);
printf("Stoping sampling...\n");
if(R_FAILED(MICU_StopSampling()) || R_FAILED(MICU_SetPower(false))) printf("Failed to stop sampling.\n");
memset(framebuf, 0xe0, 0x46500);
gfxFlushBuffers();
gfxSwapBuffers();
framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL);
memset(framebuf, 0xe0, 0x46500);
printf("Starting audio playback...\n");
if(R_SUCCEEDED(GSPGPU_FlushDataCache(audiobuf, audiobuf_pos)) && R_SUCCEEDED(csndPlaySound(0x8, SOUND_ONE_SHOT | SOUND_FORMAT_16BIT, 16360, 1.0, 0.0, (u32*)audiobuf, NULL, audiobuf_pos))) printf("Now playing.\n");
else printf("Failed to start playback.\n");
}
}
@ -82,13 +90,12 @@ int main()
gfxSwapBuffers();
}
MIC_Shutdown();
if(audio_initialized)csndExit();
free(sharedmem);
linearFree(audiobuf);
micExit();
free(micbuf);
csndExit();
gfxExit();
return 0;
}

View File

@ -4,95 +4,125 @@
*/
#pragma once
//See also: http://3dbrew.org/wiki/MIC_Services
/// Microphone audio encodings.
typedef enum
{
MICU_ENCODING_PCM8 = 0, ///< Unsigned 8-bit PCM.
MICU_ENCODING_PCM16 = 1, ///< Unsigned 16-bit PCM.
MICU_ENCODING_PCM8_SIGNED = 2, ///< Signed 8-bit PCM.
MICU_ENCODING_PCM16_SIGNED = 3, ///< Signed 16-bit PCM.
} MICU_Encoding;
/// Microphone audio sampling rates.
typedef enum
{
MICU_SAMPLE_RATE_32730 = 0, ///< 32730 Hz
MICU_SAMPLE_RATE_16360 = 1, ///< 16360 Hz
MICU_SAMPLE_RATE_10910 = 2, ///< 10910 Hz
MICU_SAMPLE_RATE_8180 = 3, ///< 8180 Hz
} MICU_SampleRate;
/**
* @brief Initializes MIC.
* @param sharedmem Shared memory block to use. Must be 0x1000-bytes aligned.
* @param sharedmem_size Size of the shared memory block to use. (audiodata size + 4, aligned to 0x1000-bytes)
* @param control Control value. Bits 0-6 = Amplification.
* @param unk0 Unknown. Typically 3.
* @param unk1 Unknown. Typically 1.
* @param unk2 Unknown. Typically 1.
* @param size Shared memory buffer to write audio data to. Must be aligned to 0x1000 bytes.
* @param handle Size of the shared memory buffer.
*/
Result MIC_Initialize(u32 *sharedmem, u32 sharedmem_size, u8 control, u8 recording, u8 unk0, u8 unk1, u8 unk2);
Result micInit(u8* buffer, u32 bufferSize);
/// Shuts down MIC.
Result MIC_Shutdown(void);
/// Exits MIC.
void micExit(void);
/**
* @brief Gets the current shared memory offset.
* @return The current shared memory offset.
* @brief Gets the size of the sample data area within the shared memory buffer.
* @return The sample data's size.
*/
u32 MIC_GetSharedMemOffsetValue(void);
u32 micGetSampleDataSize(void);
/**
* @brief Reads MIC audio data.
* @param outbuf Buffer to write audio data to.
* @param readsize Size of the buffer to write to.
* @param waitforevent Whether to wait for the MIC service to signal that audio data is ready. (non-zero = wait)
* @return Actual number of bytes read.
* @brief Gets the offset within the shared memory buffer of the last sample written.
* @return The last sample's offset.
*/
u32 MIC_ReadAudioData(u8 *outbuf, u32 readsize, u32 waitforevent);
u32 micGetLastSampleOffset(void);
/**
* @brief Maps MIC's shared memory.
* @param handle Handle of the shared memory.
* @brief Maps MIC shared memory.
* @param size Size of the shared memory.
* @param handle Handle of the shared memory.
*/
Result MIC_MapSharedMem(Handle handle, u32 size);
Result MICU_MapSharedMem(u32 size, Handle handle);
/// Unmaps MIC's shardd memory.
Result MIC_UnmapSharedMem(void);
/// Unmaps MIC shared memory.
Result MICU_UnmapSharedMem(void);
/**
* @brief Initializes MIC.
* @param unk0 Unknown.
* @param unk1 Unknown.
* @param sharedmem_baseoffset Base offset of shared memory.
* @param sharedmem_endoffset End offset of shared memory.
* @param unk2 Unknown.
* @brief Begins sampling microphone input.
* @param encoding Encoding of outputted audio.
* @param sampleRate Sample rate of outputted audio.
* @param sharedMemAudioOffset Offset to write audio data to in the shared memory buffer.
* @param sharedMemAudioSize Size of audio data to write to the shared memory buffer. This should be at most "bufferSize - 4".
* @param loop Whether to loop back to the beginning of the buffer when the end is reached.
*/
Result MIC_cmd3_Initialize(u8 unk0, u8 unk1, u32 sharedmem_baseoffset, u32 sharedmem_endoffset, u8 unk2);
/// Unknown MIC command.
Result MIC_cmd5(void);
Result MICU_StartSampling(MICU_Encoding encoding, MICU_SampleRate sampleRate, u32 offset, u32 size, bool loop);
/**
* @brief Gets CNT bit 15 from MIC.
* @param out Pointer to output the bit to.
* @brief Adjusts the configuration of the current sampling session.
* @param sampleRate Sample rate of outputted audio.
*/
Result MIC_GetCNTBit15(u8 *out);
Result MICU_AdjustSampling(MICU_SampleRate sampleRate);
/// Stops sampling microphone input.
Result MICU_StopSampling(void);
/**
* @brief Gets the event handle signaled by MIC when data is ready.
* @brief Gets whether microphone input is currently being sampled.
* @param sampling Pointer to output the sampling state to.
*/
Result MICU_IsSampling(bool* sampling);
/**
* @brief Gets an event handle triggered when the shared memory buffer is full.
* @param handle Pointer to output the event handle to.
*/
Result MIC_GetEventHandle(Handle *handle);
Result MICU_GetEventHandle(Handle* handle);
/**
* Sets the control value.
* @note Bits 0-6 = Amplification.
* @param value Control value to set.
* @brief Sets the microphone's gain.
* @param gain Gain to set.
*/
Result MIC_SetControl(u8 value);
Result MICU_SetGain(u8 gain);
/**
* Gets the control value.
* @note Bits 0-6 = Amplification.
* @param value Pointer to output the control value to.
* @brief Gets the microphone's gain.
* @param gain Pointer to output the current gain to.
*/
Result MIC_GetControl(u8 *value);
Result MICU_GetGain(u8* gain);
/**
* Sets whether the microphone is recording.
* @param value Whether the microphone is recording.
* @brief Sets whether the microphone is powered on.
* @param power Whether the microphone is powered on.
*/
Result MIC_SetRecording(u8 value);
Result MICU_SetPower(bool power);
/**
* Gets whether the microphone is recording.
* @param value Pointer to output whether the microphone is recording to.
* @brief Gets whether the microphone is powered on.
* @param power Pointer to output the power state to.
*/
Result MIC_IsRecoding(u8 *value);
Result MICU_GetPower(bool* power);
/**
* @brief Sets whether to clamp microphone input.
* @param clamp Whether to clamp microphone input.
*/
Result MICU_SetClamp(bool clamp);
/**
* @brief Gets whether to clamp microphone input.
* @param clamp Pointer to output the clamp state to.
*/
Result MICU_GetClamp(bool* clamp);
/**
* @brief Sets whether to allow sampling when the shell is closed.
* @param allowShellClosed Whether to allow sampling when the shell is closed.
*/
Result MICU_SetAllowShellClosed(bool allowShellClosed);

View File

@ -1,271 +1,226 @@
#include <stdlib.h>
#include <string.h>
#include <3ds/types.h>
#include <3ds/svc.h>
#include <3ds/srv.h>
#include <3ds/services/mic.h>
#include <3ds/ipc.h>
#include <3ds/synchronization.h>
#include <3ds/result.h>
//See also: http://3dbrew.org/wiki/MIC_Services
static Handle micHandle;
static int micRefCount;
Handle MIC_handle;
static u8* micSharedMem;
static u32 micSharedMemSize;
static Handle micSharedMemHandle;
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 micInit(u8* buffer, u32 bufferSize)
{
Result ret=0;
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;
if (AtomicPostIncrement(&micRefCount)) return 0;
ret = srvGetServiceHandle(&MIC_handle, "mic:u");
if(ret!=0)return ret;
ret = srvGetServiceHandle(&micHandle, "mic:u");
if (R_FAILED(ret)) goto end;
ret = svcCreateMemoryBlock(&MIC_sharedmem_handle, (u32)MIC_sharedmem, MIC_sharedmem_size, 3, 3);
if(ret!=0)return ret;
micSharedMem = buffer;
micSharedMemSize = bufferSize;
ret = MIC_SetControl(control);
if(ret!=0)return ret;
ret = svcCreateMemoryBlock(&micSharedMemHandle, (u32) micSharedMem, micSharedMemSize, MEMPERM_READ | MEMPERM_WRITE, MEMPERM_READ | MEMPERM_WRITE);
if (R_FAILED(ret)) goto end;
ret = MIC_MapSharedMem(MIC_sharedmem_handle, sharedmem_size);
if(ret!=0)return ret;
ret = MICU_MapSharedMem(micSharedMemSize, micSharedMemHandle);
end:
if (R_FAILED(ret)) micExit();
return ret;
}
ret = MIC_SetRecording(recording);
if(ret!=0)return ret;
void micExit(void)
{
if (AtomicDecrement(&micRefCount)) return;
ret = MIC_cmd3_Initialize(unk0, unk1, 0, MIC_sharedmem_size-4, unk2);
if(ret!=0)return ret;
if (micSharedMemHandle)
{
MICU_UnmapSharedMem();
svcCloseHandle(micSharedMemHandle);
micSharedMemHandle = 0;
}
ret = MIC_GetEventHandle(&MIC_event);
if(ret!=0)return ret;
svcClearEvent(MIC_event);
if(micHandle)
{
svcCloseHandle(micHandle);
micHandle = 0;
}
micSharedMem = NULL;
micSharedMemSize = 0;
}
u32 micGetSampleDataSize(void)
{
return micSharedMemSize - 4;
}
u32 micGetLastSampleOffset(void)
{
if(micSharedMem) return *(u32*) &micSharedMem[micGetSampleDataSize()];
return 0;
}
Result MIC_Shutdown(void)
Result MICU_MapSharedMem(u32 size, Handle handle)
{
Result ret=0;
MIC_cmd5();
MIC_SetRecording(0);
ret = MIC_UnmapSharedMem();
if(ret!=0)return ret;
MIC_cmd5();
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(void)
{
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();
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x1,1,2); // 0x10042
cmdbuf[1] = size;
cmdbuf[2] = IPC_Desc_SharedHandles(1);
cmdbuf[3] = handle;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
return (Result)cmdbuf[1];
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
return cmdbuf[1];
}
Result MIC_UnmapSharedMem(void)
Result MICU_UnmapSharedMem(void)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x2,0,0); // 0x20000
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
return (Result)cmdbuf[1];
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
return cmdbuf[1];
}
Result MIC_cmd3_Initialize(u8 unk0, u8 unk1, u32 sharedmem_baseoffset, u32 sharedmem_endoffset, u8 unk2)
Result MICU_StartSampling(MICU_Encoding encoding, MICU_SampleRate sampleRate, u32 offset, u32 size, bool loop)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x3,5,0); // 0x30140
cmdbuf[1] = unk0;
cmdbuf[2] = unk1;
cmdbuf[3] = sharedmem_baseoffset;
cmdbuf[4] = sharedmem_endoffset;
cmdbuf[5] = unk2;
cmdbuf[1] = encoding;
cmdbuf[2] = sampleRate;
cmdbuf[3] = offset;
cmdbuf[4] = size;
cmdbuf[5] = loop;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
return (Result)cmdbuf[1];
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
return cmdbuf[1];
}
Result MIC_cmd5(void)
Result MICU_AdjustSampling(MICU_SampleRate sampleRate)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x4,1,0); // 0x40040
cmdbuf[1] = sampleRate;
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
return cmdbuf[1];
}
Result MICU_StopSampling(void)
{
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x5,0,0); // 0x50000
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
return (Result)cmdbuf[1];
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
return cmdbuf[1];
}
Result MIC_GetCNTBit15(u8 *out)
Result MICU_IsSampling(bool* sampling)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x6,0,0); // 0x60000
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
if(out)*out = cmdbuf[2];
return (Result)cmdbuf[1];
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
if (sampling) *sampling = cmdbuf[2] & 0xFF;
return cmdbuf[1];
}
Result MIC_GetEventHandle(Handle *handle)
Result MICU_GetEventHandle(Handle* handle)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
if(MIC_event)
{
*handle = MIC_event;
return 0;
}
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x7,0,0); // 0x70000
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
if(handle)*handle = cmdbuf[3];
return (Result)cmdbuf[1];
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
if (handle) *handle = cmdbuf[3];
return cmdbuf[1];
}
Result MIC_SetControl(u8 value)
Result MICU_SetGain(u8 gain)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x8,1,0); // 0x80040
cmdbuf[1] = value;
cmdbuf[1] = gain;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
return (Result)cmdbuf[1];
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
return cmdbuf[1];
}
Result MIC_GetControl(u8 *value)
Result MICU_GetGain(u8* gain)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x9,0,0); // 0x90000
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
if(value)*value = cmdbuf[2];
return (Result)cmdbuf[1];
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
if (gain) *gain = cmdbuf[2] & 0xFF;
return cmdbuf[1];
}
Result MIC_SetRecording(u8 value)
Result MICU_SetPower(bool power)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0xA,1,0); // 0xA0040
cmdbuf[1] = value;
cmdbuf[1] = power;
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
if(value==1)MIC_cur_endpos = MIC_GetSharedMemOffsetValue();
return (Result)cmdbuf[1];
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
return cmdbuf[1];
}
Result MIC_IsRecoding(u8 *value)
Result MICU_GetPower(bool* power)
{
Result ret=0;
u32 *cmdbuf = getThreadCommandBuffer();
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0xB,0,0); // 0xB0000
if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret;
if(value)*value = cmdbuf[2];
return (Result)cmdbuf[1];
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
if (power) *power = cmdbuf[2] & 0xFF;
return cmdbuf[1];
}
Result MICU_SetClamp(bool clamp)
{
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0xD,1,0); // 0xD0040
cmdbuf[1] = clamp;
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
return cmdbuf[1];
}
Result MICU_GetClamp(bool* clamp)
{
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0xE,0,0); // 0xE0000
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
if (clamp) *clamp = cmdbuf[2] & 0xFF;
return cmdbuf[1];
}
Result MICU_SetAllowShellClosed(bool allowShellClosed)
{
Result ret = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0xF,1,0); // 0xF0040
cmdbuf[1] = allowShellClosed;
if (R_FAILED(ret = svcSendSyncRequest(micHandle))) return ret;
return cmdbuf[1];
}