1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WVR - demos - simple
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   $Date:: 2008-12-16#$
14   $Rev: 9665 $
15   $Author: kitase_hirotake $
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     // Initialize wireless
166     if (!WH_Initialize())
167     {
168         OS_Panic("WH_Initialize failed.");
169     }
170     WH_SetGgid(DEFAULT_GGID);
171     WH_SetReceiver(MpReceiveCallback);
172     //************************************
173 
174     // Debug string output
175     OS_Printf("ARM9: ichneumon test program started.\n");
176 
177     // Empty call for getting key input data (strategy for pressing A Button in the IPL)
178     KeyRead(&gKey);
179 
180     // Main loop
181     for (gFrame = 0; TRUE; gFrame++)
182     {
183         // Get key input data
184         KeyRead(&gKey);
185 
186         // Clear the screen
187         ClearString();
188 
189         // Distributes processes based on communication status
190         switch (WH_GetSystemState())
191         {
192         case WH_SYSSTATE_IDLE:
193             ModeSelect();
194             break;
195         case WH_SYSSTATE_ERROR:
196         case WH_SYSSTATE_CONNECT_FAIL:
197             WH_Reset();
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 to be notified end of async processing in wireless operation control library.
228 
229 
230   Arguments:    arg: Argument specified when WVR_StartUpAsync is called. Not used.
231                 result: The processing results from async 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:  Process 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         for (i = 1; i < (WM_NUM_MAX_CHILD + 1); i++)
266         {
267             gRecvFlag[i] = FALSE;
268         }
269 
270         (void)WH_ParentConnect(WH_CONNECTMODE_MP_PARENT, 0x0000, DEFAULT_CHAN);
271         //********************************
272     }
273     else if (gKey.trg & PAD_BUTTON_B)
274     {
275         static const u8 ANY_PARENT[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
276         //********************************
277         (void)WH_ChildConnectAuto(WH_CONNECTMODE_MP_CHILD, ANY_PARENT, DEFAULT_CHAN);
278         //********************************
279     }
280 }
281 
282 /*---------------------------------------------------------------------------*
283   Name:         ModeError
284 
285   Description:  Processing in error display screen.
286 
287   Arguments:    None.
288 
289   Returns:      None.
290  *---------------------------------------------------------------------------*/
ModeError(void)291 static void ModeError(void)
292 {
293     PrintString(5, 10, 0x1, "======= ERROR! =======");
294     PrintString(5, 13, 0xf, " Fatal error occured.");
295     PrintString(5, 14, 0xf, "Please reboot program.");
296 }
297 
298 /*---------------------------------------------------------------------------*
299   Name:         ModeWorking
300 
301   Description:  Processing in busy screen.
302 
303   Arguments:    None.
304 
305   Returns:      None.
306  *---------------------------------------------------------------------------*/
ModeWorking(void)307 static void ModeWorking(void)
308 {
309     PrintString(9, 11, 0xf, "Now working...");
310 
311     if (gKey.trg & PAD_BUTTON_START)
312     {
313         //********************************
314         WH_Finalize();
315         //********************************
316     }
317 }
318 
319 /*---------------------------------------------------------------------------*
320   Name:         ModeParent
321 
322   Description:  Processing in parent communications screen.
323 
324   Arguments:    None.
325 
326   Returns:      None.
327  *---------------------------------------------------------------------------*/
ModeParent(void)328 static void ModeParent(void)
329 {
330     PrintString(8, 1, 0x2, "Parent mode");
331     PrintString(4, 3, 0x4, "Send:     %08X", gSendBuf[0]);
332     PrintString(4, 5, 0x4, "Receive:");
333     {
334         s32     i;
335 
336         for (i = 1; i < (WM_NUM_MAX_CHILD + 1); i++)
337         {
338             if (gRecvFlag[i])
339             {
340                 PrintString(5, (s16)(6 + i), 0x4, "Child%02d: %08X", i, gRecvBuf[i][0]);
341             }
342             else
343             {
344                 PrintString(5, (s16)(6 + i), 0x7, "No child");
345             }
346         }
347     }
348 
349     if (gKey.trg & PAD_BUTTON_START)
350     {
351         //********************************
352         WH_Finalize();
353         //********************************
354     }
355 }
356 
357 /*---------------------------------------------------------------------------*
358   Name:         ModeChild
359 
360   Description:  Processing in child communications screen.
361 
362   Arguments:    None.
363 
364   Returns:      None.
365  *---------------------------------------------------------------------------*/
ModeChild(void)366 static void ModeChild(void)
367 {
368     PrintString(8, 1, 0x2, "Child mode");
369     PrintString(4, 3, 0x4, "Send:     %08X", gSendBuf[0]);
370     PrintString(4, 5, 0x4, "Receive:");
371     PrintString(5, 7, 0x4, "Parent:  %08X", gRecvBuf[0][0]);
372 
373     if (gKey.trg & PAD_BUTTON_START)
374     {
375         //********************************
376         WH_Finalize();
377         //********************************
378     }
379 }
380 
381 /*---------------------------------------------------------------------------*
382   Name:         VBlankIntr
383 
384   Description:  V-Blank interrupt vector.
385 
386   Arguments:    None.
387 
388   Returns:      None.
389  *---------------------------------------------------------------------------*/
VBlankIntr(void)390 static void VBlankIntr(void)
391 {
392     // Start sending new data
393     if (WH_GetSystemState() == WH_SYSSTATE_CONNECTED)
394     {
395         switch (WH_GetConnectMode())
396         {
397         case WH_CONNECTMODE_MP_PARENT:
398             gSendBuf[0] = gFrame;
399             //********************************
400             (void)WH_SendData(gSendBuf, PARENT_DATA_SIZE, NULL);
401             //********************************
402             break;
403         case WH_CONNECTMODE_MP_CHILD:
404             gSendBuf[0] = gFrame;
405             //********************************
406             (void)WH_SendData(gSendBuf, CHILD_DATA_SIZE, NULL);
407             //********************************
408             break;
409         }
410     }
411 
412     // Reflect virtual screen in VRAM
413     DC_FlushRange(gScreen, sizeof(gScreen));
414     /* I/O register is accessed using DMA operation, so cache wait is not needed */
415     // DC_WaitWriteBufferEmpty();
416     GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
417 
418     // Sets the IRQ check flag
419     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
420 }
421 
422 /*---------------------------------------------------------------------------*
423   Name:         MpReceiveCallback
424 
425   Description:  Function called when MP data is received.
426 
427   Arguments:    aid: AID of child originating transmission (if 0, then data is from parent)
428                 data: Pointer to received data (NULL is disconnection notification)
429                 length: Size of received data
430 
431   Returns:      None.
432  *---------------------------------------------------------------------------*/
MpReceiveCallback(u16 aid,u16 * data,u16 length)433 static void MpReceiveCallback(u16 aid, u16 *data, u16 length)
434 {
435 #pragma unused( length )
436     SDK_MAX_ASSERT(aid, 15);
437 
438     if (data != NULL)
439     {
440         SDK_ASSERT(length >= 4);
441         gRecvFlag[aid] = TRUE;
442         // Copy source is aligned to 2 bytes (not 4 bytes)
443         if (aid == 0)
444         {
445             // When receiving from a parent
446             MI_CpuCopy8(data, &(gRecvBuf[aid][0]), PARENT_DATA_SIZE);
447         }
448         else
449         {
450             MI_CpuCopy8(data, &(gRecvBuf[aid][0]), CHILD_DATA_SIZE);
451         }
452     }
453     else
454     {
455         gRecvFlag[aid] = FALSE;
456     }
457 }
458 
459 /*---------------------------------------------------------------------------*
460   Name:         KeyRead
461 
462   Description:  Edits key input data.
463                 Detects press trigger, release trigger, and press-and-hold repeat.
464 
465   Arguments:    pKey: Structure that holds key input data to be edited
466 
467   Returns:      None.
468  *---------------------------------------------------------------------------*/
KeyRead(KeyInfo * pKey)469 static void KeyRead(KeyInfo * pKey)
470 {
471     static u16 repeat_count[12];
472     int     i;
473     u16     r;
474 
475     r = PAD_Read();
476     pKey->trg = 0x0000;
477     pKey->up = 0x0000;
478     pKey->rep = 0x0000;
479 
480     for (i = 0; i < 12; i++)
481     {
482         if (r & (0x0001 << i))
483         {
484             if (!(pKey->cnt & (0x0001 << i)))
485             {
486                 pKey->trg |= (0x0001 << i);     // Press trigger
487                 repeat_count[i] = 1;
488             }
489             else
490             {
491                 if (repeat_count[i] > KEY_REPEAT_START)
492                 {
493                     pKey->rep |= (0x0001 << i); // Press-and-hold repeat
494                     repeat_count[i] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
495                 }
496                 else
497                 {
498                     repeat_count[i]++;
499                 }
500             }
501         }
502         else
503         {
504             if (pKey->cnt & (0x0001 << i))
505             {
506                 pKey->up |= (0x0001 << i);      // Release trigger
507             }
508         }
509     }
510     pKey->cnt = r;                     // Unprocessed key input
511 }
512 
513 /*---------------------------------------------------------------------------*
514   Name:         ClearString
515 
516   Description:  Clears the virtual screen.
517 
518   Arguments:    None.
519 
520   Returns:      None.
521  *---------------------------------------------------------------------------*/
ClearString(void)522 static void ClearString(void)
523 {
524     MI_CpuClearFast((void *)gScreen, sizeof(gScreen));
525 }
526 
527 /*---------------------------------------------------------------------------*
528   Name:         PrintString
529 
530   Description:  Positions the text string on the virtual screen. The string can be up to 32 chars.
531 
532   Arguments:    x: X-coordinate where character string starts (x 8 dots)
533                 y: Y-coordinate where character string starts (x 8 dots)
534                 palette: Specify text color by palette number
535                 text: Text string to position. NULL terminated
536                 ...: Virtual argument
537 
538   Returns:      None.
539  *---------------------------------------------------------------------------*/
PrintString(s16 x,s16 y,u8 palette,char * text,...)540 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...)
541 {
542     va_list vlist;
543     char    temp[32 + 2];
544     s32     i;
545 
546     va_start(vlist, text);
547     (void)vsnprintf(temp, 33, text, vlist);
548     va_end(vlist);
549 
550     *(u16 *)(&temp[32]) = 0x0000;
551     for (i = 0;; i++)
552     {
553         if (temp[i] == 0x00)
554         {
555             break;
556         }
557         gScreen[((y * 32) + x + i) % (32 * 32)] = (u16)((palette << 12) | temp[i]);
558     }
559 }
560 
561 /*---------------------------------------------------------------------------*
562   Name:         ColorString
563 
564   Description:  Changes the color of character strings printed on the virtual screen.
565 
566   Arguments:    x: X-coordinate (x 8 dots) from which to start color change
567                 y: Y-coordinate (x 8 dots) from which to start color change
568                 length: Number of characters to continue the color change for
569                 palette: Specify text color by palette number
570 
571   Returns:      None.
572  *---------------------------------------------------------------------------*/
ColorString(s16 x,s16 y,s16 length,u8 palette)573 static void ColorString(s16 x, s16 y, s16 length, u8 palette)
574 {
575     s32     i;
576     u16     temp;
577     s32     index;
578 
579     if (length < 0)
580         return;
581 
582     for (i = 0; i < length; i++)
583     {
584         index = ((y * 32) + x + i) % (32 * 32);
585         temp = gScreen[index];
586         temp &= 0x0fff;
587         temp |= (palette << 12);
588         gScreen[index] = temp;
589     }
590 }
591 
592 /*---------------------------------------------------------------------------*
593   Name:         InitializeAllocateSystem
594 
595   Description:  Initializes the memory allocation system within the main memory arena.
596 
597   Arguments:    None.
598 
599   Returns:      None.
600  *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)601 static void InitializeAllocateSystem(void)
602 {
603     void   *tempLo;
604     OSHeapHandle hh;
605 
606     // Based on the premise that OS_Init has been already called
607     tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
608     OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
609     hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
610     if (hh < 0)
611     {
612         OS_Panic("ARM9: Fail to create heap...\n");
613     }
614     hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
615 }
616