1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - SPI - demos - pm-1
3 File: main.c
4
5 Copyright 2003-2009 Nintendo. 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 $Date:: 2009-06-04#$
14 $Rev: 10698 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17 #include <nitro.h>
18 #include "font.h"
19 #include "screen.h"
20
21 //---- For battery display
22 char *myBatteryStr[] = { "HI", "LO", "--" };
23 #define MY_BATTERY_HI 0
24 #define MY_BATTERY_LO 1
25 #define MY_BATTERY_UNKNOWN 2
26
27 //---- For LCD switch (next status)
28 #define MY_LCD_KEEP 0 // No change
29 #define MY_LCD_OFF 1
30 #define MY_LCD_ON 2
31
32 static int myLCDNext = MY_LCD_KEEP;
33
34 //---- For power save
35 #define MY_POWER_SAVE_PERIOD 3000 // Milliseconds
36
37 //---- For battery check
38 #define MY_BATTERY_CHECK_INTERVAL 10 // Frame
39
40 static int myBatteryStatus = MY_BATTERY_UNKNOWN;
41 static u32 myBatteryCount;
42
43 //---- For RTC
44 static RTCTime myCurrentTime;
45 static int myResult;
46
47 //---- Alarm
48 static OSAlarm myAlarm;
49
50 //---- Message
51 #define MY_MESSAGE_SIZE 4
52
53 static OSMessage myMessageBuffer[MY_MESSAGE_SIZE];
54 static OSMessageQueue myMessageQueue;
55
56 //---- V-Count
57 static u32 myVCount;
58
59 //---- Sleep reason
60 #define MY_SLEEP_BY_CLOSE_COVER 0
61 #define MY_SLEEP_BY_PUSH_START 1
62 #define MY_SLEEP_BY_PUSH_LEFT 2
63 static u32 mySleepReason;
64
65 static void myInit(void);
66 static void myVBlankIntr(void);
67 static void myAlarmHandler(void *arg);
68
69 void myPreCallback(void *arg);
70 void myPostCallback(void *arg);
71 PMSleepCallbackInfo myPreCallbackInfo;
72 PMSleepCallbackInfo myPostCallbackInfo;
73
74 #ifdef SDK_TWL
75 //---- exit callback
76 PMExitCallbackInfo info;
77 void exitCallback(void*arg);
78 void batteryLowCallback(void*arg);
79 #endif
80
81 /*---------------------------------------------------------------------------*
82 Name: NitroMain
83
84 Description: Main.
85
86 Arguments: None.
87
88 Returns: None.
89 *---------------------------------------------------------------------------*/
NitroMain(void)90 void NitroMain(void)
91 {
92 u16 preButton;
93 u16 button;
94 u16 trigger;
95
96 //---------------- Initialize
97 myInit();
98 RTC_Init();
99
100 #ifdef SDK_TWL
101 if ( OS_IsRunOnTwl() )
102 {
103 PM_SetAutoExit( TRUE );
104 OS_Printf("[ARM9] set exit callback\n");
105 PM_SetExitCallbackInfo( &info, exitCallback, (void*)100 );
106 PM_AppendPreExitCallback( &info );
107
108 PM_SetBatteryLowCallback( batteryLowCallback, NULL );
109 }
110 #endif
111
112 OS_InitMessageQueue(&myMessageQueue, &myMessageBuffer[0], MY_MESSAGE_SIZE);
113 OS_CreateAlarm(&myAlarm);
114
115 preButton = PAD_Read(); // Dummy read for pressing 'A' on IPL
116
117 //---- set SleepMode callbacks
118 PM_SetSleepCallbackInfo(&myPreCallbackInfo, myPreCallback, (void *)&mySleepReason);
119 PM_SetSleepCallbackInfo(&myPostCallbackInfo, myPostCallback, NULL);
120 PM_AppendPreSleepCallback(&myPreCallbackInfo);
121 PM_AppendPostSleepCallback(&myPostCallbackInfo);
122
123 //---------------- Main loop
124 while (TRUE)
125 {
126 button = PAD_Read();
127 trigger = (u16)((button ^ preButton) & button);
128 preButton = button;
129
130 //---- V-Blank count
131 myVCount = OS_GetVBlankCount();
132
133 //---- Clear screen buffer
134 ClearScreen();
135
136 //---- Display key description
137 PrintString(3, 2, 15, "START : sleep till push");
138 PrintString(3, 3, 15, " SELECT");
139 PrintString(3, 4, 15, "A : top back light");
140 PrintString(3, 5, 15, "B : bottom back light");
141 #ifdef SDK_TWL
142 if ( OS_IsRunOnTwl() )
143 {
144 PrintString(3, 6, 15, "X : do hardware reset");
145 }
146 #endif
147 PrintString(3, 7, 15, "UP : power save till push");
148 PrintString(3, 8, 15, " DOWN or pass 3 secs");
149 PrintString(3, 9, 15, "LEFT : sleep till next min");
150 PrintString(3, 10, 15, " by RTC or push RIGHT");
151 PrintString(3, 12, 15, "CLOSE : sleep till open");
152 PrintString(3, 13, 15, "L & R : power off");
153
154 //---- Display time
155 myResult = RTC_GetTime(&myCurrentTime);
156 if (myResult == 0 /*No error */ )
157 {
158 PrintString(5, 20, 8, "%02d:%02d:%02d",
159 myCurrentTime.hour, myCurrentTime.minute, myCurrentTime.second);
160 }
161
162 //---- Display battery status
163 if (myBatteryCount < myVCount || myBatteryStatus == MY_BATTERY_UNKNOWN)
164 {
165 PMBattery battery;
166 u32 result = PM_GetBattery(&battery);
167
168 if ( result == PM_RESULT_SUCCESS )
169 {
170 myBatteryStatus = (battery == PM_BATTERY_HIGH) ? MY_BATTERY_HI : MY_BATTERY_LO;
171 }
172 else
173 {
174 OS_Printf("battery level busy\n");
175 myBatteryStatus = MY_BATTERY_UNKNOWN;
176 }
177
178 myBatteryCount = myVCount + MY_BATTERY_CHECK_INTERVAL;
179 }
180 {
181 PMBatteryLevel level;
182 if ( PM_GetBatteryLevel( &level ) == PM_RESULT_SUCCESS )
183 {
184 PrintString(3, 16, 15, "Battery status : %s val:%d", myBatteryStr[myBatteryStatus], level );
185 }
186 else
187 {
188 PrintString(3, 16, 15, "Battery status : %s val:-", myBatteryStr[myBatteryStatus] );
189 }
190 }
191
192 //---- Display AC adapter
193 {
194 BOOL isConnected;
195
196 if ( PM_GetACAdapter( &isConnected ) == PM_RESULT_SUCCESS )
197 {
198 PrintString(3, 17, 15, "AC Adapter : %s", isConnected? "PLUGGED": "NOT PLUGGED" );
199 }
200 else
201 {
202 PrintString(3, 17, 15, "AC Adapter : -" );
203 }
204 }
205
206 //---- Display counter
207 PrintString(18, 20, 4, "%08X", myVCount);
208
209 //---- Display LED pattern
210 {
211 PMLEDPattern pattern;
212 if ( PM_GetLEDPattern(&pattern) == PM_RESULT_SUCCESS )
213 {
214 PrintString(3, 18, 15, "LED Pattern : %d", pattern);
215 }
216 else
217 {
218 PrintString(3, 18, 15, "LED Pattern : -");
219 }
220 }
221
222 //---- Push START to sleep
223 if (trigger & PAD_BUTTON_START)
224 {
225 mySleepReason = MY_SLEEP_BY_PUSH_START;
226 PM_GoSleepMode(PM_TRIGGER_KEY, PM_PAD_LOGIC_AND, PAD_BUTTON_SELECT);
227 }
228
229 //---- Push A to switch top backlight on/off
230 if (trigger & PAD_BUTTON_A)
231 {
232 static int cnt = 0;
233 switch (cnt % 2)
234 {
235 case 0:
236 if ( PM_SetBackLight(PM_LCD_TOP, PM_BACKLIGHT_OFF) == PM_RESULT_SUCCESS )
237 {
238 cnt++;
239 }
240 break;
241 case 1:
242 if ( PM_SetBackLight(PM_LCD_TOP, PM_BACKLIGHT_ON) == PM_RESULT_SUCCESS )
243 {
244 cnt++;
245 }
246 break;
247 }
248 }
249
250 //---- Push B to switch top backlight on/off
251 if (trigger & PAD_BUTTON_B)
252 {
253 static int cnt = 0;
254 switch (cnt % 2)
255 {
256 case 0:
257 if ( PM_SetBackLight(PM_LCD_BOTTOM, PM_BACKLIGHT_OFF) == PM_RESULT_SUCCESS )
258 {
259 cnt++;
260 }
261 break;
262 case 1:
263 if ( PM_SetBackLight(PM_LCD_BOTTOM, PM_BACKLIGHT_ON) == PM_RESULT_SUCCESS )
264 {
265 cnt++;
266 }
267 break;
268 }
269 }
270
271 #ifdef SDK_TWL
272 if ( OS_IsRunOnTwl() )
273 {
274 //---- Push X to do hardware reset
275 if (trigger & PAD_BUTTON_X)
276 {
277 (void)OS_RebootSystem();
278 // Do not call PM_ForceToResetHardware directly
279 }
280
281 //---- Push Y to change wireless LED
282 if (trigger & PAD_BUTTON_Y)
283 {
284 static PMWirelessLEDStatus sw = PM_WIRELESS_LED_OFF;
285
286 if ( PMi_SetWirelessLED(sw) == PM_RESULT_SUCCESS )
287 {
288 sw = (sw == PM_WIRELESS_LED_OFF)? PM_WIRELESS_LED_ON: PM_WIRELESS_LED_OFF;
289 }
290 }
291 }
292 #endif
293
294 //---- Push UP for power save mode
295 if (trigger & PAD_KEY_UP && PM_GetLCDPower() == PM_LCD_POWER_ON && myLCDNext == MY_LCD_KEEP)
296 {
297 //---- Set 3-second alarm
298 OS_CancelAlarm(&myAlarm);
299 OS_SetAlarm(&myAlarm, OS_MilliSecondsToTicks(MY_POWER_SAVE_PERIOD), myAlarmHandler,
300 NULL);
301
302 //---- Turn LCD off
303 myLCDNext = MY_LCD_OFF;
304 }
305
306 //---- Push LEFT to sleep till next minute
307 if (trigger & PAD_KEY_LEFT)
308 {
309 RTCAlarmStatus st = RTC_ALARM_STATUS_ON;
310 RTCAlarmParam p;
311
312 p.week = RTC_WEEK_SUNDAY; // Dummy
313 p.hour = 1; // Dummy
314 p.minute = (myCurrentTime.minute == 59) ? 0 : (myCurrentTime.minute + 1);
315 p.enable = RTC_ALARM_ENABLE_MINUTE;
316
317 myResult = RTC_SetAlarmStatus(RTC_ALARM_CHAN_1, &st);
318 myResult = RTC_SetAlarmParam(RTC_ALARM_CHAN_1, &p);
319
320 mySleepReason = MY_SLEEP_BY_PUSH_LEFT;
321 PM_GoSleepMode(PM_TRIGGER_KEY | PM_TRIGGER_RTC_ALARM, PM_PAD_LOGIC_AND, PAD_KEY_RIGHT);
322 }
323
324 //---- Push DOWN to return from power save mode
325 if (trigger & PAD_KEY_DOWN && PM_GetLCDPower() == PM_LCD_POWER_OFF
326 && myLCDNext == MY_LCD_KEEP)
327 {
328 //---- Turn LCD on
329 myLCDNext = MY_LCD_ON;
330 OS_CancelAlarm(&myAlarm);
331 }
332
333 //---- Close cover to sleep
334 if (PAD_DetectFold() == TRUE)
335 {
336 myLCDNext = MY_LCD_KEEP;
337 mySleepReason = MY_SLEEP_BY_CLOSE_COVER;
338 PM_GoSleepMode(PM_TRIGGER_COVER_OPEN | PM_TRIGGER_CARD, 0, 0);
339 }
340
341 //---- Push L & R to power off
342 if ((button & (PAD_BUTTON_L | PAD_BUTTON_R)) == (PAD_BUTTON_L | PAD_BUTTON_R))
343 {
344 (void)PM_ForceToPowerOff();
345 }
346
347 //---- Switch LCD power
348 if (myLCDNext != MY_LCD_KEEP)
349 {
350 if (myLCDNext == MY_LCD_OFF)
351 {
352 OS_WaitVBlankIntr();
353 GX_DispOff();
354 GXS_DispOff();
355 OS_WaitVBlankIntr();
356 if (PM_SetLCDPower(PM_LCD_POWER_OFF))
357 {
358 myLCDNext = MY_LCD_KEEP;
359 }
360 }
361 else if (myLCDNext == MY_LCD_ON)
362 {
363 if (PM_SetLCDPower(PM_LCD_POWER_ON))
364 {
365 OS_WaitVBlankIntr();
366 GX_DispOn();
367 GXS_DispOn();
368 OS_WaitVBlankIntr();
369 myLCDNext = MY_LCD_KEEP;
370 }
371 }
372 }
373
374 OS_WaitVBlankIntr();
375 }
376 }
377
378 //----------------------------------------------------------------
379 // myInit
380 //
myInit(void)381 void myInit(void)
382 {
383 //---- Init
384 OS_Init();
385 OS_InitTick();
386 OS_InitAlarm();
387 FX_Init();
388 GX_Init();
389 GX_DispOff();
390 GXS_DispOff();
391
392 //---- Display init
393 GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);
394 MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
395 (void)GX_DisableBankForLCDC();
396
397 MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE);
398 MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE);
399 MI_CpuFillFast((void *)HW_DB_OAM, 192, HW_DB_OAM_SIZE);
400 MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE);
401
402 //---- Setting 2D for top screen
403 GX_SetBankForBG(GX_VRAM_BG_128_A);
404
405 G2_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256,
406 GX_BG_COLORMODE_16,
407 GX_BG_SCRBASE_0xf800, GX_BG_CHARBASE_0x00000, GX_BG_EXTPLTT_01);
408 G2_SetBG0Priority(0);
409 G2_BG0Mosaic(FALSE);
410 GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D);
411 GX_SetVisiblePlane(GX_PLANEMASK_BG0);
412
413 GX_LoadBG0Char(d_CharData, 0, sizeof(d_CharData));
414 GX_LoadBGPltt(d_PaletteData, 0, sizeof(d_PaletteData));
415
416
417
418 //---- Setting 2D for bottom screen
419 GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C);
420
421 G2S_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256,
422 GX_BG_COLORMODE_16,
423 GX_BG_SCRBASE_0xf800, GX_BG_CHARBASE_0x00000, GX_BG_EXTPLTT_01);
424 G2S_SetBG0Priority(0);
425 G2S_BG0Mosaic(FALSE);
426 GXS_SetGraphicsMode(GX_BGMODE_0);
427 GXS_SetVisiblePlane(GX_PLANEMASK_BG0);
428
429 GXS_LoadBG0Char(d_CharData, 0, sizeof(d_CharData));
430 GXS_LoadBGPltt(d_PaletteData, 0, sizeof(d_PaletteData));
431
432
433 //---- Screen
434 MI_CpuFillFast((void *)gScreen, 0, sizeof(gScreen));
435 DC_FlushRange(gScreen, sizeof(gScreen));
436 /* I/O register is accessed using DMA operation, so cache wait is not needed */
437 // DC_WaitWriteBufferEmpty();
438 GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
439 GXS_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
440
441 //---- Init interrupt
442 OS_SetIrqFunction(OS_IE_V_BLANK, myVBlankIntr);
443 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
444 (void)GX_VBlankIntr(TRUE);
445 (void)OS_EnableIrq();
446 (void)OS_EnableInterrupts();
447
448 //---- FileSytem init
449 FS_Init(FS_DMA_NOT_USE);
450
451 //---- Start displaying
452 GX_DispOn();
453 GXS_DispOn();
454 }
455
456 //----------------------------------------------------------------
457 // myVBlankIntr
458 // V-Blank interrupt handler
459 //
myVBlankIntr(void)460 static void myVBlankIntr(void)
461 {
462 //---- Upload pseudo screen to VRAM
463 DC_FlushRange(gScreen, sizeof(gScreen));
464 /* I/O register is accessed using DMA operation, so cache wait is not needed */
465 // DC_WaitWriteBufferEmpty();
466 GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
467 GXS_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
468
469 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
470 }
471
472 //----------------------------------------------------------------
473 // myAlarmHandler
474 // Alarm interrupt handler
475 //
myAlarmHandler(void * arg)476 void myAlarmHandler(void *arg)
477 {
478 #pragma unused(arg)
479 if (PM_GetLCDPower() == PM_LCD_POWER_OFF && myLCDNext == MY_LCD_KEEP)
480 {
481 myLCDNext = MY_LCD_ON;
482 }
483 }
484
485 //================================================================
486 //----------------------------------------------------------------
487 // myPreCallback
488 //
489 static const char *myCallbackReasonStr[] = {
490 "closing cover",
491 "pushing START",
492 "pushing LEFT"
493 };
494
myPreCallback(void * arg)495 void myPreCallback(void *arg)
496 {
497 int reason = *(int *)arg;
498 OS_Printf("Go to sleep mode by %s\n", myCallbackReasonStr[reason]);
499 }
500
501 //----------------------------------------------------------------
502 // myPostCallback
503 //
myPostCallback(void * arg)504 void myPostCallback(void *arg)
505 {
506 #pragma unused(arg)
507 OS_Printf("Return from sleep mode.\n");
508 }
509
510 #ifdef SDK_TWL
511 //----------------------------------------------------------------
512 // exitCallback
513 //
exitCallback(void * arg)514 void exitCallback(void *arg)
515 {
516 #ifdef SDK_FINALROM
517 #pragma unused( arg )
518 #endif
519 OS_Printf("exit callback. arg=%d factor=%d\n", arg, PM_GetExitFactor() );
520 }
521
522 //----------------------------------------------------------------
523 // batteryLowCallback
524 //
batteryLowCallback(void * arg)525 void batteryLowCallback(void *arg)
526 {
527 #ifdef SDK_FINALROM
528 #pragma unused( arg )
529 #endif
530 OS_Printf("battery low callback. arg=%d\n", arg);
531 }
532 #endif
533