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