1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - WVR - demos - simple
3 File: main.c
4
5 Copyright 2003-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 "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 // Initialize wireless
166 if (!WH_Initialize())
167 {
168 OS_Panic("WH_Initialize failed.");
169 }
170 WH_SetGgid(DEFAULT_GGID);
171 WH_SetReceiver(MpReceiveCallback);
172 //************************************
173
174 // Debug string output
175 OS_Printf("ARM9: ichneumon test program started.\n");
176
177 // Empty call for getting key input data (strategy for pressing A Button in the IPL)
178 KeyRead(&gKey);
179
180 // Main loop
181 for (gFrame = 0; TRUE; gFrame++)
182 {
183 // Get key input data
184 KeyRead(&gKey);
185
186 // Clear the screen
187 ClearString();
188
189 // Distributes processes based on communication status
190 switch (WH_GetSystemState())
191 {
192 case WH_SYSSTATE_IDLE:
193 ModeSelect();
194 break;
195 case WH_SYSSTATE_ERROR:
196 case WH_SYSSTATE_CONNECT_FAIL:
197 WH_Reset();
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 to be notified end of async processing in wireless operation control library.
228
229
230 Arguments: arg: Argument specified when WVR_StartUpAsync is called. Not used.
231 result: The processing results from async 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: Process 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 for (i = 1; i < (WM_NUM_MAX_CHILD + 1); i++)
266 {
267 gRecvFlag[i] = FALSE;
268 }
269
270 (void)WH_ParentConnect(WH_CONNECTMODE_MP_PARENT, 0x0000, DEFAULT_CHAN);
271 //********************************
272 }
273 else if (gKey.trg & PAD_BUTTON_B)
274 {
275 static const u8 ANY_PARENT[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
276 //********************************
277 (void)WH_ChildConnectAuto(WH_CONNECTMODE_MP_CHILD, ANY_PARENT, DEFAULT_CHAN);
278 //********************************
279 }
280 }
281
282 /*---------------------------------------------------------------------------*
283 Name: ModeError
284
285 Description: Processing in error display screen.
286
287 Arguments: None.
288
289 Returns: None.
290 *---------------------------------------------------------------------------*/
ModeError(void)291 static void ModeError(void)
292 {
293 PrintString(5, 10, 0x1, "======= ERROR! =======");
294 PrintString(5, 13, 0xf, " Fatal error occured.");
295 PrintString(5, 14, 0xf, "Please reboot program.");
296 }
297
298 /*---------------------------------------------------------------------------*
299 Name: ModeWorking
300
301 Description: Processing in busy screen.
302
303 Arguments: None.
304
305 Returns: None.
306 *---------------------------------------------------------------------------*/
ModeWorking(void)307 static void ModeWorking(void)
308 {
309 PrintString(9, 11, 0xf, "Now working...");
310
311 if (gKey.trg & PAD_BUTTON_START)
312 {
313 //********************************
314 WH_Finalize();
315 //********************************
316 }
317 }
318
319 /*---------------------------------------------------------------------------*
320 Name: ModeParent
321
322 Description: Processing in parent communications screen.
323
324 Arguments: None.
325
326 Returns: None.
327 *---------------------------------------------------------------------------*/
ModeParent(void)328 static void ModeParent(void)
329 {
330 PrintString(8, 1, 0x2, "Parent mode");
331 PrintString(4, 3, 0x4, "Send: %08X", gSendBuf[0]);
332 PrintString(4, 5, 0x4, "Receive:");
333 {
334 s32 i;
335
336 for (i = 1; i < (WM_NUM_MAX_CHILD + 1); i++)
337 {
338 if (gRecvFlag[i])
339 {
340 PrintString(5, (s16)(6 + i), 0x4, "Child%02d: %08X", i, gRecvBuf[i][0]);
341 }
342 else
343 {
344 PrintString(5, (s16)(6 + i), 0x7, "No child");
345 }
346 }
347 }
348
349 if (gKey.trg & PAD_BUTTON_START)
350 {
351 //********************************
352 WH_Finalize();
353 //********************************
354 }
355 }
356
357 /*---------------------------------------------------------------------------*
358 Name: ModeChild
359
360 Description: Processing in child communications screen.
361
362 Arguments: None.
363
364 Returns: None.
365 *---------------------------------------------------------------------------*/
ModeChild(void)366 static void ModeChild(void)
367 {
368 PrintString(8, 1, 0x2, "Child mode");
369 PrintString(4, 3, 0x4, "Send: %08X", gSendBuf[0]);
370 PrintString(4, 5, 0x4, "Receive:");
371 PrintString(5, 7, 0x4, "Parent: %08X", gRecvBuf[0][0]);
372
373 if (gKey.trg & PAD_BUTTON_START)
374 {
375 //********************************
376 WH_Finalize();
377 //********************************
378 }
379 }
380
381 /*---------------------------------------------------------------------------*
382 Name: VBlankIntr
383
384 Description: V-Blank interrupt vector.
385
386 Arguments: None.
387
388 Returns: None.
389 *---------------------------------------------------------------------------*/
VBlankIntr(void)390 static void VBlankIntr(void)
391 {
392 // Start sending new data
393 if (WH_GetSystemState() == WH_SYSSTATE_CONNECTED)
394 {
395 switch (WH_GetConnectMode())
396 {
397 case WH_CONNECTMODE_MP_PARENT:
398 gSendBuf[0] = gFrame;
399 //********************************
400 (void)WH_SendData(gSendBuf, PARENT_DATA_SIZE, NULL);
401 //********************************
402 break;
403 case WH_CONNECTMODE_MP_CHILD:
404 gSendBuf[0] = gFrame;
405 //********************************
406 (void)WH_SendData(gSendBuf, CHILD_DATA_SIZE, NULL);
407 //********************************
408 break;
409 }
410 }
411
412 // Reflect virtual screen in VRAM
413 DC_FlushRange(gScreen, sizeof(gScreen));
414 /* I/O register is accessed using DMA operation, so cache wait is not needed */
415 // DC_WaitWriteBufferEmpty();
416 GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
417
418 // Sets the IRQ check flag
419 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
420 }
421
422 /*---------------------------------------------------------------------------*
423 Name: MpReceiveCallback
424
425 Description: Function called when MP data is received.
426
427 Arguments: aid: AID of child originating transmission (if 0, then data is from parent)
428 data: Pointer to received data (NULL is disconnection notification)
429 length: Size of received data
430
431 Returns: None.
432 *---------------------------------------------------------------------------*/
MpReceiveCallback(u16 aid,u16 * data,u16 length)433 static void MpReceiveCallback(u16 aid, u16 *data, u16 length)
434 {
435 #pragma unused( length )
436 SDK_MAX_ASSERT(aid, 15);
437
438 if (data != NULL)
439 {
440 SDK_ASSERT(length >= 4);
441 gRecvFlag[aid] = TRUE;
442 // Copy source is aligned to 2 bytes (not 4 bytes)
443 if (aid == 0)
444 {
445 // When receiving from a parent
446 MI_CpuCopy8(data, &(gRecvBuf[aid][0]), PARENT_DATA_SIZE);
447 }
448 else
449 {
450 MI_CpuCopy8(data, &(gRecvBuf[aid][0]), CHILD_DATA_SIZE);
451 }
452 }
453 else
454 {
455 gRecvFlag[aid] = FALSE;
456 }
457 }
458
459 /*---------------------------------------------------------------------------*
460 Name: KeyRead
461
462 Description: Edits key input data.
463 Detects press trigger, release trigger, and press-and-hold repeat.
464
465 Arguments: pKey: Structure that holds key input data to be edited
466
467 Returns: None.
468 *---------------------------------------------------------------------------*/
KeyRead(KeyInfo * pKey)469 static void KeyRead(KeyInfo * pKey)
470 {
471 static u16 repeat_count[12];
472 int i;
473 u16 r;
474
475 r = PAD_Read();
476 pKey->trg = 0x0000;
477 pKey->up = 0x0000;
478 pKey->rep = 0x0000;
479
480 for (i = 0; i < 12; i++)
481 {
482 if (r & (0x0001 << i))
483 {
484 if (!(pKey->cnt & (0x0001 << i)))
485 {
486 pKey->trg |= (0x0001 << i); // Press trigger
487 repeat_count[i] = 1;
488 }
489 else
490 {
491 if (repeat_count[i] > KEY_REPEAT_START)
492 {
493 pKey->rep |= (0x0001 << i); // Press-and-hold repeat
494 repeat_count[i] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
495 }
496 else
497 {
498 repeat_count[i]++;
499 }
500 }
501 }
502 else
503 {
504 if (pKey->cnt & (0x0001 << i))
505 {
506 pKey->up |= (0x0001 << i); // Release trigger
507 }
508 }
509 }
510 pKey->cnt = r; // Unprocessed key input
511 }
512
513 /*---------------------------------------------------------------------------*
514 Name: ClearString
515
516 Description: Clears the virtual screen.
517
518 Arguments: None.
519
520 Returns: None.
521 *---------------------------------------------------------------------------*/
ClearString(void)522 static void ClearString(void)
523 {
524 MI_CpuClearFast((void *)gScreen, sizeof(gScreen));
525 }
526
527 /*---------------------------------------------------------------------------*
528 Name: PrintString
529
530 Description: Positions the text string on the virtual screen. The string can be up to 32 chars.
531
532 Arguments: x: X-coordinate where character string starts (x 8 dots)
533 y: Y-coordinate where character string starts (x 8 dots)
534 palette: Specify text color by palette number
535 text: Text string to position. NULL terminated
536 ...: Virtual argument
537
538 Returns: None.
539 *---------------------------------------------------------------------------*/
PrintString(s16 x,s16 y,u8 palette,char * text,...)540 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...)
541 {
542 va_list vlist;
543 char temp[32 + 2];
544 s32 i;
545
546 va_start(vlist, text);
547 (void)vsnprintf(temp, 33, text, vlist);
548 va_end(vlist);
549
550 *(u16 *)(&temp[32]) = 0x0000;
551 for (i = 0;; i++)
552 {
553 if (temp[i] == 0x00)
554 {
555 break;
556 }
557 gScreen[((y * 32) + x + i) % (32 * 32)] = (u16)((palette << 12) | temp[i]);
558 }
559 }
560
561 /*---------------------------------------------------------------------------*
562 Name: ColorString
563
564 Description: Changes the color of character strings printed on the virtual screen.
565
566 Arguments: x: X-coordinate (x 8 dots) from which to start color change
567 y: Y-coordinate (x 8 dots) from which to start color change
568 length: Number of characters to continue the color change for
569 palette: Specify text color by palette number
570
571 Returns: None.
572 *---------------------------------------------------------------------------*/
ColorString(s16 x,s16 y,s16 length,u8 palette)573 static void ColorString(s16 x, s16 y, s16 length, u8 palette)
574 {
575 s32 i;
576 u16 temp;
577 s32 index;
578
579 if (length < 0)
580 return;
581
582 for (i = 0; i < length; i++)
583 {
584 index = ((y * 32) + x + i) % (32 * 32);
585 temp = gScreen[index];
586 temp &= 0x0fff;
587 temp |= (palette << 12);
588 gScreen[index] = temp;
589 }
590 }
591
592 /*---------------------------------------------------------------------------*
593 Name: InitializeAllocateSystem
594
595 Description: Initializes the memory allocation system within the main memory arena.
596
597 Arguments: None.
598
599 Returns: None.
600 *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)601 static void InitializeAllocateSystem(void)
602 {
603 void *tempLo;
604 OSHeapHandle hh;
605
606 // Based on the premise that OS_Init has been already called
607 tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
608 OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
609 hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
610 if (hh < 0)
611 {
612 OS_Panic("ARM9: Fail to create heap...\n");
613 }
614 hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
615 }
616