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