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