1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WM - demos - dataShare-1
3   File:     main.c
4 
5   Copyright 2006-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-02-03#$
14   $Rev: 9963 $
15   $Author: nishimoto_takashi $
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.
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            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     // Initialize wireless
169     if (!WH_Initialize())
170     {
171         OS_Panic("WH_Initialize failed.");
172     }
173     WH_SetGgid(DEFAULT_GGID);
174     //********************************
175 
176     // LCD display start
177     GX_DispOn();
178     GXS_DispOn();
179 
180     // Debug string output
181     OS_Printf("ARM9: WM data sharing demo started.\n");
182 
183     // Empty call for getting key input data (strategy for pressing A Button in the IPL)
184     KeyRead(&gKey);
185 
186     // Main loop
187     GameFrame();                       // Never return
188 }
189 
190 /*---------------------------------------------------------------------------*
191   Name:         GameFrame
192 
193   Description:  Main loop for game frame
194 
195   Arguments:    None.
196 
197   Returns:      None.
198  *---------------------------------------------------------------------------*/
GameFrame(void)199 static void GameFrame(void)
200 {
201     for (gGameFrame = 0; TRUE; gGameFrame++)
202     {
203         // Get key input data
204         KeyRead(&gKey);
205 
206         // Distributes processes based on communication status
207         switch (WH_GetSystemState())
208         {
209         case WH_SYSSTATE_IDLE:
210             ModeSelect();
211             break;
212         case WH_SYSSTATE_ERROR:
213         case WH_SYSSTATE_CONNECT_FAIL:
214             WH_Reset();
215             break;
216         case WH_SYSSTATE_FATAL:
217             ModeError();
218             break;
219         case WH_SYSSTATE_BUSY:
220         case WH_SYSSTATE_SCANNING:
221             ModeWorking();
222             break;
223         case WH_SYSSTATE_CONNECTED:
224         case WH_SYSSTATE_DATASHARING:
225             switch (WH_GetConnectMode())
226             {
227             case WH_CONNECTMODE_DS_PARENT:
228                 ModeParent();
229                 break;
230             case WH_CONNECTMODE_DS_CHILD:
231                 ModeChild();
232                 break;
233             }
234             break;
235         }
236 
237         // Wait for completion of multiple cycles of picture frames
238         while (TRUE)
239         {
240             // Wait for V-Blank
241             OS_WaitVBlankIntr();
242             if (!(gPictureFrame % PICTURE_FRAME_PER_GAME_FRAME))
243             {
244                 break;
245             }
246         }
247     }
248 }
249 
250 /*---------------------------------------------------------------------------*
251   Name:         ModeSelect
252 
253   Description:  Process in parent/child selection screen.
254 
255   Arguments:    None.
256 
257   Returns:      None.
258  *---------------------------------------------------------------------------*/
ModeSelect(void)259 static void ModeSelect(void)
260 {
261     // Clear the screen
262     ClearString();
263     // Character display
264     PrintString(3, 10, 0xf, "Push A to connect as PARENT");
265     PrintString(3, 12, 0xf, "Push B to connect as CHILD");
266 
267     if (gKey.trg & PAD_BUTTON_A)
268     {
269         //********************************
270         // Start parent communication
271         (void)WH_ParentConnect(WH_CONNECTMODE_DS_PARENT, 0x0000, DEFAULT_CHAN);
272         //********************************
273     }
274     else if (gKey.trg & PAD_BUTTON_B)
275     {
276         static const u8 ANY_PARENT[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
277         //********************************
278         // Start child connection
279         (void)WH_ChildConnectAuto(WH_CONNECTMODE_DS_CHILD, ANY_PARENT, DEFAULT_CHAN);
280         //********************************
281     }
282 }
283 
284 /*---------------------------------------------------------------------------*
285   Name:         ModeError
286 
287   Description:  Processing in error display screen.
288 
289   Arguments:    None.
290 
291   Returns:      None.
292  *---------------------------------------------------------------------------*/
ModeError(void)293 static void ModeError(void)
294 {
295     // Clear the screen
296     ClearString();
297     // Character display
298     PrintString(5, 10, 0x1, "======= ERROR! =======");
299     PrintString(5, 13, 0xf, " Fatal error occured.");
300     PrintString(5, 14, 0xf, "Please reboot program.");
301 }
302 
303 /*---------------------------------------------------------------------------*
304   Name:         ModeWorking
305 
306   Description:  Processing in busy screen
307 
308   Arguments:    None.
309 
310   Returns:      None.
311  *---------------------------------------------------------------------------*/
ModeWorking(void)312 static void ModeWorking(void)
313 {
314     // Clear the screen
315     ClearString();
316     // Character display
317     PrintString(9, 11, 0xf, "Now working...");
318 
319     if (gKey.trg & PAD_BUTTON_START)
320     {
321         //********************************
322         // End communication
323         WH_Finalize();
324         //********************************
325     }
326 }
327 
328 /*---------------------------------------------------------------------------*
329   Name:         ModeParent
330 
331   Description:  Processing in parent communications screen.
332 
333   Arguments:    None.
334 
335   Returns:      None.
336  *---------------------------------------------------------------------------*/
ModeParent(void)337 static void ModeParent(void)
338 {
339     BOOL    result;
340 
341     // Edit send data
342     gSendBuf[0] = (u16)(gPictureFrame >> 16);
343     gSendBuf[1] = (u16)(gPictureFrame & 0xffff);
344     gSendBuf[2] = (u16)(gGameFrame >> 16);
345     gSendBuf[3] = (u16)(gGameFrame & 0xffff);
346 
347     //********************************
348     // Synchronize data sharing
349     result = WH_StepDS((void *)gSendBuf);
350     //********************************
351 
352     // Clear the screen
353     ClearString();
354     // Character display
355     PrintString(8, 1, 0x2, "Parent mode");
356     // Display shared data
357     if (result)
358     {
359         PrintSharedData(WH_GetBitmap());
360     }
361     else
362     {
363         // Also try StepDataSharing in the next frame
364         gPictureFrame--;
365     }
366 
367     if (gKey.trg & PAD_BUTTON_START)
368     {
369         //********************************
370         // End communication
371         WH_Finalize();
372         //********************************
373     }
374 }
375 
376 /*---------------------------------------------------------------------------*
377   Name:         ModeChild
378 
379   Description:  Processing in child communications screen.
380 
381   Arguments:    None.
382 
383   Returns:      None.
384  *---------------------------------------------------------------------------*/
ModeChild(void)385 static void ModeChild(void)
386 {
387     BOOL    result;
388 
389     // Edit send data
390     gSendBuf[0] = (u16)(gPictureFrame >> 16);
391     gSendBuf[1] = (u16)(gPictureFrame & 0xffff);
392     gSendBuf[2] = (u16)(gGameFrame >> 16);
393     gSendBuf[3] = (u16)(gGameFrame & 0xffff);
394 
395     //********************************
396     // Synchronize data sharing
397     result = WH_StepDS((void *)gSendBuf);
398     //********************************
399 
400     // Clear the screen
401     ClearString();
402     // Character display
403     PrintString(8, 1, 0x2, "Child mode");
404     // Display shared data
405     if (result)
406     {
407         PrintSharedData(WH_GetBitmapDS());
408     }
409     else
410     {
411         // Also try StepDataSharing in the next frame
412         gPictureFrame--;
413     }
414 
415     if (gKey.trg & PAD_BUTTON_START)
416     {
417         //********************************
418         // End communication
419         WH_Finalize();
420         //********************************
421     }
422 }
423 
424 /*---------------------------------------------------------------------------*
425   Name:         VBlankIntr
426 
427   Description:  V-Blank interrupt vector.
428 
429   Arguments:    None.
430 
431   Returns:      None.
432  *---------------------------------------------------------------------------*/
VBlankIntr(void)433 static void VBlankIntr(void)
434 {
435     // Increment picture frame counter
436     gPictureFrame++;
437 
438     // Repeat rendering to match game frame
439     if (!(gPictureFrame % PICTURE_FRAME_PER_GAME_FRAME))
440     {
441         // Reflect virtual screen in VRAM
442         DC_FlushRange(gScreen, sizeof(gScreen));
443         /* I/O register is accessed using DMA operation, so cache wait is not needed */
444         // DC_WaitWriteBufferEmpty();
445         GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
446     }
447 
448     // Sets the IRQ check flag
449     OS_SetIrqCheckFlag(OS_IE_V_BLANK);
450 }
451 
452 /*---------------------------------------------------------------------------*
453   Name:         PrintSharedData
454 
455   Description:  Displays data from each shared terminal.
456 
457   Arguments:    bitmap: ID bitmap indicating the terminal receiving data
458 
459   Returns:      None.
460  *---------------------------------------------------------------------------*/
PrintSharedData(u16 bitmap)461 static void PrintSharedData(u16 bitmap)
462 {
463     u16     i;
464     //u8     *p;
465     u16    *p;
466     u16     temp[SHARED_DATA_SIZE / sizeof(u16)];
467 
468     // Loop for maximum number of parent devices + child devices
469     for (i = 0; i < (1 + WM_NUM_MAX_CHILD); i++)
470     {
471         if (bitmap & (0x0001 << i))
472         {
473             //********************************
474             // Get data from terminal with ID of 'i'
475             p = WH_GetSharedDataAdr(i);
476             //********************************
477 
478             if (p != NULL)
479             {
480                 // Copy once to ensure alignment
481                 MI_CpuCopy8(p, temp, SHARED_DATA_SIZE);
482                 PrintString(2, (s16)(3 + i), 0x4,
483                             "%04x%04x-%04x%04x", temp[0], temp[1], temp[2], temp[3]);
484             }
485             else
486             {
487                 PrintString(2, (s16)(3 + i), 0x1, "xxxxxxxx-xxxxxxxx");
488             }
489         }
490     }
491     // Change the color only for data for this device
492     ColorString(2, (s16)(3 + WH_GetCurrentAid()), 17, 0xf);
493 }
494 
495 /*---------------------------------------------------------------------------*
496   Name:         KeyRead
497 
498   Description:  Edits key input data.
499                 Detects press trigger, release trigger, and press-and-hold repeat.
500 
501   Arguments:    pKey: Structure that holds key input data to be edited
502 
503   Returns:      None.
504  *---------------------------------------------------------------------------*/
KeyRead(KeyInfo * pKey)505 static void KeyRead(KeyInfo * pKey)
506 {
507     static u16 repeat_count[12];
508     int     i;
509     u16     r;
510 
511     r = PAD_Read();
512     pKey->trg = 0x0000;
513     pKey->up = 0x0000;
514     pKey->rep = 0x0000;
515 
516     for (i = 0; i < 12; i++)
517     {
518         if (r & (0x0001 << i))
519         {
520             if (!(pKey->cnt & (0x0001 << i)))
521             {
522                 pKey->trg |= (0x0001 << i);     // Press trigger
523                 repeat_count[i] = 1;
524             }
525             else
526             {
527                 if (repeat_count[i] > KEY_REPEAT_START)
528                 {
529                     pKey->rep |= (0x0001 << i); // Press-and-hold repeat
530                     repeat_count[i] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
531                 }
532                 else
533                 {
534                     repeat_count[i]++;
535                 }
536             }
537         }
538         else
539         {
540             if (pKey->cnt & (0x0001 << i))
541             {
542                 pKey->up |= (0x0001 << i);      // Release trigger
543             }
544         }
545     }
546     pKey->cnt = r;                     // Unprocessed key input
547 }
548 
549 /*---------------------------------------------------------------------------*
550   Name:         ClearString
551 
552   Description:  Clears the virtual screen.
553 
554   Arguments:    None.
555 
556   Returns:      None.
557  *---------------------------------------------------------------------------*/
ClearString(void)558 static void ClearString(void)
559 {
560     MI_CpuClearFast((void *)gScreen, sizeof(gScreen));
561 }
562 
563 /*---------------------------------------------------------------------------*
564   Name:         PrintString
565 
566   Description:  Positions the text string on the virtual screen. The string can be up to 32 chars.
567 
568   Arguments:    x: X-coordinate where character string starts (x 8 dots)
569                 y: Y-coordinate where character string starts (x 8 dots)
570                 palette: Specify text color by palette number
571                 text: Text string to position. Null-terminated.
572                 ...: Virtual argument.
573 
574   Returns:      None.
575  *---------------------------------------------------------------------------*/
PrintString(s16 x,s16 y,u8 palette,char * text,...)576 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...)
577 {
578     va_list vlist;
579     char    temp[32 + 2];
580     s32     i;
581 
582     va_start(vlist, text);
583     (void)vsnprintf(temp, 33, text, vlist);
584     va_end(vlist);
585 
586     *(u16 *)(&temp[32]) = 0x0000;
587     for (i = 0;; i++)
588     {
589         if (temp[i] == 0x00)
590         {
591             break;
592         }
593         gScreen[((y * 32) + x + i) % (32 * 32)] = (u16)((palette << 12) | temp[i]);
594     }
595 }
596 
597 /*---------------------------------------------------------------------------*
598   Name:         ColorString
599 
600   Description:  Changes the color of character strings printed on the virtual screen.
601 
602   Arguments:    x: X-coordinate (x 8 dots ) from which to start color change
603                 y: Y-coordinate (x 8 dots ) from which to start color change
604                 length: Number of characters to continue the color change for
605                 palette: Specify text color by palette number
606 
607   Returns:      None.
608  *---------------------------------------------------------------------------*/
ColorString(s16 x,s16 y,s16 length,u8 palette)609 static void ColorString(s16 x, s16 y, s16 length, u8 palette)
610 {
611     s32     i;
612     u16     temp;
613     s32     index;
614 
615     if (length < 0)
616         return;
617 
618     for (i = 0; i < length; i++)
619     {
620         index = ((y * 32) + x + i) % (32 * 32);
621         temp = gScreen[index];
622         temp &= 0x0fff;
623         temp |= (palette << 12);
624         gScreen[index] = temp;
625     }
626 }
627 
628 /*---------------------------------------------------------------------------*
629   Name:         InitializeAllocateSystem
630 
631   Description:  Initializes the memory allocation system within the main memory arena.
632 
633   Arguments:    None.
634 
635   Returns:      None.
636  *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)637 static void InitializeAllocateSystem(void)
638 {
639     void   *tempLo;
640     OSHeapHandle hh;
641 
642     // Based on the premise that OS_Init has been already called
643     tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
644     OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
645     hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
646     if (hh < 0)
647     {
648         OS_Panic("ARM9: Fail to create heap...\n");
649     }
650     hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
651 }
652 
653 /*---------------------------------------------------------------------------*
654   End of file
655  *---------------------------------------------------------------------------*/
656