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