1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: applet.cpp
4
5 Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Rev: 48673 $
14 *---------------------------------------------------------------------------*/
15
16 #include "applet.h"
17
18 namespace
19 {
RestoreGraphicSetting()20 void RestoreGraphicSetting()
21 {
22 // Recover the GPU register settings
23 // However, the following is the method for recovering the state set using DMPGL API.
24 // If using other libraries, it is necessary to reissue all of the register setting commands with their own methods.
25 nngxUpdateState(NN_GX_STATE_ALL);
26
27 // (Reference) Recovering settings with the GD library
28 // nn::gd::System::ForceDirty(nn::gd::MODULE_ALL);
29
30 // (Reference) Recovering settings with the GR library
31 // The GR API only creates commands; it does not have a feature for recovering settings.
32 // When rendering next time, run all of the necessary commands.
33 }
34 }
35
36 bool TransitionHandler::s_IsExitRequired = false;
37 volatile bool TransitionHandler::s_IsAfterWakeUp = false;
38 nn::os::LightEvent TransitionHandler::s_AwakeEvent;
39 nn::os::CriticalSection TransitionHandler::s_CriticalSection;
40 nn::os::CriticalSection TransitionHandler::s_CriticalSectionForSleep;
41
42 TransitionHandler::TRANSITION_CALLBACK TransitionHandler::s_PrepareSleepCallback;
43 TransitionHandler::TRANSITION_CALLBACK TransitionHandler::s_AfterSleepCallback;
44 TransitionHandler::TRANSITION_CALLBACK TransitionHandler::s_PrepareHomeButtonCallback;
45 TransitionHandler::TRANSITION_CALLBACK TransitionHandler::s_AfterHomeButtonCallback;
46 TransitionHandler::TRANSITION_CALLBACK TransitionHandler::s_PreparePowerButtonCallback;
47
Initialize()48 void TransitionHandler::Initialize()
49 {
50 // Set sleep-related callbacks
51 nn::applet::SetSleepQueryCallback(SleepQueryCallback, 0);
52 nn::applet::SetAwakeCallback(AwakeCallback, 0);
53 // nn::applet::SetSleepCanceledCallback(NULL, 0); // Recommend not using SleepCanceledCallback
54
55 s_AwakeEvent.Initialize(true);
56 s_CriticalSection.Initialize();
57 s_CriticalSectionForSleep.Initialize();
58
59 // During wake-up, always set to Signal state
60 s_AwakeEvent.Signal();
61
62 // Enable features related to the applet library.
63 // If you set 'false' for the argument, then sleep will be rejected automatically until nn::applet::EnableSleep() is called.
64 //
65 nn::applet::Enable(false);
66
67 // The Initialize function for each of the gx, snd, and dsp libraries must be called after the applet::Enable function
68 // In particular, the nngxInitialize function, which initializes the GX library, should be called after determining whether to exit immediately following a call to the Enable function.
69
70 // The application terminates here if the termination conditions are already established, such as by pressing the POWER Button while displaying the logo
71 if ( nn::applet::IsExpectedToCloseApplication() )
72 {
73 s_IsExitRequired = true;
74 }
75 }
76
Finalize()77 void TransitionHandler::Finalize()
78 {
79 s_AwakeEvent.Finalize();
80 s_CriticalSection.Finalize();
81 s_CriticalSectionForSleep.Finalize();
82
83 nn::applet::SetSleepQueryCallback(NULL, 0);
84 nn::applet::SetAwakeCallback(NULL, 0);
85 }
86
EnableSleep()87 void TransitionHandler::EnableSleep()
88 {
89 // Enable responses to sleep requests.
90 // Check the system state. If the system has been closed, issue a sleep request.
91 nn::applet::EnableSleep(true);
92 }
93
DisableSleep()94 void TransitionHandler::DisableSleep()
95 {
96 // Reject sleep.
97 // Return REJECT if a sleep request has come already.
98 nn::applet::DisableSleep(true);
99 }
100
Process()101 void TransitionHandler::Process()
102 {
103 // When waking up from sleep, enable LCD after waiting for one-frame worth of rendering to complete
104 if ( TransitionHandler::s_IsAfterWakeUp )
105 {
106 nn::gx::StartLcdDisplay();
107 TransitionHandler::s_IsAfterWakeUp = false;
108 }
109
110 // If the consistency of the GPU register settings is taken into account, the responses to various transitions and sleep requests should be done after rendering has ended.
111 //
112
113 // Determination for System Sleep Mode
114 if ( nn::applet::IsExpectedToReplySleepQuery() )
115 {
116 // If you any reason REJECT is returned for SleepQuery, make the determination here.
117 // Return REJECT and exit from this function.
118
119 // Do not enter sleep during file system processing
120 if ( TryLockForSleep() )
121 {
122 // Perform the Sleep Mode pre-processing here as required
123 if ( s_PrepareSleepCallback )
124 {
125 s_PrepareSleepCallback();
126 }
127
128 // Clears AwakeEvent immediately before permitting Sleep Mode
129 s_AwakeEvent.ClearSignal();
130
131 // Permits Sleep Mode, and stops the main thread immediately
132 nn::applet::ReplySleepQuery(nn::applet::REPLY_ACCEPT);
133 s_AwakeEvent.Wait();
134
135 // Perform the processing when recovering from Sleep Mode here as required
136 if ( s_AfterSleepCallback )
137 {
138 s_AfterSleepCallback();
139 }
140
141 UnlockForSleep();
142 }
143 }
144
145 // Check termination request
146 if ( nn::applet::IsExpectedToCloseApplication() )
147 {
148 s_IsExitRequired = true;
149 return;
150 }
151
152 // Performs application transition processing
153
154 // HOME Button processing (the graphics library must already be initialized)
155 if ( nn::applet::IsExpectedToProcessHomeButton() )
156 {
157 // If exiting the block by determining with flags or other things here, the HOME Button prohibition interval can be implemented
158 // HOME Button flag must be deleted with nn::applet::ClearHomeButtonState function
159
160 if ( TryLock() )
161 {
162 if ( s_PrepareHomeButtonCallback )
163 {
164 s_PrepareHomeButtonCallback();
165 }
166
167 nn::applet::ProcessHomeButtonAndWait();
168
169 Unlock();
170
171 // Caused by exiting from the HOME Menu or low batteries
172 // If it is determined to end the application, exit from the application main loop and go to termination processing
173 if ( nn::applet::IsExpectedToCloseApplication() )
174 {
175 // No render rights are passed
176 s_IsExitRequired = true;
177
178 if ( s_AfterHomeButtonCallback )
179 {
180 s_AfterHomeButtonCallback();
181 }
182 return;
183 }
184
185 if ( s_AfterHomeButtonCallback )
186 {
187 s_AfterHomeButtonCallback();
188 }
189
190 // Restore graphics settings
191 RestoreGraphicSetting();
192 }
193 }
194
195 // POWER Button processing (the graphics library must already be initialized)
196 if ( nn::applet::IsExpectedToProcessPowerButton() )
197 {
198 // Quickly handle the POWER Button, but as for the other tasks that should be done before the application ends, (such as dealing with save data) should be done after nn::applet::ProcessPowerButtonAndWait() returns.
199 //
200 //
201 if ( s_PreparePowerButtonCallback )
202 {
203 s_PreparePowerButtonCallback();
204 }
205
206 nn::applet::ProcessPowerButtonAndWait();
207
208 // If it is determined to end the application, exit from the application main loop and go to termination processing
209 if ( nn::applet::IsExpectedToCloseApplication() )
210 {
211 // No render rights are passed
212 s_IsExitRequired = true;
213 return;
214 }
215
216 // Restore graphics settings
217 RestoreGraphicSetting();
218 }
219 }
220
IsExitRequired()221 bool TransitionHandler::IsExitRequired()
222 {
223 return s_IsExitRequired;
224 }
225
Lock()226 void TransitionHandler::Lock()
227 {
228 s_CriticalSection.Enter();
229 }
230
TryLock()231 bool TransitionHandler::TryLock()
232 {
233 return s_CriticalSection.TryEnter();
234 }
235
Unlock()236 void TransitionHandler::Unlock()
237 {
238 s_CriticalSection.Leave();
239 }
240
LockForSleep()241 void TransitionHandler::LockForSleep()
242 {
243 s_CriticalSectionForSleep.Enter();
244 }
245
TryLockForSleep()246 bool TransitionHandler::TryLockForSleep()
247 {
248 return s_CriticalSectionForSleep.TryEnter();
249 }
250
UnlockForSleep()251 void TransitionHandler::UnlockForSleep()
252 {
253 s_CriticalSectionForSleep.Leave();
254 }
255
256 /*------------------------------------------------------------------------*
257 Callback called when there is a sleep query
258 *------------------------------------------------------------------------*/
SleepQueryCallback(uptr arg)259 AppletQueryReply TransitionHandler::SleepQueryCallback( uptr arg )
260 {
261 NN_UNUSED_VAR(arg);
262
263 if ( !nn::applet::IsActive() )
264 {
265 // When Inactive, the main thread is stopped on the applet::WaitForStarting function,
266 // and other threads also should be stopped. (Implementation-dependent on the application side.)
267 return nn::applet::REPLY_ACCEPT;
268 }
269 else
270 {
271 // The main thread is suspended here because it will sleep after the necessary processing completes
272 //
273 return nn::applet::REPLY_LATER;
274 }
275 }
276
277 /*------------------------------------------------------------------------*
278 Callback called when recovering from sleep
279 *------------------------------------------------------------------------*/
AwakeCallback(uptr arg)280 void TransitionHandler::AwakeCallback( uptr arg )
281 {
282 NN_UNUSED_VAR(arg);
283 s_AwakeEvent.Signal();
284
285 s_IsAfterWakeUp = true;
286 }
287