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