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