1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WVR - demos - simple
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-08-31#$
14   $Rev: 11029 $
15   $Author: tominaga_masafumi $
16  *---------------------------------------------------------------------------*/
17 
18 #include    <nitro.h>
19 #include    <nitro/wm.h>
20 #include    <nitro/wvr.h>
21 
22 #include    "font.h"
23 #include    "wh.h"
24 
25 
26 /*---------------------------------------------------------------------------*
27     Constant definitions
28  *---------------------------------------------------------------------------*/
29 #define     KEY_REPEAT_START    25     // Number of frames until key repeat starts
30 #define     KEY_REPEAT_SPAN     10     // Number of frames between key repeats
31 
32 #define     PICTURE_FRAME_PER_GAME_FRAME    1
33 
34 #define     DEFAULT_GGID            0x003fff60
35 #define     NUM_MAX_CHILD           15
36 #define     DEFAULT_CHAN            1
37 #define     PARENT_DATA_SIZE        4
38 #define     CHILD_DATA_SIZE         4
39 
40 /*---------------------------------------------------------------------------*
41     Structure definitions
42  *---------------------------------------------------------------------------*/
43 // Key input data
44 typedef struct KeyInfo
45 {
46     u16     cnt;                       // Unprocessed input value
47     u16     trg;                       // Push trigger input
48     u16     up;                        // Release trigger input
49     u16     rep;                       // Press and hold repeat input
50 
51 }
52 KeyInfo;
53 
54 
55 /*---------------------------------------------------------------------------*
56     Internal Function Definitions
57  *---------------------------------------------------------------------------*/
58 static void StartUpCallback(void *arg, WVRResult result);
59 
60 static void ModeSelect(void);          // Parent/child select screen
61 static void ModeError(void);           // Error display screen
62 static void ModeWorking(void);         // Busy screen
63 static void ModeParent(void);          // Parent communications screen
64 static void ModeChild(void);           // Child communications screen
65 static void VBlankIntr(void);          // V-Blank interrupt handler
66 
67 // Functions called when receiving data
68 static void MpReceiveCallback(u16 aid, u16 *data, u16 length);
69 
70 // General purpose subroutines
71 static void KeyRead(KeyInfo * pKey);
72 static void ClearString(void);
73 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...);
74 static void ColorString(s16 x, s16 y, s16 length, u8 palette);
75 static void InitializeAllocateSystem(void);
76 
77 
78 /*---------------------------------------------------------------------------*
79     Internal Variable Definitions
80  *---------------------------------------------------------------------------*/
81 static u16 gScreen[32 * 32];           // Virtual screen
82 static KeyInfo gKey;                   // Key input
83 static u32 gFrame;                     // Frame counter
84 
85 // Send/receive buffer for display
86 static u32 gSendBuf[1024] ATTRIBUTE_ALIGN(32);
87 static u32 gRecvBuf[1 + WM_NUM_MAX_CHILD][1024];
88 static BOOL gRecvFlag[1 + WM_NUM_MAX_CHILD];
89 
90 static volatile u8 startCheck;
91 
92 
93 /*---------------------------------------------------------------------------*
94   Name:         NitroMain
95 
96   Description:  Initialization and main loop.
97 
98   Arguments:    None.
99 
100   Returns:      None.
101  *---------------------------------------------------------------------------*/
NitroMain(void)102 void NitroMain(void)
103 {
104     // Various types of initialization
105     OS_Init();
106     FX_Init();
107     GX_Init();
108     GX_DispOff();
109     GXS_DispOff();
110 
111     // Initializes display settings
112     GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);
113     MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
114     (void)GX_DisableBankForLCDC();
115     MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE);
116     MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE);
117     MI_CpuFillFast((void *)HW_DB_OAM, 192, HW_DB_OAM_SIZE);
118     MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE);
119 
120     // 2D display settings for text string display
121     GX_SetBankForBG(GX_VRAM_BG_128_A);
122     G2_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16, GX_BG_SCRBASE_0xf800,      // SCR base block 31
123                      GX_BG_CHARBASE_0x00000,    // CHR base block 0
124                      GX_BG_EXTPLTT_01);
125     G2_SetBG0Priority(0);
126     G2_BG0Mosaic(FALSE);
127     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D);
128     GX_SetVisiblePlane(GX_PLANEMASK_BG0);
129     GX_LoadBG0Char(d_CharData, 0, sizeof(d_CharData));
130     GX_LoadBGPltt(d_PaletteData, 0, sizeof(d_PaletteData));
131     MI_CpuFillFast((void *)gScreen, 0, sizeof(gScreen));
132     DC_FlushRange(gScreen, sizeof(gScreen));
133     /* I/O register is accessed using DMA operation, so cache wait is not needed */
134     // DC_WaitWriteBufferEmpty();
135     GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
136 
137     // Interrupt settings
138     OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
139     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
140     (void)GX_VBlankIntr(TRUE);
141     (void)OS_EnableIrq();
142     (void)OS_EnableInterrupts();
143 
144     // Memory allocation
145     InitializeAllocateSystem();
146 
147     // LCD display start
148     GX_DispOn();
149     GXS_DispOn();
150 
151     //************************************
152     // Start activating the wireless library
153     {
154         startCheck = 0;
155         if (WVR_RESULT_OPERATING != WVR_StartUpAsync(GX_VRAM_ARM7_128_D, StartUpCallback, NULL))
156         {
157             OS_TPanic("WVR_StartUpAsync failed. \n");
158         }
159         while (!startCheck)
160         {
161         }
162     }
163     //************************************
164     //************************************
165     // Wireless settings
166     WH_SetGgid(DEFAULT_GGID);
167     //************************************
168 
169     // Debug string output
170     OS_Printf("ARM9: ichneumon test program started.\n");
171 
172     // Empty call for getting key input data (strategy for pressing A Button in the IPL)
173     KeyRead(&gKey);
174 
175     // Main loop
176     for (gFrame = 0; TRUE; gFrame++)
177     {
178         // Get key input data
179         KeyRead(&gKey);
180 
181         // Clear the screen
182         ClearString();
183 
184         // Distributes processes based on communication status
185         switch (WH_GetSystemState())
186         {
187         case WH_SYSSTATE_STOP:
188             ModeSelect();
189             break;
190         case WH_SYSSTATE_IDLE:
191         case WH_SYSSTATE_ERROR:
192         case WH_SYSSTATE_CONNECT_FAIL:
193             // End communication
194             WH_Finalize();
195             while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
196             (void)WH_End();
197             while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
198             break;
199         case WH_SYSSTATE_FATAL:
200             ModeError();
201             break;
202         case WH_SYSSTATE_BUSY:
203         case WH_SYSSTATE_SCANNING:
204             ModeWorking();
205             break;
206         case WH_SYSSTATE_CONNECTED:
207             switch (WH_GetConnectMode())
208             {
209             case WH_CONNECTMODE_MP_PARENT:
210                 ModeParent();
211                 break;
212             case WH_CONNECTMODE_MP_CHILD:
213                 ModeChild();
214                 break;
215             }
216             break;
217         }
218 
219         // Waiting for the V-Blank
220         OS_WaitVBlankIntr();
221     }
222 }
223 
224 /*---------------------------------------------------------------------------*
225   Name:         StartUpCallback
226 
227   Description:  Callback function that notifies of asynchronous process completion in wireless control library.
228 
229 
230   Arguments:    arg: Argument specified when WVR_StartUpAsync is called. Not used.
231                 result: The processing results from the asynchronous function.
232 
233   Returns:      None.
234  *---------------------------------------------------------------------------*/
StartUpCallback(void * arg,WVRResult result)235 static void StartUpCallback(void *arg, WVRResult result)
236 {
237 #pragma unused( arg )
238 
239     if (result != WVR_RESULT_SUCCESS)
240     {
241         OS_TPanic("WVR_StartUpAsync error.[%08xh]\n", result);
242     }
243     startCheck = 1;
244 }
245 
246 /*---------------------------------------------------------------------------*
247   Name:         ModeSelect
248 
249   Description:  Processing in parent/child selection screen.
250 
251   Arguments:    None.
252 
253   Returns:      None.
254  *---------------------------------------------------------------------------*/
ModeSelect(void)255 static void ModeSelect(void)
256 {
257     PrintString(3, 10, 0xf, "Push A to connect as PARENT");
258     PrintString(3, 12, 0xf, "Push B to connect as CHILD");
259 
260     if (gKey.trg & PAD_BUTTON_A)
261     {
262         //********************************
263         s32     i;
264 
265         // WH initialization
266         if (!WH_Initialize())
267         {
268             OS_Panic("WH_Initiailze failed.");
269         }
270         else
271         {
272             // Wait for initialization to complete
273             while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
274         }
275         WH_SetReceiver(MpReceiveCallback);
276 
277         for (i = 1; i < (WM_NUM_MAX_CHILD + 1); i++)
278         {
279             gRecvFlag[i] = FALSE;
280         }
281 
282         (void)WH_ParentConnect(WH_CONNECTMODE_MP_PARENT, 0x0000, DEFAULT_CHAN);
283         //********************************
284     }
285     else if (gKey.trg & PAD_BUTTON_B)
286     {
287         static const u8 ANY_PARENT[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
288 
289         // WH initialization
290         if (!WH_Initialize())
291         {
292             OS_Panic("WH_Initiailze failed.");
293         }
294         else
295         {
296             // Wait for initialization to complete
297             while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
298         }
299         WH_SetReceiver(MpReceiveCallback);
300 
301         //********************************
302         (void)WH_ChildConnectAuto(WH_CONNECTMODE_MP_CHILD, ANY_PARENT, DEFAULT_CHAN);
303         //********************************
304     }
305 }
306 
307 /*---------------------------------------------------------------------------*
308   Name:         ModeError
309 
310   Description:  Processing in error display screen.
311 
312   Arguments:    None.
313 
314   Returns:      None.
315  *---------------------------------------------------------------------------*/
ModeError(void)316 static void ModeError(void)
317 {
318     PrintString(5, 10, 0x1, "======= ERROR! =======");
319     PrintString(5, 13, 0xf, " Fatal error occured.");
320     PrintString(5, 14, 0xf, "Please reboot program.");
321 }
322 
323 /*---------------------------------------------------------------------------*
324   Name:         ModeWorking
325 
326   Description:  Processing in busy screen.
327 
328   Arguments:    None.
329 
330   Returns:      None.
331  *---------------------------------------------------------------------------*/
ModeWorking(void)332 static void ModeWorking(void)
333 {
334     PrintString(9, 11, 0xf, "Now working...");
335 
336     if (gKey.trg & PAD_BUTTON_START)
337     {
338         //********************************
339         // End communication
340         WH_Finalize();
341         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
342         (void)WH_End();
343         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
344         //********************************
345     }
346 }
347 
348 /*---------------------------------------------------------------------------*
349   Name:         ModeParent
350 
351   Description:  Processing in parent communications screen.
352 
353   Arguments:    None.
354 
355   Returns:      None.
356  *---------------------------------------------------------------------------*/
ModeParent(void)357 static void ModeParent(void)
358 {
359     PrintString(8, 1, 0x2, "Parent mode");
360     PrintString(4, 3, 0x4, "Send:     %08X", gSendBuf[0]);
361     PrintString(4, 5, 0x4, "Receive:");
362     {
363         s32     i;
364 
365         for (i = 1; i < (WM_NUM_MAX_CHILD + 1); i++)
366         {
367             if (gRecvFlag[i])
368             {
369                 PrintString(5, (s16)(6 + i), 0x4, "Child%02d: %08X", i, gRecvBuf[i][0]);
370             }
371             else
372             {
373                 PrintString(5, (s16)(6 + i), 0x7, "No child");
374             }
375         }
376     }
377 
378     if (gKey.trg & PAD_BUTTON_START)
379     {
380         //********************************
381         // End communication
382         WH_Finalize();
383         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
384         (void)WH_End();
385         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
386         //********************************
387     }
388 }
389 
390 /*---------------------------------------------------------------------------*
391   Name:         ModeChild
392 
393   Description:  Processing in child communications screen.
394 
395   Arguments:    None.
396 
397   Returns:      None.
398  *---------------------------------------------------------------------------*/
ModeChild(void)399 static void ModeChild(void)
400 {
401     PrintString(8, 1, 0x2, "Child mode");
402     PrintString(4, 3, 0x4, "Send:     %08X", gSendBuf[0]);
403     PrintString(4, 5, 0x4, "Receive:");
404     PrintString(5, 7, 0x4, "Parent:  %08X", gRecvBuf[0][0]);
405 
406     if (gKey.trg & PAD_BUTTON_START)
407     {
408         //********************************
409         // End communication
410         WH_Finalize();
411         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
412         (void)WH_End();
413         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
414         //********************************
415     }
416 }
417 
418 /*---------------------------------------------------------------------------*
419   Name:         VBlankIntr
420 
421   Description:  V-Blank interrupt vector.
422 
423   Arguments:    None.
424 
425   Returns:      None.
426  *---------------------------------------------------------------------------*/
VBlankIntr(void)427 static void VBlankIntr(void)
428 {
429     // Start sending new data
430     if (WH_GetSystemState() == WH_SYSSTATE_CONNECTED)
431     {
432         switch (WH_GetConnectMode())
433         {
434         case WH_CONNECTMODE_MP_PARENT:
435             gSendBuf[0] = gFrame;
436             //********************************
437             (void)WH_SendData(gSendBuf, PARENT_DATA_SIZE, NULL);
438             //********************************
439             break;
440         case WH_CONNECTMODE_MP_CHILD:
441             gSendBuf[0] = gFrame;
442             //********************************
443             (void)WH_SendData(gSendBuf, CHILD_DATA_SIZE, NULL);
444             //********************************
445             break;
446         }
447     }
448 
449     // Reflect virtual screen in VRAM
450     DC_FlushRange(gScreen, sizeof(gScreen));
451     /* I/O register is accessed using DMA operation, so cache wait is not needed */
452     // DC_WaitWriteBufferEmpty();
453     GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
454 
455     // Sets the IRQ check flag
456     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
457 }
458 
459 /*---------------------------------------------------------------------------*
460   Name:         MpReceiveCallback
461 
462   Description:  Function called when MP data is received.
463 
464   Arguments:    aid: AID of child originating transmission (if 0, then data is from parent)
465                 data: Pointer to received data (NULL is disconnection notification)
466                 length: Size of received data
467 
468   Returns:      None.
469  *---------------------------------------------------------------------------*/
MpReceiveCallback(u16 aid,u16 * data,u16 length)470 static void MpReceiveCallback(u16 aid, u16 *data, u16 length)
471 {
472 #pragma unused( length )
473     SDK_MAX_ASSERT(aid, 15);
474 
475     if (data != NULL)
476     {
477         SDK_ASSERT(length >= 4);
478         gRecvFlag[aid] = TRUE;
479         // Copy source is aligned to 2 bytes (not 4 bytes)
480         if (aid == 0)
481         {
482             // When receiving from a parent
483             MI_CpuCopy8(data, &(gRecvBuf[aid][0]), PARENT_DATA_SIZE);
484         }
485         else
486         {
487             MI_CpuCopy8(data, &(gRecvBuf[aid][0]), CHILD_DATA_SIZE);
488         }
489     }
490     else
491     {
492         gRecvFlag[aid] = FALSE;
493     }
494 }
495 
496 /*---------------------------------------------------------------------------*
497   Name:         KeyRead
498 
499   Description:  Edits key input data
500                 Detects press trigger, release trigger, and press-and-hold repeat.
501 
502   Arguments:    pKey: Structure that holds key input data to be edited
503 
504   Returns:      None.
505  *---------------------------------------------------------------------------*/
KeyRead(KeyInfo * pKey)506 static void KeyRead(KeyInfo * pKey)
507 {
508     static u16 repeat_count[12];
509     int     i;
510     u16     r;
511 
512     r = PAD_Read();
513     pKey->trg = 0x0000;
514     pKey->up = 0x0000;
515     pKey->rep = 0x0000;
516 
517     for (i = 0; i < 12; i++)
518     {
519         if (r & (0x0001 << i))
520         {
521             if (!(pKey->cnt & (0x0001 << i)))
522             {
523                 pKey->trg |= (0x0001 << i);     // Press trigger
524                 repeat_count[i] = 1;
525             }
526             else
527             {
528                 if (repeat_count[i] > KEY_REPEAT_START)
529                 {
530                     pKey->rep |= (0x0001 << i); // Press-and-hold repeat
531                     repeat_count[i] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
532                 }
533                 else
534                 {
535                     repeat_count[i]++;
536                 }
537             }
538         }
539         else
540         {
541             if (pKey->cnt & (0x0001 << i))
542             {
543                 pKey->up |= (0x0001 << i);      // Release trigger
544             }
545         }
546     }
547     pKey->cnt = r;                     // Unprocessed key input
548 }
549 
550 /*---------------------------------------------------------------------------*
551   Name:         ClearString
552 
553   Description:  Clears the virtual screen.
554 
555   Arguments:    None.
556 
557   Returns:      None.
558  *---------------------------------------------------------------------------*/
ClearString(void)559 static void ClearString(void)
560 {
561     MI_CpuClearFast((void *)gScreen, sizeof(gScreen));
562 }
563 
564 /*---------------------------------------------------------------------------*
565   Name:         PrintString
566 
567   Description:  Positions the text string on the virtual screen. The string can be up to 32 chars.
568 
569   Arguments:    x: X-coordinate where character string starts (x 8 pixels).
570                 y: Y-coordinate where character string starts (x 8 pixels).
571                 palette: Specify text color by palette number.
572                 text: Text string to position. Null-terminated.
573                 ...: Virtual argument.
574 
575   Returns:      None.
576  *---------------------------------------------------------------------------*/
PrintString(s16 x,s16 y,u8 palette,char * text,...)577 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...)
578 {
579     va_list vlist;
580     char    temp[32 + 2];
581     s32     i;
582 
583     va_start(vlist, text);
584     (void)vsnprintf(temp, 33, text, vlist);
585     va_end(vlist);
586 
587     *(u16 *)(&temp[32]) = 0x0000;
588     for (i = 0;; i++)
589     {
590         if (temp[i] == 0x00)
591         {
592             break;
593         }
594         gScreen[((y * 32) + x + i) % (32 * 32)] = (u16)((palette << 12) | temp[i]);
595     }
596 }
597 
598 /*---------------------------------------------------------------------------*
599   Name:         ColorString
600 
601   Description:  Changes the color of character strings printed on the virtual screen.
602 
603   Arguments:    x:         X-coordinate (x 8 pixels) from which to start color change.
604                 y:         Y-coordinate (x 8 pixels) from which to start color change.
605                 length:   Number of characters to continue the color change for.
606                 palette: Specify text color by palette number.
607 
608   Returns:      None.
609  *---------------------------------------------------------------------------*/
ColorString(s16 x,s16 y,s16 length,u8 palette)610 static void ColorString(s16 x, s16 y, s16 length, u8 palette)
611 {
612     s32     i;
613     u16     temp;
614     s32     index;
615 
616     if (length < 0)
617         return;
618 
619     for (i = 0; i < length; i++)
620     {
621         index = ((y * 32) + x + i) % (32 * 32);
622         temp = gScreen[index];
623         temp &= 0x0fff;
624         temp |= (palette << 12);
625         gScreen[index] = temp;
626     }
627 }
628 
629 /*---------------------------------------------------------------------------*
630   Name:         InitializeAllocateSystem
631 
632   Description:  Initializes the memory allocation system within the main memory arena.
633 
634   Arguments:    None.
635 
636   Returns:      None.
637  *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)638 static void InitializeAllocateSystem(void)
639 {
640     void   *tempLo;
641     OSHeapHandle hh;
642 
643     // Based on the premise that OS_Init has been already called
644     tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
645     OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
646     hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
647     if (hh < 0)
648     {
649         OS_Panic("ARM9: Fail to create heap...\n");
650     }
651     hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
652 }
653