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