1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - WM - demos - wep-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-08-28#$
14 $Rev: 11026 $
15 $Author: tominaga_masafumi $
16 *---------------------------------------------------------------------------*/
17
18 /*
19 wep-1 demo
20
21 This demo is the dataShare-Model demo with WEP usage added during connection.
22 */
23 #ifdef SDK_TWL
24 #include <twl.h>
25 #else
26 #include <nitro.h>
27 #endif
28
29 #include <nitro/wm.h>
30 #include <string.h>
31
32 #include "main.h"
33 #include "font.h"
34 #include "print.h"
35 #include "key.h"
36 #include "graphics.h"
37 #include "wh.h"
38 #include "menu.h"
39
40 /* The GGID used in this demo */
41 #define WH_GGID SDK_MAKEGGID_SYSTEM(0x14)
42 #define GRAPH_TOTAL_FRAME 60
43
44 typedef struct GraphData_
45 {
46 u16 level;
47 s16 data;
48 }
49 GraphData;
50
51 static u16 sForcedChannel = 0;
52 static u16 sTgid = 0;
53 static int sSysMode = 0;
54 static int sSysModeStep = 0;
55
56 static s32 sFrame = 0;
57 static u8 sSendBuf[512] ATTRIBUTE_ALIGN(32);
58 static u8 sRecvBuf[512] ATTRIBUTE_ALIGN(32);
59 static BOOL sRecvFlag[WM_NUM_MAX_CHILD + 1];
60
61 static WMKeySet sKeySet;
62
63 static GraphData sGraphData[1 + WM_NUM_MAX_CHILD][GRAPH_TOTAL_FRAME];
64 static PRScreen sInfoScreen ATTRIBUTE_ALIGN(32);
65 static PRScreen sDebugScreen ATTRIBUTE_ALIGN(32);
66
67 static int sBeaconCount = 0;
68 static int sNeedWait = 0;
69 static BOOL sGraphEnabled = 0;
70
71 static WMBssDesc sBssDesc[3];
72 static Window sRoleMenuWindow;
73 static Window sSelectChannelWindow;
74 static Window sSelectParentWindow;
75 static Window sLobbyWindow;
76 static Window sErrorWindow;
77 static Window sBusyWindow;
78 static Window sOptionWindow;
79 static Window sWaitWindow;
80
81 static MATHRandContext32 sRand;
82
83 extern const unsigned char wlicon_image[];
84 extern const unsigned short wlicon_palette[];
85
86 static u16 ParentWEPKeyGenerator(u16 *wepkey, const WMParentParam *parentParam);
87 static u16 ChildWEPKeyGenerator(u16 *wepkey, const WMBssDesc *bssDesc);
88
TraceWH(const char * fmt,...)89 static void TraceWH(const char *fmt, ...)
90 {
91 va_list vlist;
92 va_start(vlist, fmt);
93 PR_VPrintString(&sDebugScreen, fmt, vlist);
94 va_end(vlist);
95 }
96
printString(const char * fmt,...)97 static void printString(const char *fmt, ...)
98 {
99 va_list vlist;
100 va_start(vlist, fmt);
101 PR_VPrintString(&sInfoScreen, fmt, vlist);
102 va_end(vlist);
103 }
104
isDataReceived(int index)105 BOOL isDataReceived(int index)
106 {
107 return sRecvFlag[index];
108 }
109
getRecvData(int index)110 ShareData *getRecvData(int index)
111 {
112 return (ShareData *) (&(sRecvBuf[index * sizeof(ShareData)]));
113 }
114
getSendData(void)115 ShareData *getSendData(void)
116 {
117 return (ShareData *) sSendBuf;
118 }
119
getInfoScreen(void)120 PRScreen *getInfoScreen(void)
121 {
122 return &sInfoScreen;
123 }
124
changeSysMode(int s)125 void changeSysMode(int s)
126 {
127 if (sSysMode == s)
128 {
129 return;
130 }
131
132 OS_Printf("sysmode = %d\n", s);
133 sSysMode = s;
134 sSysModeStep = 0;
135 }
136
indicateCallback(void * arg)137 static void indicateCallback(void *arg)
138 {
139 WMIndCallback *cb;
140 cb = (WMIndCallback *)arg;
141 if (cb->state == WM_STATECODE_BEACON_RECV)
142 {
143 sBeaconCount = 2;
144 }
145 }
146
scanCallback(WMBssDesc * bssdesc)147 static void scanCallback(WMBssDesc *bssdesc)
148 {
149 char buf[ITEM_LENGTH_MAX];
150 int i;
151
152 for (i = 0; i < sSelectParentWindow.itemnum; ++i)
153 {
154 if (memcmp(sBssDesc[i].bssid, bssdesc->bssid, 12) == 0)
155 {
156 // Parents with the same bssid are excluded on grounds of being an identical entry
157 return;
158 }
159 }
160
161 WH_PrintBssDesc(bssdesc);
162
163 // Save the information
164 sBssDesc[sSelectParentWindow.itemnum] = *bssdesc;
165
166 // Create the menu item for parent selection
167 (void)snprintf(buf,
168 ITEM_LENGTH_MAX,
169 "[%d]channel%d", sSelectParentWindow.itemnum + 1, bssdesc->channel);
170 addItemToWindow(&sSelectParentWindow, buf);
171 WH_PrintBssDesc(bssdesc);
172 }
173
forceSpinWait(void)174 static void forceSpinWait(void)
175 {
176 // Process to create the process failure state at will using OS_SpinWait
177 //
178
179 static int waitcycle = 0;
180
181 if (getKeyInfo()->cnt & PAD_BUTTON_L)
182 {
183 waitcycle += 4000;
184 // OS_Printf("wait = %d\n", waitcycle);
185
186 }
187 else if (getKeyInfo()->cnt & PAD_BUTTON_R)
188 {
189 waitcycle -= 4000;
190 if (waitcycle < 0)
191 {
192 waitcycle = 0;
193 }
194 // OS_Printf("wait = %d\n", waitcycle);
195 }
196
197 OS_SpinWait((u32)waitcycle);
198 }
199
ModeSelectRole(void)200 static void ModeSelectRole(void)
201 {
202 static const char *menuitems[] = {
203 "Start (Parent mode)",
204 "Start (Child mode)",
205 "Option",
206 NULL
207 };
208
209 if (sSysModeStep == 0)
210 {
211 sRoleMenuWindow.selected = 0;
212 setupWindow(&sRoleMenuWindow, 16, 16, WIN_FLAG_SELECTABLE, 24, 24, 16);
213 if (sRoleMenuWindow.itemnum == 0)
214 {
215 int i;
216 for (i = 0; menuitems[i] != NULL; ++i)
217 {
218 addItemToWindow(&sRoleMenuWindow, menuitems[i]);
219 }
220 }
221 openWindow(&sRoleMenuWindow);
222 }
223
224 if (sRoleMenuWindow.state == WIN_STATE_CLOSED)
225 {
226 if (sRoleMenuWindow.selected < 0)
227 {
228 openWindow(&sRoleMenuWindow);
229 return;
230 }
231
232 switch (sRoleMenuWindow.selected)
233 {
234 case 0:
235 // WH initialization
236 if (!WH_Initialize())
237 {
238 OS_Panic("WH_Initiailze failed.");
239 }
240 else
241 {
242 // Wait for initialization to complete
243 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
244 }
245
246 if (sForcedChannel == 0)
247 {
248 // Get the best channel based on the signal usage rate and connect.
249 (void)WH_StartMeasureChannel();
250
251 }
252 else
253 {
254 // Start the connection using the manually-selected channel
255 static u32 wepSeed;
256 wepSeed = MATH_Rand32(&sRand, 0);
257 // Embed the Seed value used in WEP calculations into UserGameInfo
258 WH_SetUserGameInfo((u16 *)&wepSeed, 4);
259 sTgid++;
260 (void)WH_ParentConnect(WH_CONNECTMODE_DS_PARENT, sTgid, sForcedChannel);
261 }
262 changeSysMode(SYSMODE_LOBBY);
263 break;
264
265 case 1:
266 // WH initialization
267 if (!WH_Initialize())
268 {
269 OS_Panic("WH_Initiailze failed.");
270 }
271 else
272 {
273 // Wait for initialization to complete
274 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
275 }
276
277 {
278 // Search for a parent
279 static const u8 ANY_PARENT[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
280 enum
281 { ALL_CHANNEL = 0 };
282
283 initWindow(&sSelectParentWindow);
284 setupWindow(&sSelectParentWindow, 16, 16, WIN_FLAG_SELECTABLE, 8, 8, 16);
285 (void)WH_StartScan(scanCallback, ANY_PARENT, ALL_CHANNEL);
286 changeSysMode(SYSMODE_SCAN_PARENT);
287 }
288 break;
289
290 case 2:
291 // To the option screen
292 changeSysMode(SYSMODE_OPTION);
293 break;
294
295 default:
296 break;
297 }
298 }
299 }
300
ModeOption(void)301 static void ModeOption(void)
302 {
303 // Option screen process
304
305 if (sSysModeStep == 0)
306 {
307 initWindow(&sOptionWindow);
308 setupWindow(&sOptionWindow, 16, 16, WIN_FLAG_SELECTABLE, 8, 8, 16);
309 addItemToWindow(&sOptionWindow, "Select channel (parent)");
310
311 if (sGraphEnabled)
312 {
313 addItemToWindow(&sOptionWindow, "Disable beacon graph");
314 }
315 else
316 {
317 addItemToWindow(&sOptionWindow, "Enable beacon graph");
318 }
319
320 openWindow(&sOptionWindow);
321 return;
322 }
323
324 if (sOptionWindow.state == WIN_STATE_CLOSED)
325 {
326 if (sOptionWindow.selected < 0)
327 {
328 // Cancelled
329 changeSysMode(SYSMODE_SELECT_ROLE);
330 return;
331 }
332
333 if (sOptionWindow.selected == 0)
334 {
335 // To the channel selection screen
336 changeSysMode(SYSMODE_SELECT_CHANNEL);
337
338 }
339 else if (sOptionWindow.selected == 1)
340 {
341 sGraphEnabled = sGraphEnabled ? FALSE : TRUE;
342 changeSysMode(SYSMODE_SELECT_ROLE);
343 }
344 }
345 }
346
ModeLobby(void)347 static void ModeLobby(void)
348 {
349 // Lobby screen process
350
351 u16 bmap;
352 int i;
353
354 if (sSysModeStep == 0)
355 {
356 initWindow(&sLobbyWindow);
357 setupWindow(&sLobbyWindow, 16, 16, WIN_FLAG_NONE, 8, 8, 16);
358
359 for (i = 0; i < WH_CHILD_MAX; ++i)
360 {
361 addItemToWindow(&sLobbyWindow, "");
362 }
363
364 addItemToWindow(&sLobbyWindow, "");
365 addItemToWindow(&sLobbyWindow, "Push A to start");
366
367 openWindow(&sLobbyWindow);
368 return;
369 }
370
371 bmap = WH_GetBitmap();
372 for (i = 0; i < WH_CHILD_MAX; ++i)
373 {
374 if (bmap & (1 << i))
375 {
376 (void)OS_SNPrintf(sLobbyWindow.item[i], ITEM_LENGTH_MAX, "[%02d] - entry", i);
377 }
378 else
379 {
380 (void)OS_SNPrintf(sLobbyWindow.item[i], ITEM_LENGTH_MAX, "[%02d] - waiting", i);
381 }
382 }
383
384 if (sLobbyWindow.state == WIN_STATE_CLOSED)
385 {
386 getSendData()->command = SHARECMD_NONE;
387 if (sLobbyWindow.selected < 0)
388 {
389 // WH shutdown
390 WH_Finalize();
391 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
392 (void)WH_End();
393 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
394
395 changeSysMode(SYSMODE_SELECT_ROLE);
396 return;
397 }
398
399 changeSysMode(SYSMODE_PARENT);
400 }
401 }
402
ModeLobbyWait(void)403 static void ModeLobbyWait(void)
404 {
405 // Process during child device lobby standby
406 // Wait until a parent sends a start signal
407
408 if (sSysModeStep == 0)
409 {
410 initWindow(&sWaitWindow);
411 setupWindow(&sWaitWindow, 32, 56, WIN_FLAG_NOCONTROL, 8, 8, 8);
412 addItemToWindow(&sWaitWindow, "\\2Accepted.");
413 addItemToWindow(&sWaitWindow, "\\2Waiting for parent...");
414 openWindow(&sWaitWindow);
415 return;
416 }
417
418 if (getRecvData(0)->command == SHARECMD_EXITLOBBY)
419 {
420 closeWindow(&sWaitWindow);
421 changeSysMode(SYSMODE_CHILD);
422 }
423 }
424
ModeSelectChannel(void)425 static void ModeSelectChannel(void)
426 {
427 static u16 channelList[15]; // Auto select + maximum 14 channels
428 // Channel selection screen
429 if (sSysModeStep == 0)
430 {
431 setupWindow(&sSelectChannelWindow, 16, 16, WIN_FLAG_SELECTABLE, 16, 12, 16);
432
433 if (sSelectChannelWindow.itemnum == 0)
434 {
435 u16 pattern;
436 int i, j;
437 for (i = 0; i < 14; i++)
438 {
439 channelList[i] = 0;
440 }
441
442 // WH initialization
443 if (!WH_Initialize())
444 {
445 OS_Panic("WH_Initiailze failed.");
446 }
447 else
448 {
449 // Wait for initialization to complete
450 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
451 }
452
453 pattern = WH_GetAllowedChannel();
454
455 // WH shutdown
456 WH_Finalize();
457 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
458 (void)WH_End();
459 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
460
461 addItemToWindow(&sSelectChannelWindow, "Auto select");
462 for (i = 1, j = 1; i <= 14; ++i)
463 {
464 if (pattern & (1 << (i - 1)))
465 {
466 char buf[ITEM_LENGTH_MAX];
467 (void)OS_SNPrintf(buf, ITEM_LENGTH_MAX, "Channel %d", i);
468 channelList[j] = (u16)i;
469 ++j;
470 addItemToWindow(&sSelectChannelWindow, buf);
471 }
472 }
473 }
474
475 openWindow(&sSelectChannelWindow);
476 }
477
478 if (sSelectChannelWindow.state == WIN_STATE_CLOSED)
479 {
480 if (sSelectChannelWindow.selected >= 0)
481 {
482 sForcedChannel = channelList[sSelectChannelWindow.selected];
483 }
484
485 // Return to the role selection screen
486 changeSysMode(SYSMODE_SELECT_ROLE);
487 }
488 }
489
ModeSelectParent(void)490 static void ModeSelectParent(void)
491 {
492 // Display parent on the list and select it.
493 // In this state, WH is scanning a parent, and if a new parent is found during scanning, it is immediately added/reflected to the menu.
494 //
495
496 if (WH_GetSystemState() == WH_SYSSTATE_CONNECT_FAIL)
497 {
498 // Because the internal WM state is invalid if the WM_StartConnect function fails, WM_Reset must be called once to reset the state to IDLE
499 //
500 WH_Reset();
501 return;
502 }
503
504 if (sSysModeStep == 0)
505 {
506 openWindow(&sSelectParentWindow);
507 }
508
509 // Did the user close the parent search screen?
510 if ((sSelectParentWindow.state == WIN_STATE_CLOSED))
511 {
512 if (WH_GetSystemState() == WH_SYSSTATE_SCANNING)
513 {
514 // If the parent is currently scanning, scan is finished for a moment
515 (void)WH_EndScan();
516 return;
517 }
518
519 if (WH_GetSystemState() == WH_SYSSTATE_IDLE)
520 {
521 if (sSelectParentWindow.selected < 0)
522 {
523 // WH shutdown
524 WH_Finalize();
525 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
526 (void)WH_End();
527 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
528
529 changeSysMode(SYSMODE_SELECT_ROLE);
530 return;
531 }
532
533 // If not scanning, and if the user has selected a parent, data sharing starts
534 (void)WH_ChildConnect(WH_CONNECTMODE_DS_CHILD,
535 &(sBssDesc[sSelectParentWindow.selected]));
536 changeSysMode(SYSMODE_LOBBYWAIT);
537 }
538 }
539 }
540
ModeError(void)541 static void ModeError(void)
542 {
543 // Error state
544 if (sSysModeStep == 0)
545 {
546 initWindow(&sErrorWindow);
547 setupWindow(&sErrorWindow, 16, 16, WIN_FLAG_NONE, 8, 8, 16);
548
549 addItemToWindow(&sErrorWindow, "\\1Error has occured!");
550
551 if (WH_GetLastError() == WM_ERRCODE_OVER_MAX_ENTRY)
552 {
553 addItemToWindow(&sErrorWindow, "\\4Rejected\n");
554 }
555
556 if (WH_GetLastError() == WH_ERRCODE_DISCONNECTED)
557 {
558 addItemToWindow(&sErrorWindow, "\\4Disconnected by parent\n");
559 }
560
561 if (WH_GetLastError() == WH_ERRCODE_PARENT_NOT_FOUND)
562 {
563 addItemToWindow(&sErrorWindow, "\\4Parent not found\n");
564 }
565
566 if (WH_GetLastError() == WH_ERRCODE_LOST_PARENT)
567 {
568 addItemToWindow(&sErrorWindow, "\\4Lost parent\n");
569 }
570
571 addItemToWindow(&sErrorWindow, "");
572 addItemToWindow(&sErrorWindow, "\\fPush A to reset");
573
574 closeAllWindow();
575 openWindow(&sErrorWindow);
576 }
577
578 if (sErrorWindow.state == WIN_STATE_CLOSED)
579 {
580 // WH shutdown
581 WH_Finalize();
582 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
583 (void)WH_End();
584 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
585
586 getRecvData(0)->command = SHARECMD_NONE;
587 changeSysMode(SYSMODE_SELECT_ROLE);
588 }
589 }
590
printShareData(void)591 static void printShareData(void)
592 {
593 s32 i;
594 ShareData *sd;
595
596 sd = getSendData();
597 printString("\\2Send: 0x%04x 0x%04x\n", sd->key, sd->count & 0xffff);
598
599 printString("\\4Receive:\n");
600 for (i = 1; i < (WM_NUM_MAX_CHILD + 1); i++)
601 {
602 if (sRecvFlag[i])
603 {
604 sd = getRecvData(i);
605 printString("\\4Child%02d: 0x%04x 0x%04x\n", i, sd->key, sd->count & 0xffff);
606
607 }
608 else
609 {
610 printString("No child\n");
611 }
612 }
613 }
614
ModeParent(void)615 static void ModeParent(void)
616 {
617 printString("\n \\fParent mode\n\n");
618 printShareData();
619 }
620
ModeChild(void)621 static void ModeChild(void)
622 {
623 ShareData *sd;
624
625 printString("\n \\fChild mode\n\n");
626 printShareData();
627
628 sd = (ShareData *) getRecvData(0);
629 printString("\\4Parent: 0x%04x 0x%04x\n", sd->key, sd->count & 0xffff);
630 }
631
VBlankIntr(void)632 static void VBlankIntr(void)
633 {
634 /*
635 Some other samples use StepDataSharing here (the VBlankIntr function).
636 This sample also performed StepDataSharing here before.
637
638
639 It is this way because WM_StepDataSharing (and WM_GetKeySet) have to be called before the start of MP communications in a frame for communications to be stable.
640 Because the V-Count when the SDK prepares for the default MP communication is 240 for a child and 260 for a parent, setting it immediately after a V-Blank starts presents the fewest problems. (Although not implemented at the time this document was written, it is planned to make it possible to specify, during initialization, the V-Count of the MP communications startup.)
641
642 For 30-fps (and other) games, code is normally required to limit the number of StepDS calls to one every two frames.
643 In that case, wait only a single frame (instead of two) when WM_ERRCODE_NO_DATASET is returned (if processing was lost).
644 Otherwise, when there is one frame difference between the parent and child, it cannot be corrected.
645
646
647
648
649
650
651
652 */
653
654 updateKeys();
655 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
656 }
657
initAllocSystem(void)658 static void initAllocSystem(void)
659 {
660 void *tempLo;
661 OSHeapHandle hh;
662
663 tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
664 OS_SetArenaLo(OS_ARENA_MAIN, tempLo);
665 hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
666 if (hh < 0)
667 {
668 OS_Panic("ARM9: Fail to create heap...\n");
669 }
670 hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
671 }
672
drawPowerGraph(void)673 static void drawPowerGraph(void)
674 {
675 static const GXRgb linecolor[4] = {
676 GX_RGB(15, 0, 0), // Dark red (dead)
677 GX_RGB(31, 31, 0), // Yellow
678 GX_RGB(0, 31, 0), // Green
679 GX_RGB(20, 31, 20), // Light green
680 };
681
682 int midx, ringidx;
683
684 ringidx = (sFrame % GRAPH_TOTAL_FRAME);
685
686 for (midx = 0; midx < WM_NUM_MAX_CHILD + 1; ++midx)
687 {
688 sGraphData[midx][ringidx].data = (s16)getRecvData(midx)->data;
689 sGraphData[midx][ringidx].level = (u16)getRecvData(midx)->level;
690 }
691
692 G3_PolygonAttr(GX_LIGHTMASK_NONE,
693 GX_POLYGONMODE_MODULATE, GX_CULL_NONE, 0, 31, GX_POLYGON_ATTR_MISC_DISP_1DOT);
694 G3_TexImageParam(GX_TEXFMT_NONE,
695 GX_TEXGEN_NONE,
696 GX_TEXSIZE_S16,
697 GX_TEXSIZE_T16, GX_TEXREPEAT_NONE, GX_TEXFLIP_NONE, GX_TEXPLTTCOLOR0_USE, 0);
698
699 G3_MtxMode(GX_MTXMODE_POSITION_VECTOR);
700 G3_PushMtx();
701 G3_Identity();
702 G3_Translate(0, 0, -FX16_ONE * 4);
703
704 G3_Begin(GX_BEGIN_TRIANGLES);
705
706 for (midx = 1; midx < WM_NUM_MAX_CHILD + 1; ++midx)
707 {
708 int basey, ys, ye, gi, x, level;
709 basey = ((WM_NUM_MAX_CHILD / 2 - midx) * 9 + 6) * FX16_ONE / 64;
710
711 for (gi = 0; gi < GRAPH_TOTAL_FRAME; ++gi)
712 {
713 int ri;
714 ri = (ringidx - gi);
715 if (ri < 0)
716 {
717 ri += GRAPH_TOTAL_FRAME;
718 }
719
720 ys = sGraphData[midx][ri].data;
721 level = sGraphData[midx][ri].level;
722
723 ++ri;
724 if (ri >= GRAPH_TOTAL_FRAME)
725 {
726 ri -= GRAPH_TOTAL_FRAME;
727 }
728
729 ye = sGraphData[midx][ri].data;
730
731 x = -(gi - GRAPH_TOTAL_FRAME / 2) * 3;
732 x *= FX16_ONE / 64;
733 ys = ys * FX16_ONE / 64 + basey;
734 ye = ye * FX16_ONE / 64 + basey;
735
736 G3_Color(linecolor[level]);
737
738 G3_Vtx((fx16)x, (fx16)ys, 0);
739 G3_Vtx((fx16)(x + FX16_ONE / 64 / 2), (fx16)(ys + FX16_ONE / 64), 0);
740 G3_Vtx((fx16)(x + 3 * FX16_ONE / 64), (fx16)ye, 0);
741 }
742 }
743
744 G3_End();
745 G3_PopMtx(1);
746 }
747
drawPowerIcon(void)748 static void drawPowerIcon(void)
749 {
750 // GUIDELINE
751 // Display the signal reception strength icon.
752 setupPseudo2DCamera();
753
754 G3_PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGONMODE_DECAL, GX_CULL_NONE, 0, 31, 0);
755
756 G3_TexImageParam(GX_TEXFMT_PLTT16,
757 GX_TEXGEN_TEXCOORD,
758 GX_TEXSIZE_S16,
759 GX_TEXSIZE_T16,
760 GX_TEXREPEAT_NONE,
761 GX_TEXFLIP_NONE,
762 GX_TEXPLTTCOLOR0_USE, (u32)(0x2000 + WM_GetLinkLevel() * 16 * 16 / 2));
763 G3_TexPlttBase(0x2000, GX_TEXFMT_PLTT16);
764 G3_MtxMode(GX_MTXMODE_POSITION_VECTOR);
765 drawPseudo2DTexQuad(224, 160, 16, 16, 16, 16);
766 }
767
drawRadioIcon(void)768 static void drawRadioIcon(void)
769 {
770 // GUIDELINE
771 // Display the sending-a-signal icon.
772 int i;
773
774 G3_PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGONMODE_DECAL, GX_CULL_NONE, 0, 31, 0);
775
776 G3_TexPlttBase(0x2000, GX_TEXFMT_PLTT16);
777 G3_TexImageParam(GX_TEXFMT_PLTT16,
778 GX_TEXGEN_TEXCOORD,
779 GX_TEXSIZE_S16,
780 GX_TEXSIZE_T16,
781 GX_TEXREPEAT_NONE,
782 GX_TEXFLIP_NONE, GX_TEXPLTTCOLOR0_USE, 0x2000 + 4 * 16 * 16 / 2);
783
784 for (i = 0; i < 2; ++i)
785 {
786 drawPseudo2DTexQuad(16,
787 12 + i * 24 + ((i == sRoleMenuWindow.selected) ? (sFrame / 15 & 1) : 0),
788 16, 16, 16, 16);
789 }
790 }
791
updateShareData(void)792 static void updateShareData(void)
793 {
794 if (WH_GetSystemState() == WH_SYSSTATE_DATASHARING)
795 {
796 if (WH_StepDS(sSendBuf))
797 {
798 u16 i;
799 for (i = 0; i < WM_NUM_MAX_CHILD + 1; ++i)
800 {
801 u8 *adr;
802 ShareData *sd;
803
804 adr = (u8 *)WH_GetSharedDataAdr(i);
805 sd = (ShareData *) & (sRecvBuf[i * sizeof(ShareData)]);
806
807 if (adr != NULL)
808 {
809 MI_CpuCopy8(adr, sd, sizeof(ShareData));
810 sRecvFlag[i] = TRUE;
811
812 }
813 else
814 {
815 sd->level = 0;
816 sd->data = 0;
817 sRecvFlag[i] = FALSE;
818 }
819 }
820
821 sNeedWait = FALSE;
822
823 }
824 else
825 {
826 u16 i;
827 for (i = 0; i < WM_NUM_MAX_CHILD + 1; ++i)
828 {
829 sRecvFlag[i] = FALSE;
830 }
831
832 sNeedWait = TRUE;
833 }
834
835 }
836 else
837 {
838 u16 i;
839 for (i = 0; i < WM_NUM_MAX_CHILD + 1; ++i)
840 {
841 sRecvFlag[i] = FALSE;
842 }
843
844 sNeedWait = FALSE;
845 }
846 }
847
packSendData(void)848 static void packSendData(void)
849 {
850 ShareData *senddata;
851
852 if (sNeedWait)
853 {
854 return;
855 }
856
857 senddata = getSendData();
858 senddata->command = (sSysMode == SYSMODE_LOBBY) ? SHARECMD_NONE : SHARECMD_EXITLOBBY;
859
860 senddata->level = (u16)WM_GetLinkLevel();
861
862 senddata->data = 0;
863 senddata->key = getKeyInfo()->cnt;
864 senddata->count = sFrame & 0xffff;
865
866 if (sBeaconCount != 0)
867 {
868 senddata->data += sBeaconCount * senddata->level;
869
870 if (sBeaconCount > 0)
871 {
872 sBeaconCount = -sBeaconCount + 1;
873 }
874 else
875 {
876 sBeaconCount = -sBeaconCount - 1;
877 }
878 }
879 }
880
mainLoop(void)881 static void mainLoop(void)
882 {
883 int retry = 0;
884 enum {
885 MAX_RETRY = 5
886 };
887
888 for (sFrame = 0; TRUE; sFrame++)
889 {
890 int whstate;
891 int prevmode;
892
893 whstate = WH_GetSystemState();
894 prevmode = sSysMode;
895
896 switch (whstate)
897 {
898 case WH_SYSSTATE_CONNECT_FAIL:
899 // Retry several times when a connection fails
900 if (sSysMode == SYSMODE_LOBBYWAIT && retry < MAX_RETRY)
901 {
902 changeSysMode(SYSMODE_SELECT_PARENT);
903 sSysModeStep = 1; // Make it so that 'window' will not open
904 retry++;
905 break;
906 }
907 // When a retry fails, transition unchanged to the error state
908
909 case WH_SYSSTATE_ERROR:
910 // WH state has the priority if an error occurred
911 changeSysMode(SYSMODE_ERROR);
912 break;
913
914 case WH_SYSSTATE_MEASURECHANNEL:
915 {
916 u16 channel = WH_GetMeasureChannel();
917 static u32 wepSeed;
918 wepSeed = MATH_Rand32(&sRand, 0);
919 // Embed the Seed value used in WEP calculations into UserGameInfo
920 WH_SetUserGameInfo((u16 *)&wepSeed, 4);
921 sTgid++;
922 (void)WH_ParentConnect(WH_CONNECTMODE_DS_PARENT, sTgid, channel);
923 }
924 break;
925
926 default:
927 break;
928 }
929
930 PR_ClearScreen(&sInfoScreen);
931
932 // Load test
933 forceSpinWait();
934
935 switch (sSysMode)
936 {
937 case SYSMODE_SELECT_ROLE:
938 // Role (parent or child) selection screen
939 ModeSelectRole();
940 retry = 0;
941 break;
942
943 case SYSMODE_SELECT_CHANNEL:
944 // Channel selection screen
945 ModeSelectChannel();
946 break;
947
948 case SYSMODE_LOBBY:
949 // Lobby screen
950 ModeLobby();
951 break;
952
953 case SYSMODE_LOBBYWAIT:
954 // Lobby standby screen
955 ModeLobbyWait();
956 break;
957
958 case SYSMODE_OPTION:
959 // Option screen
960 ModeOption();
961 break;
962
963 case SYSMODE_SCAN_PARENT:
964 case SYSMODE_SELECT_PARENT:
965 // Parent selection screen
966 ModeSelectParent();
967 break;
968
969 case SYSMODE_ERROR:
970 // Error report screen
971 ModeError();
972 break;
973
974 case SYSMODE_PARENT:
975 // Parent mode screen
976 ModeParent();
977 break;
978
979 case SYSMODE_CHILD:
980 // Child mode screen
981 ModeChild();
982 break;
983
984 default:
985 break;
986 }
987
988 if ((whstate == WH_SYSSTATE_BUSY)
989 || ((whstate == WH_SYSSTATE_SCANNING) && (sSelectParentWindow.itemnum == 0)))
990 {
991 sBusyWindow.state = WIN_STATE_OPENED;
992
993 }
994 else
995 {
996 sBusyWindow.state = WIN_STATE_CLOSED;
997 }
998
999 updateAllWindow();
1000 drawAllWindow();
1001
1002 if( (sSysMode != SYSMODE_SELECT_ROLE) && (sSysMode != SYSMODE_OPTION) && (sSysMode != SYSMODE_SELECT_CHANNEL) )
1003 {
1004 drawPowerIcon();
1005 }
1006
1007 if ((sSysMode == SYSMODE_PARENT) || (sSysMode == SYSMODE_CHILD))
1008 {
1009 if (sGraphEnabled)
1010 {
1011 drawPowerGraph();
1012 }
1013 }
1014
1015 if ((sSysMode == SYSMODE_SELECT_ROLE) && (sRoleMenuWindow.state == WIN_STATE_OPENED))
1016 {
1017 drawRadioIcon();
1018 }
1019
1020 G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
1021
1022 if (!sNeedWait && ((sSysMode == SYSMODE_PARENT) || (sSysMode == SYSMODE_CHILD)))
1023 {
1024 // ... In an actual game, the update processing for characters and so on is performed here
1025 //
1026 }
1027
1028 DC_FlushRange(sInfoScreen.screen, sizeof(u16) * PR_SCREEN_SIZE);
1029 /* I/O register is accessed using DMA operation, so cache wait is not needed */
1030
1031 // DC_WaitWriteBufferEmpty();
1032 GX_LoadBG2Scr(sInfoScreen.screen, 0, sizeof(u16) * PR_SCREEN_SIZE);
1033 DC_FlushRange(sDebugScreen.screen, sizeof(u16) * PR_SCREEN_SIZE);
1034 /* I/O register is accessed using DMA operation, so cache wait is not needed */
1035
1036 // DC_WaitWriteBufferEmpty();
1037 GXS_LoadBG2Scr(sDebugScreen.screen, 0, sizeof(u16) * PR_SCREEN_SIZE);
1038
1039 OS_WaitVBlankIntr();
1040
1041 packSendData();
1042 updateShareData();
1043
1044 if (prevmode == sSysMode)
1045 {
1046 ++sSysModeStep;
1047 }
1048 }
1049 }
1050
1051 #ifdef SDK_TWL
TwlMain(void)1052 void TwlMain(void)
1053 #else
1054 void NitroMain(void)
1055 #endif
1056 {
1057 OS_Init();
1058 FX_Init();
1059 RTC_Init();
1060
1061 initGraphics();
1062
1063 GX_SetBankForBG(GX_VRAM_BG_256_AB);
1064 GX_SetBankForBGExtPltt(GX_VRAM_BGEXTPLTT_01_F);
1065 G2_SetBG2ControlText(GX_BG_SCRSIZE_TEXT_256x256,
1066 GX_BG_COLORMODE_16, GX_BG_SCRBASE_0x0000, GX_BG_CHARBASE_0x04000);
1067
1068 GX_BeginLoadTex();
1069 GX_LoadTex(wlicon_image, 0x2000, 16 * 16 * 5);
1070 GX_EndLoadTex();
1071
1072 GX_BeginLoadTexPltt();
1073 GX_LoadTexPltt(wlicon_palette, 0x2000, 32);
1074 GX_EndLoadTexPltt();
1075
1076 GX_LoadBG2Char(d_CharData, 0, sizeof(d_CharData));
1077 GX_LoadBGPltt(d_PaletteData, 0, sizeof(d_PaletteData));
1078
1079 GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C);
1080 GX_SetBankForSubBGExtPltt(GX_VRAM_SUB_BGEXTPLTT_0123_H);
1081 G2S_SetBG2ControlText(GX_BG_SCRSIZE_TEXT_256x256,
1082 GX_BG_COLORMODE_16, GX_BG_SCRBASE_0x0000, GX_BG_CHARBASE_0x00000);
1083
1084 GXS_SetGraphicsMode(GX_BGMODE_0);
1085 GXS_SetVisiblePlane(GX_PLANEMASK_BG2);
1086 G2S_SetBG2Priority(0);
1087 G2S_BG2Mosaic(FALSE);
1088
1089 GXS_LoadBG2Char(d_CharData, 0, sizeof(d_CharData));
1090 GXS_LoadBGPltt(d_PaletteData, 0, sizeof(d_PaletteData));
1091
1092 initAllocSystem();
1093
1094 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
1095 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
1096 (void)GX_VBlankIntr(TRUE);
1097 (void)OS_EnableIrq();
1098 (void)OS_EnableInterrupts();
1099
1100 sInfoScreen.scroll = FALSE;
1101 sDebugScreen.scroll = TRUE;
1102
1103 // Initialize wireless
1104 // Set callback specified in the WM_SetIndCallback called within wh
1105 WH_SetIndCallback(indicateCallback);
1106
1107 // WH initialization settings
1108 WH_SetGgid(WH_GGID);
1109 WH_SetDebugOutput(TraceWH);
1110
1111 // WEP Key Generator configuration
1112 WH_SetParentWEPKeyGenerator(ParentWEPKeyGenerator);
1113 WH_SetChildWEPKeyGenerator(ChildWEPKeyGenerator);
1114
1115 // Initialize random number generator for WEP Key seed
1116 {
1117 u64 randSeed = 0;
1118 RTCDate date;
1119 RTCTime time;
1120 if (RTC_GetDateTime(&date, &time) == RTC_RESULT_SUCCESS)
1121 {
1122 randSeed =
1123 (((((((u64)date.year * 16ULL + date.month) * 32ULL) + date.day) * 32ULL +
1124 time.hour) * 64ULL + time.minute) * 64ULL + time.second);
1125 }
1126 MATH_InitRand32(&sRand, randSeed);
1127 }
1128
1129 GX_DispOn();
1130 GXS_DispOn();
1131
1132 initWindow(&sRoleMenuWindow);
1133 initWindow(&sSelectChannelWindow);
1134 initWindow(&sSelectParentWindow);
1135 initWindow(&sLobbyWindow);
1136 initWindow(&sErrorWindow);
1137 initWindow(&sOptionWindow);
1138 initWindow(&sWaitWindow);
1139 initWindow(&sBusyWindow);
1140
1141 setupWindow(&sBusyWindow, 64, 80, WIN_FLAG_NOCONTROL, 8, 8, 16);
1142 addItemToWindow(&sBusyWindow, "\\2Working...");
1143
1144 // Countermeasure for pressing A Button in IPL
1145 updateKeys();
1146
1147 // initCharacter();
1148 changeSysMode(SYSMODE_SELECT_ROLE);
1149 mainLoop();
1150 }
1151
1152 // Common key used to generate WEP key (parent and child use the same key)
1153 // It should be unique for each application
1154 // Does not have to be an ASCII char string; can be binary data of any length
1155 static char *sSecretKey = "this is a secret key for HMAC";
1156 static u32 sSecretKeyLength = 30; // Ideally, the key should be more than 20 bytes
1157
1158 // Calculation routine for parent's WEP key
ParentWEPKeyGenerator(u16 * wepkey,const WMParentParam * parentParam)1159 u16 ParentWEPKeyGenerator(u16 *wepkey, const WMParentParam *parentParam)
1160 {
1161 u16 data[20 / sizeof(u16)];
1162 u16 tmpWep[20 / sizeof(u16)];
1163 u8 macAddress[WM_SIZE_MACADDR];
1164
1165 OS_GetMacAddress(macAddress);
1166 MI_CpuClear16(data, sizeof(data));
1167
1168 // Right before the WH_ParentConnect function, apply the Seed value set earlier in UserGameInfo to the WEP Key, using the WH_SetUserGameInfo function
1169 //
1170 MI_CpuCopy16(parentParam->userGameInfo, data, 4);
1171 // To allow the same algorithm to be used in different applications, also reflect the GGID in the WEP key
1172 //
1173 MI_CpuCopy16(&parentParam->ggid, data + 2, sizeof(u32));
1174 *(u16 *)(data + 4) = parentParam->tgid;
1175 // Also reflect the MAC Address in the WEP Key so that different parents will have different WEP keys
1176 MI_CpuCopy8(macAddress, (u8 *)(data + 5), WM_SIZE_MACADDR);
1177
1178 // A keyed hash value is taken with HMAC-SHA-1 and is reduced to 128 bits to create the WEP key.
1179 // The key used with HMAC should be unique for each application.
1180 // (For details on HMAC, see RFC2104)
1181 MATH_CalcHMACSHA1(tmpWep, data, sizeof(data), sSecretKey, sSecretKeyLength);
1182 MI_CpuCopy8(tmpWep, wepkey, 16);
1183 OS_TPrintf("wepkey: %04x%04x %04x%04x %04x%04x %04x%04x\n", wepkey[0], wepkey[1],
1184 wepkey[2], wepkey[3], wepkey[4], wepkey[5], wepkey[6], wepkey[7]);
1185
1186 return WM_WEPMODE_128BIT;
1187 }
1188
1189 // Calculation routine for child's WEP key
ChildWEPKeyGenerator(u16 * wepkey,const WMBssDesc * bssDesc)1190 u16 ChildWEPKeyGenerator(u16 *wepkey, const WMBssDesc *bssDesc)
1191 {
1192 u16 data[20 / sizeof(u16)];
1193 u16 tmpWep[20 / sizeof(u16)];
1194
1195 MI_CpuClear16(data, sizeof(data));
1196
1197 // Calculate WEP key using the seed value embedded in UserGameInfo
1198 MI_CpuCopy16(bssDesc->gameInfo.userGameInfo, data, 4);
1199 // Include consideration of the GGID, TGID, and the MAC Address of the parent
1200 MI_CpuCopy16(&bssDesc->gameInfo.ggid, data + 2, sizeof(u32));
1201 *(u16 *)(data + 4) = bssDesc->gameInfo.tgid;
1202 MI_CpuCopy8(bssDesc->bssid, (u8 *)(data + 5), WM_SIZE_MACADDR);
1203
1204 // A keyed hash value is taken with HMAC-SHA-1 and is reduced to 128 bits to create the WEP key.
1205 // The key used with HMAC should be unique for each application.
1206 // (For details on HMAC, see RFC2104)
1207 MATH_CalcHMACSHA1(tmpWep, data, sizeof(data), sSecretKey, sSecretKeyLength);
1208 MI_CpuCopy8(tmpWep, wepkey, 16);
1209 OS_TPrintf("wepkey: %04x%04x %04x%04x %04x%04x %04x%04x\n", wepkey[0], wepkey[1],
1210 wepkey[2], wepkey[3], wepkey[4], wepkey[5], wepkey[6], wepkey[7]);
1211
1212 return WM_WEPMODE_128BIT;
1213 }
1214