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