1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - WM - demos - dataShare-1
3 File: main.c
4
5 Copyright 2006-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-02-03#$
14 $Rev: 9963 $
15 $Author: nishimoto_takashi $
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.
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 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 // Initialize wireless
169 if (!WH_Initialize())
170 {
171 OS_Panic("WH_Initialize failed.");
172 }
173 WH_SetGgid(DEFAULT_GGID);
174 //********************************
175
176 // LCD display start
177 GX_DispOn();
178 GXS_DispOn();
179
180 // Debug string output
181 OS_Printf("ARM9: WM data sharing demo started.\n");
182
183 // Empty call for getting key input data (strategy for pressing A Button in the IPL)
184 KeyRead(&gKey);
185
186 // Main loop
187 GameFrame(); // Never return
188 }
189
190 /*---------------------------------------------------------------------------*
191 Name: GameFrame
192
193 Description: Main loop for game frame
194
195 Arguments: None.
196
197 Returns: None.
198 *---------------------------------------------------------------------------*/
GameFrame(void)199 static void GameFrame(void)
200 {
201 for (gGameFrame = 0; TRUE; gGameFrame++)
202 {
203 // Get key input data
204 KeyRead(&gKey);
205
206 // Distributes processes based on communication status
207 switch (WH_GetSystemState())
208 {
209 case WH_SYSSTATE_IDLE:
210 ModeSelect();
211 break;
212 case WH_SYSSTATE_ERROR:
213 case WH_SYSSTATE_CONNECT_FAIL:
214 WH_Reset();
215 break;
216 case WH_SYSSTATE_FATAL:
217 ModeError();
218 break;
219 case WH_SYSSTATE_BUSY:
220 case WH_SYSSTATE_SCANNING:
221 ModeWorking();
222 break;
223 case WH_SYSSTATE_CONNECTED:
224 case WH_SYSSTATE_DATASHARING:
225 switch (WH_GetConnectMode())
226 {
227 case WH_CONNECTMODE_DS_PARENT:
228 ModeParent();
229 break;
230 case WH_CONNECTMODE_DS_CHILD:
231 ModeChild();
232 break;
233 }
234 break;
235 }
236
237 // Wait for completion of multiple cycles of picture frames
238 while (TRUE)
239 {
240 // Wait for V-Blank
241 OS_WaitVBlankIntr();
242 if (!(gPictureFrame % PICTURE_FRAME_PER_GAME_FRAME))
243 {
244 break;
245 }
246 }
247 }
248 }
249
250 /*---------------------------------------------------------------------------*
251 Name: ModeSelect
252
253 Description: Process in parent/child selection screen.
254
255 Arguments: None.
256
257 Returns: None.
258 *---------------------------------------------------------------------------*/
ModeSelect(void)259 static void ModeSelect(void)
260 {
261 // Clear the screen
262 ClearString();
263 // Character display
264 PrintString(3, 10, 0xf, "Push A to connect as PARENT");
265 PrintString(3, 12, 0xf, "Push B to connect as CHILD");
266
267 if (gKey.trg & PAD_BUTTON_A)
268 {
269 //********************************
270 // Start parent communication
271 (void)WH_ParentConnect(WH_CONNECTMODE_DS_PARENT, 0x0000, DEFAULT_CHAN);
272 //********************************
273 }
274 else if (gKey.trg & PAD_BUTTON_B)
275 {
276 static const u8 ANY_PARENT[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
277 //********************************
278 // Start child connection
279 (void)WH_ChildConnectAuto(WH_CONNECTMODE_DS_CHILD, ANY_PARENT, DEFAULT_CHAN);
280 //********************************
281 }
282 }
283
284 /*---------------------------------------------------------------------------*
285 Name: ModeError
286
287 Description: Processing in error display screen.
288
289 Arguments: None.
290
291 Returns: None.
292 *---------------------------------------------------------------------------*/
ModeError(void)293 static void ModeError(void)
294 {
295 // Clear the screen
296 ClearString();
297 // Character display
298 PrintString(5, 10, 0x1, "======= ERROR! =======");
299 PrintString(5, 13, 0xf, " Fatal error occured.");
300 PrintString(5, 14, 0xf, "Please reboot program.");
301 }
302
303 /*---------------------------------------------------------------------------*
304 Name: ModeWorking
305
306 Description: Processing in busy screen
307
308 Arguments: None.
309
310 Returns: None.
311 *---------------------------------------------------------------------------*/
ModeWorking(void)312 static void ModeWorking(void)
313 {
314 // Clear the screen
315 ClearString();
316 // Character display
317 PrintString(9, 11, 0xf, "Now working...");
318
319 if (gKey.trg & PAD_BUTTON_START)
320 {
321 //********************************
322 // End communication
323 WH_Finalize();
324 //********************************
325 }
326 }
327
328 /*---------------------------------------------------------------------------*
329 Name: ModeParent
330
331 Description: Processing in parent communications screen.
332
333 Arguments: None.
334
335 Returns: None.
336 *---------------------------------------------------------------------------*/
ModeParent(void)337 static void ModeParent(void)
338 {
339 BOOL result;
340
341 // Edit send data
342 gSendBuf[0] = (u16)(gPictureFrame >> 16);
343 gSendBuf[1] = (u16)(gPictureFrame & 0xffff);
344 gSendBuf[2] = (u16)(gGameFrame >> 16);
345 gSendBuf[3] = (u16)(gGameFrame & 0xffff);
346
347 //********************************
348 // Synchronize data sharing
349 result = WH_StepDS((void *)gSendBuf);
350 //********************************
351
352 // Clear the screen
353 ClearString();
354 // Character display
355 PrintString(8, 1, 0x2, "Parent mode");
356 // Display shared data
357 if (result)
358 {
359 PrintSharedData(WH_GetBitmap());
360 }
361 else
362 {
363 // Also try StepDataSharing in the next frame
364 gPictureFrame--;
365 }
366
367 if (gKey.trg & PAD_BUTTON_START)
368 {
369 //********************************
370 // End communication
371 WH_Finalize();
372 //********************************
373 }
374 }
375
376 /*---------------------------------------------------------------------------*
377 Name: ModeChild
378
379 Description: Processing in child communications screen.
380
381 Arguments: None.
382
383 Returns: None.
384 *---------------------------------------------------------------------------*/
ModeChild(void)385 static void ModeChild(void)
386 {
387 BOOL result;
388
389 // Edit send data
390 gSendBuf[0] = (u16)(gPictureFrame >> 16);
391 gSendBuf[1] = (u16)(gPictureFrame & 0xffff);
392 gSendBuf[2] = (u16)(gGameFrame >> 16);
393 gSendBuf[3] = (u16)(gGameFrame & 0xffff);
394
395 //********************************
396 // Synchronize data sharing
397 result = WH_StepDS((void *)gSendBuf);
398 //********************************
399
400 // Clear the screen
401 ClearString();
402 // Character display
403 PrintString(8, 1, 0x2, "Child mode");
404 // Display shared data
405 if (result)
406 {
407 PrintSharedData(WH_GetBitmapDS());
408 }
409 else
410 {
411 // Also try StepDataSharing in the next frame
412 gPictureFrame--;
413 }
414
415 if (gKey.trg & PAD_BUTTON_START)
416 {
417 //********************************
418 // End communication
419 WH_Finalize();
420 //********************************
421 }
422 }
423
424 /*---------------------------------------------------------------------------*
425 Name: VBlankIntr
426
427 Description: V-Blank interrupt vector.
428
429 Arguments: None.
430
431 Returns: None.
432 *---------------------------------------------------------------------------*/
VBlankIntr(void)433 static void VBlankIntr(void)
434 {
435 // Increment picture frame counter
436 gPictureFrame++;
437
438 // Repeat rendering to match game frame
439 if (!(gPictureFrame % PICTURE_FRAME_PER_GAME_FRAME))
440 {
441 // Reflect virtual screen in VRAM
442 DC_FlushRange(gScreen, sizeof(gScreen));
443 /* I/O register is accessed using DMA operation, so cache wait is not needed */
444 // DC_WaitWriteBufferEmpty();
445 GX_LoadBG0Scr(gScreen, 0, sizeof(gScreen));
446 }
447
448 // Sets the IRQ check flag
449 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
450 }
451
452 /*---------------------------------------------------------------------------*
453 Name: PrintSharedData
454
455 Description: Displays data from each shared terminal.
456
457 Arguments: bitmap: ID bitmap indicating the terminal receiving data
458
459 Returns: None.
460 *---------------------------------------------------------------------------*/
PrintSharedData(u16 bitmap)461 static void PrintSharedData(u16 bitmap)
462 {
463 u16 i;
464 //u8 *p;
465 u16 *p;
466 u16 temp[SHARED_DATA_SIZE / sizeof(u16)];
467
468 // Loop for maximum number of parent devices + child devices
469 for (i = 0; i < (1 + WM_NUM_MAX_CHILD); i++)
470 {
471 if (bitmap & (0x0001 << i))
472 {
473 //********************************
474 // Get data from terminal with ID of 'i'
475 p = WH_GetSharedDataAdr(i);
476 //********************************
477
478 if (p != NULL)
479 {
480 // Copy once to ensure alignment
481 MI_CpuCopy8(p, temp, SHARED_DATA_SIZE);
482 PrintString(2, (s16)(3 + i), 0x4,
483 "%04x%04x-%04x%04x", temp[0], temp[1], temp[2], temp[3]);
484 }
485 else
486 {
487 PrintString(2, (s16)(3 + i), 0x1, "xxxxxxxx-xxxxxxxx");
488 }
489 }
490 }
491 // Change the color only for data for this device
492 ColorString(2, (s16)(3 + WH_GetCurrentAid()), 17, 0xf);
493 }
494
495 /*---------------------------------------------------------------------------*
496 Name: KeyRead
497
498 Description: Edits key input data.
499 Detects press trigger, release trigger, and press-and-hold repeat.
500
501 Arguments: pKey: Structure that holds key input data to be edited
502
503 Returns: None.
504 *---------------------------------------------------------------------------*/
KeyRead(KeyInfo * pKey)505 static void KeyRead(KeyInfo * pKey)
506 {
507 static u16 repeat_count[12];
508 int i;
509 u16 r;
510
511 r = PAD_Read();
512 pKey->trg = 0x0000;
513 pKey->up = 0x0000;
514 pKey->rep = 0x0000;
515
516 for (i = 0; i < 12; i++)
517 {
518 if (r & (0x0001 << i))
519 {
520 if (!(pKey->cnt & (0x0001 << i)))
521 {
522 pKey->trg |= (0x0001 << i); // Press trigger
523 repeat_count[i] = 1;
524 }
525 else
526 {
527 if (repeat_count[i] > KEY_REPEAT_START)
528 {
529 pKey->rep |= (0x0001 << i); // Press-and-hold repeat
530 repeat_count[i] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
531 }
532 else
533 {
534 repeat_count[i]++;
535 }
536 }
537 }
538 else
539 {
540 if (pKey->cnt & (0x0001 << i))
541 {
542 pKey->up |= (0x0001 << i); // Release trigger
543 }
544 }
545 }
546 pKey->cnt = r; // Unprocessed key input
547 }
548
549 /*---------------------------------------------------------------------------*
550 Name: ClearString
551
552 Description: Clears the virtual screen.
553
554 Arguments: None.
555
556 Returns: None.
557 *---------------------------------------------------------------------------*/
ClearString(void)558 static void ClearString(void)
559 {
560 MI_CpuClearFast((void *)gScreen, sizeof(gScreen));
561 }
562
563 /*---------------------------------------------------------------------------*
564 Name: PrintString
565
566 Description: Positions the text string on the virtual screen. The string can be up to 32 chars.
567
568 Arguments: x: X-coordinate where character string starts (x 8 dots)
569 y: Y-coordinate where character string starts (x 8 dots)
570 palette: Specify text color by palette number
571 text: Text string to position. Null-terminated.
572 ...: Virtual argument.
573
574 Returns: None.
575 *---------------------------------------------------------------------------*/
PrintString(s16 x,s16 y,u8 palette,char * text,...)576 static void PrintString(s16 x, s16 y, u8 palette, char *text, ...)
577 {
578 va_list vlist;
579 char temp[32 + 2];
580 s32 i;
581
582 va_start(vlist, text);
583 (void)vsnprintf(temp, 33, text, vlist);
584 va_end(vlist);
585
586 *(u16 *)(&temp[32]) = 0x0000;
587 for (i = 0;; i++)
588 {
589 if (temp[i] == 0x00)
590 {
591 break;
592 }
593 gScreen[((y * 32) + x + i) % (32 * 32)] = (u16)((palette << 12) | temp[i]);
594 }
595 }
596
597 /*---------------------------------------------------------------------------*
598 Name: ColorString
599
600 Description: Changes the color of character strings printed on the virtual screen.
601
602 Arguments: x: X-coordinate (x 8 dots ) from which to start color change
603 y: Y-coordinate (x 8 dots ) from which to start color change
604 length: Number of characters to continue the color change for
605 palette: Specify text color by palette number
606
607 Returns: None.
608 *---------------------------------------------------------------------------*/
ColorString(s16 x,s16 y,s16 length,u8 palette)609 static void ColorString(s16 x, s16 y, s16 length, u8 palette)
610 {
611 s32 i;
612 u16 temp;
613 s32 index;
614
615 if (length < 0)
616 return;
617
618 for (i = 0; i < length; i++)
619 {
620 index = ((y * 32) + x + i) % (32 * 32);
621 temp = gScreen[index];
622 temp &= 0x0fff;
623 temp |= (palette << 12);
624 gScreen[index] = temp;
625 }
626 }
627
628 /*---------------------------------------------------------------------------*
629 Name: InitializeAllocateSystem
630
631 Description: Initializes the memory allocation system within the main memory arena.
632
633 Arguments: None.
634
635 Returns: None.
636 *---------------------------------------------------------------------------*/
InitializeAllocateSystem(void)637 static void InitializeAllocateSystem(void)
638 {
639 void *tempLo;
640 OSHeapHandle hh;
641
642 // Based on the premise that OS_Init has been already called
643 tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
644 OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
645 hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
646 if (hh < 0)
647 {
648 OS_Panic("ARM9: Fail to create heap...\n");
649 }
650 hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
651 }
652
653 /*---------------------------------------------------------------------------*
654 End of file
655 *---------------------------------------------------------------------------*/
656