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