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