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