1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - WVR - demos - simple
3 File: main.c
4
5 Copyright 2003-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 "wh.h"
24
25
26 /*---------------------------------------------------------------------------*
27 Constant definitions
28 *---------------------------------------------------------------------------*/
29 #define KEY_REPEAT_START 25 // Number of frames until key repeat starts
30 #define KEY_REPEAT_SPAN 10 // Number of frames between key repeats
31
32 #define PICTURE_FRAME_PER_GAME_FRAME 1
33
34 #define DEFAULT_GGID 0x003fff60
35 #define NUM_MAX_CHILD 15
36 #define DEFAULT_CHAN 1
37 #define PARENT_DATA_SIZE 4
38 #define CHILD_DATA_SIZE 4
39
40 /*---------------------------------------------------------------------------*
41 Structure definitions
42 *---------------------------------------------------------------------------*/
43 // Key input data
44 typedef struct KeyInfo
45 {
46 u16 cnt; // Unprocessed input value
47 u16 trg; // Push trigger input
48 u16 up; // Release trigger input
49 u16 rep; // Press and hold repeat input
50
51 }
52 KeyInfo;
53
54
55 /*---------------------------------------------------------------------------*
56 Internal Function Definitions
57 *---------------------------------------------------------------------------*/
58 static void StartUpCallback(void *arg, WVRResult result);
59
60 static void ModeSelect(void); // Parent/child select screen
61 static void ModeError(void); // Error display screen
62 static void ModeWorking(void); // Busy screen
63 static void ModeParent(void); // Parent communications screen
64 static void ModeChild(void); // Child communications screen
65 static void VBlankIntr(void); // V-Blank interrupt handler
66
67 // Functions called when receiving data
68 static void MpReceiveCallback(u16 aid, u16 *data, u16 length);
69
70 // General purpose subroutines
71 static void KeyRead(KeyInfo * pKey);
72 static void ClearString(void);
73 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...);
74 static void ColorString(s16 x, s16 y, s16 length, u8 palette);
75 static void InitializeAllocateSystem(void);
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 /*---------------------------------------------------------------------------*
94 Name: NitroMain
95
96 Description: Initialization and main loop.
97
98 Arguments: None.
99
100 Returns: None.
101 *---------------------------------------------------------------------------*/
NitroMain(void)102 void NitroMain(void)
103 {
104 // Various types of initialization
105 OS_Init();
106 FX_Init();
107 GX_Init();
108 GX_DispOff();
109 GXS_DispOff();
110
111 // Initializes display settings
112 GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);
113 MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
114 (void)GX_DisableBankForLCDC();
115 MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE);
116 MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE);
117 MI_CpuFillFast((void *)HW_DB_OAM, 192, HW_DB_OAM_SIZE);
118 MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE);
119
120 // 2D display settings for text string display
121 GX_SetBankForBG(GX_VRAM_BG_128_A);
122 G2_SetBG0Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16, GX_BG_SCRBASE_0xf800, // SCR base block 31
123 GX_BG_CHARBASE_0x00000, // CHR base block 0
124 GX_BG_EXTPLTT_01);
125 G2_SetBG0Priority(0);
126 G2_BG0Mosaic(FALSE);
127 GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D);
128 GX_SetVisiblePlane(GX_PLANEMASK_BG0);
129 GX_LoadBG0Char(d_CharData, 0, sizeof(d_CharData));
130 GX_LoadBGPltt(d_PaletteData, 0, sizeof(d_PaletteData));
131 MI_CpuFillFast((void *)gScreen, 0, sizeof(gScreen));
132 DC_FlushRange(gScreen, sizeof(gScreen));
133 /* I/O register is accessed using DMA operation, so cache wait is not needed */
134 // DC_WaitWriteBufferEmpty();
135 GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
136
137 // Interrupt settings
138 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
139 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
140 (void)GX_VBlankIntr(TRUE);
141 (void)OS_EnableIrq();
142 (void)OS_EnableInterrupts();
143
144 // Memory allocation
145 InitializeAllocateSystem();
146
147 // LCD display start
148 GX_DispOn();
149 GXS_DispOn();
150
151 //************************************
152 // Start activating the wireless library
153 {
154 startCheck = 0;
155 if (WVR_RESULT_OPERATING != WVR_StartUpAsync(GX_VRAM_ARM7_128_D, StartUpCallback, NULL))
156 {
157 OS_TPanic("WVR_StartUpAsync failed. \n");
158 }
159 while (!startCheck)
160 {
161 }
162 }
163 //************************************
164 //************************************
165 // Wireless settings
166 WH_SetGgid(DEFAULT_GGID);
167 //************************************
168
169 // Debug string output
170 OS_Printf("ARM9: ichneumon test program started.\n");
171
172 // Empty call for getting key input data (strategy for pressing A Button in the IPL)
173 KeyRead(&gKey);
174
175 // Main loop
176 for (gFrame = 0; TRUE; gFrame++)
177 {
178 // Get key input data
179 KeyRead(&gKey);
180
181 // Clear the screen
182 ClearString();
183
184 // Distributes processes based on communication status
185 switch (WH_GetSystemState())
186 {
187 case WH_SYSSTATE_STOP:
188 ModeSelect();
189 break;
190 case WH_SYSSTATE_IDLE:
191 case WH_SYSSTATE_ERROR:
192 case WH_SYSSTATE_CONNECT_FAIL:
193 // End communication
194 WH_Finalize();
195 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
196 (void)WH_End();
197 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
198 break;
199 case WH_SYSSTATE_FATAL:
200 ModeError();
201 break;
202 case WH_SYSSTATE_BUSY:
203 case WH_SYSSTATE_SCANNING:
204 ModeWorking();
205 break;
206 case WH_SYSSTATE_CONNECTED:
207 switch (WH_GetConnectMode())
208 {
209 case WH_CONNECTMODE_MP_PARENT:
210 ModeParent();
211 break;
212 case WH_CONNECTMODE_MP_CHILD:
213 ModeChild();
214 break;
215 }
216 break;
217 }
218
219 // Waiting for the V-Blank
220 OS_WaitVBlankIntr();
221 }
222 }
223
224 /*---------------------------------------------------------------------------*
225 Name: StartUpCallback
226
227 Description: Callback function that notifies of asynchronous process completion in wireless control library.
228
229
230 Arguments: arg: Argument specified when WVR_StartUpAsync is called. Not used.
231 result: The processing results from the asynchronous function.
232
233 Returns: None.
234 *---------------------------------------------------------------------------*/
StartUpCallback(void * arg,WVRResult result)235 static void StartUpCallback(void *arg, WVRResult result)
236 {
237 #pragma unused( arg )
238
239 if (result != WVR_RESULT_SUCCESS)
240 {
241 OS_TPanic("WVR_StartUpAsync error.[%08xh]\n", result);
242 }
243 startCheck = 1;
244 }
245
246 /*---------------------------------------------------------------------------*
247 Name: ModeSelect
248
249 Description: Processing in parent/child selection screen.
250
251 Arguments: None.
252
253 Returns: None.
254 *---------------------------------------------------------------------------*/
ModeSelect(void)255 static void ModeSelect(void)
256 {
257 PrintString(3, 10, 0xf, "Push A to connect as PARENT");
258 PrintString(3, 12, 0xf, "Push B to connect as CHILD");
259
260 if (gKey.trg & PAD_BUTTON_A)
261 {
262 //********************************
263 s32 i;
264
265 // WH initialization
266 if (!WH_Initialize())
267 {
268 OS_Panic("WH_Initiailze failed.");
269 }
270 else
271 {
272 // Wait for initialization to complete
273 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
274 }
275 WH_SetReceiver(MpReceiveCallback);
276
277 for (i = 1; i < (WM_NUM_MAX_CHILD + 1); i++)
278 {
279 gRecvFlag[i] = FALSE;
280 }
281
282 (void)WH_ParentConnect(WH_CONNECTMODE_MP_PARENT, 0x0000, DEFAULT_CHAN);
283 //********************************
284 }
285 else if (gKey.trg & PAD_BUTTON_B)
286 {
287 static const u8 ANY_PARENT[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
288
289 // WH initialization
290 if (!WH_Initialize())
291 {
292 OS_Panic("WH_Initiailze failed.");
293 }
294 else
295 {
296 // Wait for initialization to complete
297 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
298 }
299 WH_SetReceiver(MpReceiveCallback);
300
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 // End communication
340 WH_Finalize();
341 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
342 (void)WH_End();
343 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
344 //********************************
345 }
346 }
347
348 /*---------------------------------------------------------------------------*
349 Name: ModeParent
350
351 Description: Processing in parent communications screen.
352
353 Arguments: None.
354
355 Returns: None.
356 *---------------------------------------------------------------------------*/
ModeParent(void)357 static void ModeParent(void)
358 {
359 PrintString(8, 1, 0x2, "Parent mode");
360 PrintString(4, 3, 0x4, "Send: %08X", gSendBuf[0]);
361 PrintString(4, 5, 0x4, "Receive:");
362 {
363 s32 i;
364
365 for (i = 1; i < (WM_NUM_MAX_CHILD + 1); i++)
366 {
367 if (gRecvFlag[i])
368 {
369 PrintString(5, (s16)(6 + i), 0x4, "Child%02d: %08X", i, gRecvBuf[i][0]);
370 }
371 else
372 {
373 PrintString(5, (s16)(6 + i), 0x7, "No child");
374 }
375 }
376 }
377
378 if (gKey.trg & PAD_BUTTON_START)
379 {
380 //********************************
381 // End communication
382 WH_Finalize();
383 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
384 (void)WH_End();
385 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
386 //********************************
387 }
388 }
389
390 /*---------------------------------------------------------------------------*
391 Name: ModeChild
392
393 Description: Processing in child communications screen.
394
395 Arguments: None.
396
397 Returns: None.
398 *---------------------------------------------------------------------------*/
ModeChild(void)399 static void ModeChild(void)
400 {
401 PrintString(8, 1, 0x2, "Child mode");
402 PrintString(4, 3, 0x4, "Send: %08X", gSendBuf[0]);
403 PrintString(4, 5, 0x4, "Receive:");
404 PrintString(5, 7, 0x4, "Parent: %08X", gRecvBuf[0][0]);
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: VBlankIntr
420
421 Description: V-Blank interrupt vector.
422
423 Arguments: None.
424
425 Returns: None.
426 *---------------------------------------------------------------------------*/
VBlankIntr(void)427 static void VBlankIntr(void)
428 {
429 // Start sending new data
430 if (WH_GetSystemState() == WH_SYSSTATE_CONNECTED)
431 {
432 switch (WH_GetConnectMode())
433 {
434 case WH_CONNECTMODE_MP_PARENT:
435 gSendBuf[0] = gFrame;
436 //********************************
437 (void)WH_SendData(gSendBuf, PARENT_DATA_SIZE, NULL);
438 //********************************
439 break;
440 case WH_CONNECTMODE_MP_CHILD:
441 gSendBuf[0] = gFrame;
442 //********************************
443 (void)WH_SendData(gSendBuf, CHILD_DATA_SIZE, NULL);
444 //********************************
445 break;
446 }
447 }
448
449 // Reflect virtual screen in VRAM
450 DC_FlushRange(gScreen, sizeof(gScreen));
451 /* I/O register is accessed using DMA operation, so cache wait is not needed */
452 // DC_WaitWriteBufferEmpty();
453 GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
454
455 // Sets the IRQ check flag
456 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
457 }
458
459 /*---------------------------------------------------------------------------*
460 Name: MpReceiveCallback
461
462 Description: Function called when MP data is received.
463
464 Arguments: aid: AID of child originating transmission (if 0, then data is from parent)
465 data: Pointer to received data (NULL is disconnection notification)
466 length: Size of received data
467
468 Returns: None.
469 *---------------------------------------------------------------------------*/
MpReceiveCallback(u16 aid,u16 * data,u16 length)470 static void MpReceiveCallback(u16 aid, u16 *data, u16 length)
471 {
472 #pragma unused( length )
473 SDK_MAX_ASSERT(aid, 15);
474
475 if (data != NULL)
476 {
477 SDK_ASSERT(length >= 4);
478 gRecvFlag[aid] = TRUE;
479 // Copy source is aligned to 2 bytes (not 4 bytes)
480 if (aid == 0)
481 {
482 // When receiving from a parent
483 MI_CpuCopy8(data, &(gRecvBuf[aid][0]), PARENT_DATA_SIZE);
484 }
485 else
486 {
487 MI_CpuCopy8(data, &(gRecvBuf[aid][0]), CHILD_DATA_SIZE);
488 }
489 }
490 else
491 {
492 gRecvFlag[aid] = FALSE;
493 }
494 }
495
496 /*---------------------------------------------------------------------------*
497 Name: KeyRead
498
499 Description: Edits key input data
500 Detects press trigger, release trigger, and press-and-hold repeat.
501
502 Arguments: pKey: Structure that holds key input data to be edited
503
504 Returns: None.
505 *---------------------------------------------------------------------------*/
KeyRead(KeyInfo * pKey)506 static void KeyRead(KeyInfo * pKey)
507 {
508 static u16 repeat_count[12];
509 int i;
510 u16 r;
511
512 r = PAD_Read();
513 pKey->trg = 0x0000;
514 pKey->up = 0x0000;
515 pKey->rep = 0x0000;
516
517 for (i = 0; i < 12; i++)
518 {
519 if (r & (0x0001 << i))
520 {
521 if (!(pKey->cnt & (0x0001 << i)))
522 {
523 pKey->trg |= (0x0001 << i); // Press trigger
524 repeat_count[i] = 1;
525 }
526 else
527 {
528 if (repeat_count[i] > KEY_REPEAT_START)
529 {
530 pKey->rep |= (0x0001 << i); // Press-and-hold repeat
531 repeat_count[i] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
532 }
533 else
534 {
535 repeat_count[i]++;
536 }
537 }
538 }
539 else
540 {
541 if (pKey->cnt & (0x0001 << i))
542 {
543 pKey->up |= (0x0001 << i); // Release trigger
544 }
545 }
546 }
547 pKey->cnt = r; // Unprocessed key input
548 }
549
550 /*---------------------------------------------------------------------------*
551 Name: ClearString
552
553 Description: Clears the virtual screen.
554
555 Arguments: None.
556
557 Returns: None.
558 *---------------------------------------------------------------------------*/
ClearString(void)559 static void ClearString(void)
560 {
561 MI_CpuClearFast((void *)gScreen, sizeof(gScreen));
562 }
563
564 /*---------------------------------------------------------------------------*
565 Name: PrintString
566
567 Description: Positions the text string on the virtual screen. The string can be up to 32 chars.
568
569 Arguments: x: X-coordinate where character string starts (x 8 pixels).
570 y: Y-coordinate where character string starts (x 8 pixels).
571 palette: Specify text color by palette number.
572 text: Text string to position. Null-terminated.
573 ...: Virtual argument.
574
575 Returns: None.
576 *---------------------------------------------------------------------------*/
PrintString(s16 x,s16 y,u8 palette,char * text,...)577 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...)
578 {
579 va_list vlist;
580 char temp[32 + 2];
581 s32 i;
582
583 va_start(vlist, text);
584 (void)vsnprintf(temp, 33, text, vlist);
585 va_end(vlist);
586
587 *(u16 *)(&temp[32]) = 0x0000;
588 for (i = 0;; i++)
589 {
590 if (temp[i] == 0x00)
591 {
592 break;
593 }
594 gScreen[((y * 32) + x + i) % (32 * 32)] = (u16)((palette << 12) | temp[i]);
595 }
596 }
597
598 /*---------------------------------------------------------------------------*
599 Name: ColorString
600
601 Description: Changes the color of character strings printed on the virtual screen.
602
603 Arguments: x: X-coordinate (x 8 pixels) from which to start color change.
604 y: Y-coordinate (x 8 pixels) from which to start color change.
605 length: Number of characters to continue the color change for.
606 palette: Specify text color by palette number.
607
608 Returns: None.
609 *---------------------------------------------------------------------------*/
ColorString(s16 x,s16 y,s16 length,u8 palette)610 static void ColorString(s16 x, s16 y, s16 length, u8 palette)
611 {
612 s32 i;
613 u16 temp;
614 s32 index;
615
616 if (length < 0)
617 return;
618
619 for (i = 0; i < length; i++)
620 {
621 index = ((y * 32) + x + i) % (32 * 32);
622 temp = gScreen[index];
623 temp &= 0x0fff;
624 temp |= (palette << 12);
625 gScreen[index] = temp;
626 }
627 }
628
629 /*---------------------------------------------------------------------------*
630 Name: InitializeAllocateSystem
631
632 Description: Initializes the memory allocation system within the main memory arena.
633
634 Arguments: None.
635
636 Returns: None.
637 *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)638 static void InitializeAllocateSystem(void)
639 {
640 void *tempLo;
641 OSHeapHandle hh;
642
643 // Based on the premise that OS_Init has been already called
644 tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
645 OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
646 hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
647 if (hh < 0)
648 {
649 OS_Panic("ARM9: Fail to create heap...\n");
650 }
651 hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
652 }
653