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