1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WM - demos - dataShare-1
3   File:     main.c
4 
5   Copyright 2006-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-28#$
14   $Rev: 11026 $
15   $Author: tominaga_masafumi $
16  *---------------------------------------------------------------------------*/
17 /*---------------------------------------------------------------------------*
18     This sample performs wireless data sharing communication using the WM library.
19     It automatically connects to a nearby dataShare-1 demo and shares a total of 8 bytes in the wireless communications group: a 4-byte game frame count and a 4-byte picture frame count.
20 
21 
22 
23     HOWTO:
24         1. Press the A Button to start communications as a parent.
25            As soon as a nearby child with the same dataShare-1 demo is found, data-sharing communication with that child begins automatically. Communication with up to 15 children is possible at the same time.
26 
27         2. Press the B Button to start communications as a child.
28            As soon as a nearby parent with the same dataShare-1 demo is found, communication with that parent begins automatically.
29 
30         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.
31 
32  *---------------------------------------------------------------------------*/
33 
34 #ifdef SDK_TWL
35 #include    <twl.h>
36 #else
37 #include    <nitro.h>
38 #endif
39 
40 #include    <nitro/wm.h>
41 
42 #include    "font.h"
43 #include    "wh.h"
44 
45 
46 /*---------------------------------------------------------------------------*
47     Constant definitions
48  *---------------------------------------------------------------------------*/
49 #define     KEY_REPEAT_START    25     // Number of frames until key repeat starts
50 #define     KEY_REPEAT_SPAN     10     // Number of frames between key repeats
51 
52 #define     PICTURE_FRAME_PER_GAME_FRAME    2
53 
54 #define     DEFAULT_GGID            0x003fff11
55 #define     NUM_MAX_CHILD           15
56 #define     DEFAULT_CHAN            1
57 #define     SHARED_DATA_SIZE        8
58 
59 /*---------------------------------------------------------------------------*
60     Structure definitions
61  *---------------------------------------------------------------------------*/
62 // Key input data
63 typedef struct KeyInfo
64 {
65     u16     cnt;                       // Unprocessed input value
66     u16     trg;                       // Push trigger input
67     u16     up;                        // Release trigger input
68     u16     rep;                       // Press and hold repeat input
69 
70 }
71 KeyInfo;
72 
73 
74 /*---------------------------------------------------------------------------*
75     Internal Function Definitions
76  *---------------------------------------------------------------------------*/
77 static void GameFrame(void);           // Main loop for game frame
78 static void ModeSelect(void);          // Parent/child select screen
79 static void ModeError(void);           // Error display screen
80 static void ModeWorking(void);         // Busy screen
81 static void ModeParent(void);          // Parent communications screen
82 static void ModeChild(void);           // Child communications screen
83 static void VBlankIntr(void);          // V-Blank interrupt handler
84 static void PrintSharedData(u16 bitmap);        // Displays shared data
85 
86 // General purpose subroutines
87 static void KeyRead(KeyInfo * pKey);
88 static void ClearString(void);
89 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...);
90 static void ColorString(s16 x, s16 y, s16 length, u8 palette);
91 static void InitializeAllocateSystem(void);
92 
93 
94 /*---------------------------------------------------------------------------*
95     Internal Variable Definitions
96  *---------------------------------------------------------------------------*/
97 static u16 gScreen[32 * 32];           // Virtual screen
98 static KeyInfo gKey;                   // Key input
99 static vs32 gPictureFrame;             // Picture frame counter
100 static vs32 gGameFrame;                // Game frame counter
101 
102 // Send data buffer (must be 32-Byte aligned)
103 static u16 gSendBuf[SHARED_DATA_SIZE / sizeof(u16)] ATTRIBUTE_ALIGN(32);
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()
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     // Variable initialization
155     gPictureFrame = 0;
156 
157     // Interrupt settings
158     OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
159     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
160     (void)GX_VBlankIntr(TRUE);
161     (void)OS_EnableIrq();
162     (void)OS_EnableInterrupts();
163 
164     // Initialize memory allocation system
165     InitializeAllocateSystem();
166 
167     //********************************
168     // Wireless settings
169     WH_SetGgid(DEFAULT_GGID);
170     //********************************
171 
172     // LCD display start
173     GX_DispOn();
174     GXS_DispOn();
175 
176     // Debug string output
177     OS_Printf("ARM9: WM data sharing demo started.\n");
178 
179     // Empty call for getting key input data (strategy for pressing A Button in the IPL)
180     KeyRead(&gKey);
181 
182     // Main loop
183     GameFrame();                       // Never return
184 }
185 
186 /*---------------------------------------------------------------------------*
187   Name:         GameFrame
188 
189   Description:  Main loop for game frame
190 
191   Arguments:    None.
192 
193   Returns:      None.
194  *---------------------------------------------------------------------------*/
GameFrame(void)195 static void GameFrame(void)
196 {
197     for (gGameFrame = 0; TRUE; gGameFrame++)
198     {
199         // Get key input data
200         KeyRead(&gKey);
201 
202         // Distributes processes based on communication status
203         switch (WH_GetSystemState())
204         {
205         case WH_SYSSTATE_STOP:
206             ModeSelect();
207             break;
208         case WH_SYSSTATE_IDLE:
209         case WH_SYSSTATE_ERROR:
210         case WH_SYSSTATE_CONNECT_FAIL:
211             // End communication
212             WH_Finalize();
213             while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
214             (void)WH_End();
215             while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
216             break;
217         case WH_SYSSTATE_FATAL:
218             ModeError();
219             break;
220         case WH_SYSSTATE_BUSY:
221         case WH_SYSSTATE_SCANNING:
222             ModeWorking();
223             break;
224         case WH_SYSSTATE_CONNECTED:
225         case WH_SYSSTATE_DATASHARING:
226             switch (WH_GetConnectMode())
227             {
228             case WH_CONNECTMODE_DS_PARENT:
229                 ModeParent();
230                 break;
231             case WH_CONNECTMODE_DS_CHILD:
232                 ModeChild();
233                 break;
234             }
235             break;
236         }
237 
238         // Wait for completion of multiple cycles of picture frames
239         while (TRUE)
240         {
241             // Wait for V-Blank
242             OS_WaitVBlankIntr();
243             if (!(gPictureFrame % PICTURE_FRAME_PER_GAME_FRAME))
244             {
245                 break;
246             }
247         }
248     }
249 }
250 
251 /*---------------------------------------------------------------------------*
252   Name:         ModeSelect
253 
254   Description:  Processing in parent/child selection screen.
255 
256   Arguments:    None.
257 
258   Returns:      None.
259  *---------------------------------------------------------------------------*/
ModeSelect(void)260 static void ModeSelect(void)
261 {
262     // Clear the screen
263     ClearString();
264     // Character display
265     PrintString(3, 10, 0xf, "Push A to connect as PARENT");
266     PrintString(3, 12, 0xf, "Push B to connect as CHILD");
267 
268     if (gKey.trg & PAD_BUTTON_A)
269     {
270         // WH initialization
271         if (!WH_Initialize())
272         {
273             OS_Panic("WH_Initiailze failed.");
274         }
275         else
276         {
277             // Wait for initialization to complete
278             while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
279         }
280 
281         //********************************
282         // Start parent communication
283         (void)WH_ParentConnect(WH_CONNECTMODE_DS_PARENT, 0x0000, DEFAULT_CHAN);
284         //********************************
285     }
286     else if (gKey.trg & PAD_BUTTON_B)
287     {
288         static const u8 ANY_PARENT[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
289 
290         // WH initialization
291         if (!WH_Initialize())
292         {
293             OS_Panic("WH_Initiailze failed.");
294         }
295         else
296         {
297             // Wait for initialization to complete
298             while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
299         }
300 
301         //********************************
302         // Start child connection
303         (void)WH_ChildConnectAuto(WH_CONNECTMODE_DS_CHILD, ANY_PARENT, DEFAULT_CHAN);
304         //********************************
305     }
306 }
307 
308 /*---------------------------------------------------------------------------*
309   Name:         ModeError
310 
311   Description:  Processing in error display screen.
312 
313   Arguments:    None.
314 
315   Returns:      None.
316  *---------------------------------------------------------------------------*/
ModeError(void)317 static void ModeError(void)
318 {
319     // Clear the screen
320     ClearString();
321     // Character display
322     PrintString(5, 10, 0x1, "======= ERROR! =======");
323     PrintString(5, 13, 0xf, " Fatal error occured.");
324     PrintString(5, 14, 0xf, "Please reboot program.");
325 }
326 
327 /*---------------------------------------------------------------------------*
328   Name:         ModeWorking
329 
330   Description:  Processing in busy screen.
331 
332   Arguments:    None.
333 
334   Returns:      None.
335  *---------------------------------------------------------------------------*/
ModeWorking(void)336 static void ModeWorking(void)
337 {
338     // Clear the screen
339     ClearString();
340     // Character display
341     PrintString(9, 11, 0xf, "Now working...");
342 
343     if (gKey.trg & PAD_BUTTON_START)
344     {
345         //********************************
346         // End communication
347         WH_Finalize();
348         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
349         (void)WH_End();
350         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
351         //********************************
352     }
353 }
354 
355 /*---------------------------------------------------------------------------*
356   Name:         ModeParent
357 
358   Description:  Processing in parent communications screen.
359 
360   Arguments:    None.
361 
362   Returns:      None.
363  *---------------------------------------------------------------------------*/
ModeParent(void)364 static void ModeParent(void)
365 {
366     BOOL    result;
367 
368     // Edit send data
369     gSendBuf[0] = (u16)(gPictureFrame >> 16);
370     gSendBuf[1] = (u16)(gPictureFrame & 0xffff);
371     gSendBuf[2] = (u16)(gGameFrame >> 16);
372     gSendBuf[3] = (u16)(gGameFrame & 0xffff);
373 
374     //********************************
375     // Synchronize data sharing
376     result = WH_StepDS((void *)gSendBuf);
377     //********************************
378 
379     // Clear the screen
380     ClearString();
381     // Character display
382     PrintString(8, 1, 0x2, "Parent mode");
383     // Display shared data
384     if (result)
385     {
386         PrintSharedData(WH_GetBitmap());
387     }
388     else
389     {
390         // Also try StepDataSharing in the next frame
391         gPictureFrame--;
392     }
393 
394     if (gKey.trg & PAD_BUTTON_START)
395     {
396         //********************************
397         // End communication
398         WH_Finalize();
399         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
400         (void)WH_End();
401         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
402         //********************************
403     }
404 }
405 
406 /*---------------------------------------------------------------------------*
407   Name:         ModeChild
408 
409   Description:  Processing in child communications screen.
410 
411   Arguments:    None.
412 
413   Returns:      None.
414  *---------------------------------------------------------------------------*/
ModeChild(void)415 static void ModeChild(void)
416 {
417     BOOL    result;
418 
419     // Edit send data
420     gSendBuf[0] = (u16)(gPictureFrame >> 16);
421     gSendBuf[1] = (u16)(gPictureFrame & 0xffff);
422     gSendBuf[2] = (u16)(gGameFrame >> 16);
423     gSendBuf[3] = (u16)(gGameFrame & 0xffff);
424 
425     //********************************
426     // Synchronize data sharing
427     result = WH_StepDS((void *)gSendBuf);
428     //********************************
429 
430     // Clear the screen
431     ClearString();
432     // Character display
433     PrintString(8, 1, 0x2, "Child mode");
434     // Display shared data
435     if (result)
436     {
437         PrintSharedData(WH_GetBitmapDS());
438     }
439     else
440     {
441         // Also try StepDataSharing in the next frame
442         gPictureFrame--;
443     }
444 
445     if (gKey.trg & PAD_BUTTON_START)
446     {
447         //********************************
448         // End communication
449         WH_Finalize();
450         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
451         (void)WH_End();
452         while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
453         //********************************
454     }
455 }
456 
457 /*---------------------------------------------------------------------------*
458   Name:         VBlankIntr
459 
460   Description:  V-Blank interrupt vector.
461 
462   Arguments:    None.
463 
464   Returns:      None.
465  *---------------------------------------------------------------------------*/
VBlankIntr(void)466 static void VBlankIntr(void)
467 {
468     // Increment picture frame counter
469     gPictureFrame++;
470 
471     // Repeat rendering to match game frame
472     if (!(gPictureFrame % PICTURE_FRAME_PER_GAME_FRAME))
473     {
474         // Reflect virtual screen in VRAM
475         DC_FlushRange(gScreen, sizeof(gScreen));
476         /* I/O register is accessed using DMA operation, so cache wait is not needed */
477         // DC_WaitWriteBufferEmpty();
478         GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
479     }
480 
481     // Sets the IRQ check flag
482     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
483 }
484 
485 /*---------------------------------------------------------------------------*
486   Name:         PrintSharedData
487 
488   Description:  Displays data from each shared terminal.
489 
490   Arguments:    bitmap: bitmap of IDs indicating the terminals that received data.
491 
492   Returns:      None.
493  *---------------------------------------------------------------------------*/
PrintSharedData(u16 bitmap)494 static void PrintSharedData(u16 bitmap)
495 {
496     u16     i;
497     //u8     *p;
498     u16    *p;
499     u16     temp[SHARED_DATA_SIZE / sizeof(u16)];
500 
501     // Loop for maximum number of parent devices + child devices
502     for (i = 0; i < (1 + WM_NUM_MAX_CHILD); i++)
503     {
504         if (bitmap & (0x0001 << i))
505         {
506             //********************************
507             // Get data from terminal with ID of 'i'
508             p = WH_GetSharedDataAdr(i);
509             //********************************
510 
511             if (p != NULL)
512             {
513                 // Copy once to ensure alignment
514                 MI_CpuCopy8(p, temp, SHARED_DATA_SIZE);
515                 PrintString(2, (s16)(3 + i), 0x4,
516                             "%04x%04x-%04x%04x", temp[0], temp[1], temp[2], temp[3]);
517             }
518             else
519             {
520                 PrintString(2, (s16)(3 + i), 0x1, "xxxxxxxx-xxxxxxxx");
521             }
522         }
523     }
524     // Change the color only for data for the local host
525     ColorString(2, (s16)(3 + WH_GetCurrentAid()), 17, 0xf);
526 }
527 
528 /*---------------------------------------------------------------------------*
529   Name:         KeyRead
530 
531   Description:  Edits key input data
532                 Detects press trigger, release trigger, and press-and-hold repeat.
533 
534   Arguments:    pKey: Structure that holds key input data to be edited
535 
536   Returns:      None.
537  *---------------------------------------------------------------------------*/
KeyRead(KeyInfo * pKey)538 static void KeyRead(KeyInfo * pKey)
539 {
540     static u16 repeat_count[12];
541     int     i;
542     u16     r;
543 
544     r = PAD_Read();
545     pKey->trg = 0x0000;
546     pKey->up = 0x0000;
547     pKey->rep = 0x0000;
548 
549     for (i = 0; i < 12; i++)
550     {
551         if (r & (0x0001 << i))
552         {
553             if (!(pKey->cnt & (0x0001 << i)))
554             {
555                 pKey->trg |= (0x0001 << i);     // Press trigger
556                 repeat_count[i] = 1;
557             }
558             else
559             {
560                 if (repeat_count[i] > KEY_REPEAT_START)
561                 {
562                     pKey->rep |= (0x0001 << i); // Press-and-hold repeat
563                     repeat_count[i] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
564                 }
565                 else
566                 {
567                     repeat_count[i]++;
568                 }
569             }
570         }
571         else
572         {
573             if (pKey->cnt & (0x0001 << i))
574             {
575                 pKey->up |= (0x0001 << i);      // Release trigger
576             }
577         }
578     }
579     pKey->cnt = r;                     // Unprocessed key input
580 }
581 
582 /*---------------------------------------------------------------------------*
583   Name:         ClearString
584 
585   Description:  Clears the virtual screen.
586 
587   Arguments:    None.
588 
589   Returns:      None.
590  *---------------------------------------------------------------------------*/
ClearString(void)591 static void ClearString(void)
592 {
593     MI_CpuClearFast((void *)gScreen, sizeof(gScreen));
594 }
595 
596 /*---------------------------------------------------------------------------*
597   Name:         PrintString
598 
599   Description:  Positions the text string on the virtual screen. The string can be up to 32 chars.
600 
601   Arguments:    x: X-coordinate where character string starts (x 8 pixels).
602                 y: Y-coordinate where character string starts (x 8 pixels).
603                 palette: Specify text color by palette number.
604                 text: Text string to position. Null-terminated.
605                 ...: Virtual argument.
606 
607   Returns:      None.
608  *---------------------------------------------------------------------------*/
PrintString(s16 x,s16 y,u8 palette,char * text,...)609 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...)
610 {
611     va_list vlist;
612     char    temp[32 + 2];
613     s32     i;
614 
615     va_start(vlist, text);
616     (void)vsnprintf(temp, 33, text, vlist);
617     va_end(vlist);
618 
619     *(u16 *)(&temp[32]) = 0x0000;
620     for (i = 0;; i++)
621     {
622         if (temp[i] == 0x00)
623         {
624             break;
625         }
626         gScreen[((y * 32) + x + i) % (32 * 32)] = (u16)((palette << 12) | temp[i]);
627     }
628 }
629 
630 /*---------------------------------------------------------------------------*
631   Name:         ColorString
632 
633   Description:  Changes the color of character strings printed on the virtual screen.
634 
635   Arguments:    x:         X-coordinate (x 8 pixels) from which to start color change.
636                 y:         Y-coordinate (x 8 pixels) from which to start color change.
637                 length:   Number of characters to continue the color change for.
638                 palette: Specify text color by palette number.
639 
640   Returns:      None.
641  *---------------------------------------------------------------------------*/
ColorString(s16 x,s16 y,s16 length,u8 palette)642 static void ColorString(s16 x, s16 y, s16 length, u8 palette)
643 {
644     s32     i;
645     u16     temp;
646     s32     index;
647 
648     if (length < 0)
649         return;
650 
651     for (i = 0; i < length; i++)
652     {
653         index = ((y * 32) + x + i) % (32 * 32);
654         temp = gScreen[index];
655         temp &= 0x0fff;
656         temp |= (palette << 12);
657         gScreen[index] = temp;
658     }
659 }
660 
661 /*---------------------------------------------------------------------------*
662   Name:         InitializeAllocateSystem
663 
664   Description:  Initializes the memory allocation system within the main memory arena.
665 
666   Arguments:    None.
667 
668   Returns:      None.
669  *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)670 static void InitializeAllocateSystem(void)
671 {
672     void   *tempLo;
673     OSHeapHandle hh;
674 
675     // Based on the premise that OS_Init has been already called
676     tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
677     OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
678     hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
679     if (hh < 0)
680     {
681         OS_Panic("ARM9: Fail to create heap...\n");
682     }
683     hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
684 }
685 
686 /*---------------------------------------------------------------------------*
687   End of file
688  *---------------------------------------------------------------------------*/
689