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