1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - WM - demos - dataShare-1
3 File: main.c
4
5 Copyright 2006-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-28#$
14 $Rev: 11026 $
15 $Author: tominaga_masafumi $
16 *---------------------------------------------------------------------------*/
17 /*---------------------------------------------------------------------------*
18 This sample performs wireless data sharing communication using the WM library.
19 It automatically connects to a nearby dataShare-1 demo and shares a total of 8 bytes in the wireless communications group: a 4-byte game frame count and a 4-byte picture frame count.
20
21
22
23 HOWTO:
24 1. Press the A Button to start communications as a parent.
25 As soon as a nearby child with the same dataShare-1 demo is found, data-sharing communication with that child begins automatically. Communication with up to 15 children is possible at the same time.
26
27 2. Press the B Button to start communications as a child.
28 As soon as a nearby parent with the same dataShare-1 demo is found, communication with that parent begins automatically.
29
30 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.
31
32 *---------------------------------------------------------------------------*/
33
34 #ifdef SDK_TWL
35 #include <twl.h>
36 #else
37 #include <nitro.h>
38 #endif
39
40 #include <nitro/wm.h>
41
42 #include "font.h"
43 #include "wh.h"
44
45
46 /*---------------------------------------------------------------------------*
47 Constant definitions
48 *---------------------------------------------------------------------------*/
49 #define KEY_REPEAT_START 25 // Number of frames until key repeat starts
50 #define KEY_REPEAT_SPAN 10 // Number of frames between key repeats
51
52 #define PICTURE_FRAME_PER_GAME_FRAME 2
53
54 #define DEFAULT_GGID 0x003fff11
55 #define NUM_MAX_CHILD 15
56 #define DEFAULT_CHAN 1
57 #define SHARED_DATA_SIZE 8
58
59 /*---------------------------------------------------------------------------*
60 Structure definitions
61 *---------------------------------------------------------------------------*/
62 // Key input data
63 typedef struct KeyInfo
64 {
65 u16 cnt; // Unprocessed input value
66 u16 trg; // Push trigger input
67 u16 up; // Release trigger input
68 u16 rep; // Press and hold repeat input
69
70 }
71 KeyInfo;
72
73
74 /*---------------------------------------------------------------------------*
75 Internal Function Definitions
76 *---------------------------------------------------------------------------*/
77 static void GameFrame(void); // Main loop for game frame
78 static void ModeSelect(void); // Parent/child select screen
79 static void ModeError(void); // Error display screen
80 static void ModeWorking(void); // Busy screen
81 static void ModeParent(void); // Parent communications screen
82 static void ModeChild(void); // Child communications screen
83 static void VBlankIntr(void); // V-Blank interrupt handler
84 static void PrintSharedData(u16 bitmap); // Displays shared data
85
86 // General purpose subroutines
87 static void KeyRead(KeyInfo * pKey);
88 static void ClearString(void);
89 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...);
90 static void ColorString(s16 x, s16 y, s16 length, u8 palette);
91 static void InitializeAllocateSystem(void);
92
93
94 /*---------------------------------------------------------------------------*
95 Internal Variable Definitions
96 *---------------------------------------------------------------------------*/
97 static u16 gScreen[32 * 32]; // Virtual screen
98 static KeyInfo gKey; // Key input
99 static vs32 gPictureFrame; // Picture frame counter
100 static vs32 gGameFrame; // Game frame counter
101
102 // Send data buffer (must be 32-Byte aligned)
103 static u16 gSendBuf[SHARED_DATA_SIZE / sizeof(u16)] ATTRIBUTE_ALIGN(32);
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()
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 // Variable initialization
155 gPictureFrame = 0;
156
157 // Interrupt settings
158 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
159 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
160 (void)GX_VBlankIntr(TRUE);
161 (void)OS_EnableIrq();
162 (void)OS_EnableInterrupts();
163
164 // Initialize memory allocation system
165 InitializeAllocateSystem();
166
167 //********************************
168 // Wireless settings
169 WH_SetGgid(DEFAULT_GGID);
170 //********************************
171
172 // LCD display start
173 GX_DispOn();
174 GXS_DispOn();
175
176 // Debug string output
177 OS_Printf("ARM9: WM data sharing demo started.\n");
178
179 // Empty call for getting key input data (strategy for pressing A Button in the IPL)
180 KeyRead(&gKey);
181
182 // Main loop
183 GameFrame(); // Never return
184 }
185
186 /*---------------------------------------------------------------------------*
187 Name: GameFrame
188
189 Description: Main loop for game frame
190
191 Arguments: None.
192
193 Returns: None.
194 *---------------------------------------------------------------------------*/
GameFrame(void)195 static void GameFrame(void)
196 {
197 for (gGameFrame = 0; TRUE; gGameFrame++)
198 {
199 // Get key input data
200 KeyRead(&gKey);
201
202 // Distributes processes based on communication status
203 switch (WH_GetSystemState())
204 {
205 case WH_SYSSTATE_STOP:
206 ModeSelect();
207 break;
208 case WH_SYSSTATE_IDLE:
209 case WH_SYSSTATE_ERROR:
210 case WH_SYSSTATE_CONNECT_FAIL:
211 // End communication
212 WH_Finalize();
213 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
214 (void)WH_End();
215 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
216 break;
217 case WH_SYSSTATE_FATAL:
218 ModeError();
219 break;
220 case WH_SYSSTATE_BUSY:
221 case WH_SYSSTATE_SCANNING:
222 ModeWorking();
223 break;
224 case WH_SYSSTATE_CONNECTED:
225 case WH_SYSSTATE_DATASHARING:
226 switch (WH_GetConnectMode())
227 {
228 case WH_CONNECTMODE_DS_PARENT:
229 ModeParent();
230 break;
231 case WH_CONNECTMODE_DS_CHILD:
232 ModeChild();
233 break;
234 }
235 break;
236 }
237
238 // Wait for completion of multiple cycles of picture frames
239 while (TRUE)
240 {
241 // Wait for V-Blank
242 OS_WaitVBlankIntr();
243 if (!(gPictureFrame % PICTURE_FRAME_PER_GAME_FRAME))
244 {
245 break;
246 }
247 }
248 }
249 }
250
251 /*---------------------------------------------------------------------------*
252 Name: ModeSelect
253
254 Description: Processing in parent/child selection screen.
255
256 Arguments: None.
257
258 Returns: None.
259 *---------------------------------------------------------------------------*/
ModeSelect(void)260 static void ModeSelect(void)
261 {
262 // Clear the screen
263 ClearString();
264 // Character display
265 PrintString(3, 10, 0xf, "Push A to connect as PARENT");
266 PrintString(3, 12, 0xf, "Push B to connect as CHILD");
267
268 if (gKey.trg & PAD_BUTTON_A)
269 {
270 // WH initialization
271 if (!WH_Initialize())
272 {
273 OS_Panic("WH_Initiailze failed.");
274 }
275 else
276 {
277 // Wait for initialization to complete
278 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
279 }
280
281 //********************************
282 // Start parent communication
283 (void)WH_ParentConnect(WH_CONNECTMODE_DS_PARENT, 0x0000, DEFAULT_CHAN);
284 //********************************
285 }
286 else if (gKey.trg & PAD_BUTTON_B)
287 {
288 static const u8 ANY_PARENT[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
289
290 // WH initialization
291 if (!WH_Initialize())
292 {
293 OS_Panic("WH_Initiailze failed.");
294 }
295 else
296 {
297 // Wait for initialization to complete
298 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
299 }
300
301 //********************************
302 // Start child connection
303 (void)WH_ChildConnectAuto(WH_CONNECTMODE_DS_CHILD, ANY_PARENT, DEFAULT_CHAN);
304 //********************************
305 }
306 }
307
308 /*---------------------------------------------------------------------------*
309 Name: ModeError
310
311 Description: Processing in error display screen.
312
313 Arguments: None.
314
315 Returns: None.
316 *---------------------------------------------------------------------------*/
ModeError(void)317 static void ModeError(void)
318 {
319 // Clear the screen
320 ClearString();
321 // Character display
322 PrintString(5, 10, 0x1, "======= ERROR! =======");
323 PrintString(5, 13, 0xf, " Fatal error occured.");
324 PrintString(5, 14, 0xf, "Please reboot program.");
325 }
326
327 /*---------------------------------------------------------------------------*
328 Name: ModeWorking
329
330 Description: Processing in busy screen.
331
332 Arguments: None.
333
334 Returns: None.
335 *---------------------------------------------------------------------------*/
ModeWorking(void)336 static void ModeWorking(void)
337 {
338 // Clear the screen
339 ClearString();
340 // Character display
341 PrintString(9, 11, 0xf, "Now working...");
342
343 if (gKey.trg & PAD_BUTTON_START)
344 {
345 //********************************
346 // End communication
347 WH_Finalize();
348 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
349 (void)WH_End();
350 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
351 //********************************
352 }
353 }
354
355 /*---------------------------------------------------------------------------*
356 Name: ModeParent
357
358 Description: Processing in parent communications screen.
359
360 Arguments: None.
361
362 Returns: None.
363 *---------------------------------------------------------------------------*/
ModeParent(void)364 static void ModeParent(void)
365 {
366 BOOL result;
367
368 // Edit send data
369 gSendBuf[0] = (u16)(gPictureFrame >> 16);
370 gSendBuf[1] = (u16)(gPictureFrame & 0xffff);
371 gSendBuf[2] = (u16)(gGameFrame >> 16);
372 gSendBuf[3] = (u16)(gGameFrame & 0xffff);
373
374 //********************************
375 // Synchronize data sharing
376 result = WH_StepDS((void *)gSendBuf);
377 //********************************
378
379 // Clear the screen
380 ClearString();
381 // Character display
382 PrintString(8, 1, 0x2, "Parent mode");
383 // Display shared data
384 if (result)
385 {
386 PrintSharedData(WH_GetBitmap());
387 }
388 else
389 {
390 // Also try StepDataSharing in the next frame
391 gPictureFrame--;
392 }
393
394 if (gKey.trg & PAD_BUTTON_START)
395 {
396 //********************************
397 // End communication
398 WH_Finalize();
399 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
400 (void)WH_End();
401 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
402 //********************************
403 }
404 }
405
406 /*---------------------------------------------------------------------------*
407 Name: ModeChild
408
409 Description: Processing in child communications screen.
410
411 Arguments: None.
412
413 Returns: None.
414 *---------------------------------------------------------------------------*/
ModeChild(void)415 static void ModeChild(void)
416 {
417 BOOL result;
418
419 // Edit send data
420 gSendBuf[0] = (u16)(gPictureFrame >> 16);
421 gSendBuf[1] = (u16)(gPictureFrame & 0xffff);
422 gSendBuf[2] = (u16)(gGameFrame >> 16);
423 gSendBuf[3] = (u16)(gGameFrame & 0xffff);
424
425 //********************************
426 // Synchronize data sharing
427 result = WH_StepDS((void *)gSendBuf);
428 //********************************
429
430 // Clear the screen
431 ClearString();
432 // Character display
433 PrintString(8, 1, 0x2, "Child mode");
434 // Display shared data
435 if (result)
436 {
437 PrintSharedData(WH_GetBitmapDS());
438 }
439 else
440 {
441 // Also try StepDataSharing in the next frame
442 gPictureFrame--;
443 }
444
445 if (gKey.trg & PAD_BUTTON_START)
446 {
447 //********************************
448 // End communication
449 WH_Finalize();
450 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
451 (void)WH_End();
452 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
453 //********************************
454 }
455 }
456
457 /*---------------------------------------------------------------------------*
458 Name: VBlankIntr
459
460 Description: V-Blank interrupt vector.
461
462 Arguments: None.
463
464 Returns: None.
465 *---------------------------------------------------------------------------*/
VBlankIntr(void)466 static void VBlankIntr(void)
467 {
468 // Increment picture frame counter
469 gPictureFrame++;
470
471 // Repeat rendering to match game frame
472 if (!(gPictureFrame % PICTURE_FRAME_PER_GAME_FRAME))
473 {
474 // Reflect virtual screen in VRAM
475 DC_FlushRange(gScreen, sizeof(gScreen));
476 /* I/O register is accessed using DMA operation, so cache wait is not needed */
477 // DC_WaitWriteBufferEmpty();
478 GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
479 }
480
481 // Sets the IRQ check flag
482 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
483 }
484
485 /*---------------------------------------------------------------------------*
486 Name: PrintSharedData
487
488 Description: Displays data from each shared terminal.
489
490 Arguments: bitmap: bitmap of IDs indicating the terminals that received data.
491
492 Returns: None.
493 *---------------------------------------------------------------------------*/
PrintSharedData(u16 bitmap)494 static void PrintSharedData(u16 bitmap)
495 {
496 u16 i;
497 //u8 *p;
498 u16 *p;
499 u16 temp[SHARED_DATA_SIZE / sizeof(u16)];
500
501 // Loop for maximum number of parent devices + child devices
502 for (i = 0; i < (1 + WM_NUM_MAX_CHILD); i++)
503 {
504 if (bitmap & (0x0001 << i))
505 {
506 //********************************
507 // Get data from terminal with ID of 'i'
508 p = WH_GetSharedDataAdr(i);
509 //********************************
510
511 if (p != NULL)
512 {
513 // Copy once to ensure alignment
514 MI_CpuCopy8(p, temp, SHARED_DATA_SIZE);
515 PrintString(2, (s16)(3 + i), 0x4,
516 "%04x%04x-%04x%04x", temp[0], temp[1], temp[2], temp[3]);
517 }
518 else
519 {
520 PrintString(2, (s16)(3 + i), 0x1, "xxxxxxxx-xxxxxxxx");
521 }
522 }
523 }
524 // Change the color only for data for the local host
525 ColorString(2, (s16)(3 + WH_GetCurrentAid()), 17, 0xf);
526 }
527
528 /*---------------------------------------------------------------------------*
529 Name: KeyRead
530
531 Description: Edits key input data
532 Detects press trigger, release trigger, and press-and-hold repeat.
533
534 Arguments: pKey: Structure that holds key input data to be edited
535
536 Returns: None.
537 *---------------------------------------------------------------------------*/
KeyRead(KeyInfo * pKey)538 static void KeyRead(KeyInfo * pKey)
539 {
540 static u16 repeat_count[12];
541 int i;
542 u16 r;
543
544 r = PAD_Read();
545 pKey->trg = 0x0000;
546 pKey->up = 0x0000;
547 pKey->rep = 0x0000;
548
549 for (i = 0; i < 12; i++)
550 {
551 if (r & (0x0001 << i))
552 {
553 if (!(pKey->cnt & (0x0001 << i)))
554 {
555 pKey->trg |= (0x0001 << i); // Press trigger
556 repeat_count[i] = 1;
557 }
558 else
559 {
560 if (repeat_count[i] > KEY_REPEAT_START)
561 {
562 pKey->rep |= (0x0001 << i); // Press-and-hold repeat
563 repeat_count[i] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
564 }
565 else
566 {
567 repeat_count[i]++;
568 }
569 }
570 }
571 else
572 {
573 if (pKey->cnt & (0x0001 << i))
574 {
575 pKey->up |= (0x0001 << i); // Release trigger
576 }
577 }
578 }
579 pKey->cnt = r; // Unprocessed key input
580 }
581
582 /*---------------------------------------------------------------------------*
583 Name: ClearString
584
585 Description: Clears the virtual screen.
586
587 Arguments: None.
588
589 Returns: None.
590 *---------------------------------------------------------------------------*/
ClearString(void)591 static void ClearString(void)
592 {
593 MI_CpuClearFast((void *)gScreen, sizeof(gScreen));
594 }
595
596 /*---------------------------------------------------------------------------*
597 Name: PrintString
598
599 Description: Positions the text string on the virtual screen. The string can be up to 32 chars.
600
601 Arguments: x: X-coordinate where character string starts (x 8 pixels).
602 y: Y-coordinate where character string starts (x 8 pixels).
603 palette: Specify text color by palette number.
604 text: Text string to position. Null-terminated.
605 ...: Virtual argument.
606
607 Returns: None.
608 *---------------------------------------------------------------------------*/
PrintString(s16 x,s16 y,u8 palette,char * text,...)609 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...)
610 {
611 va_list vlist;
612 char temp[32 + 2];
613 s32 i;
614
615 va_start(vlist, text);
616 (void)vsnprintf(temp, 33, text, vlist);
617 va_end(vlist);
618
619 *(u16 *)(&temp[32]) = 0x0000;
620 for (i = 0;; i++)
621 {
622 if (temp[i] == 0x00)
623 {
624 break;
625 }
626 gScreen[((y * 32) + x + i) % (32 * 32)] = (u16)((palette << 12) | temp[i]);
627 }
628 }
629
630 /*---------------------------------------------------------------------------*
631 Name: ColorString
632
633 Description: Changes the color of character strings printed on the virtual screen.
634
635 Arguments: x: X-coordinate (x 8 pixels) from which to start color change.
636 y: Y-coordinate (x 8 pixels) from which to start color change.
637 length: Number of characters to continue the color change for.
638 palette: Specify text color by palette number.
639
640 Returns: None.
641 *---------------------------------------------------------------------------*/
ColorString(s16 x,s16 y,s16 length,u8 palette)642 static void ColorString(s16 x, s16 y, s16 length, u8 palette)
643 {
644 s32 i;
645 u16 temp;
646 s32 index;
647
648 if (length < 0)
649 return;
650
651 for (i = 0; i < length; i++)
652 {
653 index = ((y * 32) + x + i) % (32 * 32);
654 temp = gScreen[index];
655 temp &= 0x0fff;
656 temp |= (palette << 12);
657 gScreen[index] = temp;
658 }
659 }
660
661 /*---------------------------------------------------------------------------*
662 Name: InitializeAllocateSystem
663
664 Description: Initializes the memory allocation system within the main memory arena.
665
666 Arguments: None.
667
668 Returns: None.
669 *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)670 static void InitializeAllocateSystem(void)
671 {
672 void *tempLo;
673 OSHeapHandle hh;
674
675 // Based on the premise that OS_Init has been already called
676 tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
677 OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
678 hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
679 if (hh < 0)
680 {
681 OS_Panic("ARM9: Fail to create heap...\n");
682 }
683 hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
684 }
685
686 /*---------------------------------------------------------------------------*
687 End of file
688 *---------------------------------------------------------------------------*/
689