From 1f413a7d4485b8e1d1a69d32c83aa703f2c17898 Mon Sep 17 00:00:00 2001 From: StapleButter Date: Thu, 18 Sep 2014 22:09:15 +0200 Subject: [PATCH] Add synchronization mechanism for entering sleep mode. When the APT status is APP_PREPARE_SLEEPMODE, the application main thread should call aptSignalReadyForSleep() to signal that it is ready to enter sleep mode, and then call aptWaitStatusEvent() as usual. Example code: APP_STATUS status; while ((status = aptGetStatus()) != APP_EXITING) { if(status==APP_RUNNING) { // application logic here } else if(status == APP_SUSPENDING) { aptReturnToMenu(); } else if(status == APP_PREPARE_SLEEPMODE) { aptSignalReadyForSleep(); aptWaitStatusEvent(); } } This maybe isn't the proper/recommended way to do sleep mode, but I tested it multiple times and it always worked reliably. (note: maybe the sample code above will not work if GPU drawing is done in a separate thread, haven't tested that) --- libctru/include/3ds/services/apt.h | 1 + libctru/source/services/apt.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/libctru/include/3ds/services/apt.h b/libctru/include/3ds/services/apt.h index 9377c0b..b8c05d9 100644 --- a/libctru/include/3ds/services/apt.h +++ b/libctru/include/3ds/services/apt.h @@ -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); diff --git a/libctru/source/services/apt.c b/libctru/source/services/apt.c index d2f65d9..3c8de84 100644 --- a/libctru/source/services/apt.c +++ b/libctru/source/services/apt.c @@ -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;