1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MB - demos - multiboot-Model
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-01-14#$
14   $Rev: 9840 $
15   $Author: nishimoto_takashi $
16  *---------------------------------------------------------------------------*/
17 
18 #include <nitro.h>
19 #include <nitro/wm.h>
20 #include <nitro/mb.h>
21 
22 #include "common.h"
23 #include "disp.h"
24 #include "gmain.h"
25 #include "wh.h"
26 
27 //============================================================================
28 //  Prototype Declarations
29 //============================================================================
30 
31 static void ModeConnect(void);         // Begins a connection to a parent device
32 static void ModeError(void);           // Error display screen
33 static void ModeWorking(void);         // Busy screen
34 static void ChildReceiveCallback(WMmpRecvBuf *data);
35 
36 
37 //============================================================================
38 //  Variable Definitions
39 //============================================================================
40 
41 static s32 gFrame;                     // Frame counter
42 
43 static WMBssDesc gMBParentBssDesc ATTRIBUTE_ALIGN(32);
44 
45 //============================================================================
46 //  Function Definitions
47 //============================================================================
48 
49 /*---------------------------------------------------------------------------*
50   Name:         NitroMain
51 
52   Description:  Child main routine.
53 
54   Arguments:    None.
55 
56   Returns:      None.
57  *---------------------------------------------------------------------------*/
NitroMain(void)58 void NitroMain(void)
59 {
60 
61     // Initialize screen, OS
62     CommonInit();
63 
64     // This child checks to see if it is a child started from multiboot
65     if (!MB_IsMultiBootChild())
66     {
67         OS_Panic("not found Multiboot child flag!\n");
68     }
69 
70     //--------------------------------------------------------------
71     // If it was started from multi-boot, it will be reset once, and communication will be disconnected.
72     // The child maintains the BssDesc of the parent that booted it. Use this information to reconnect to the parent.
73     //
74     // There is no particular problem with extracting the MAC address from BssDesc, then specifying that MAC address and scanning for and connecting to that parent. However, to connect to the parent directly using the stored BssDesc, it is necessary to set the parent's and child's communications size and transfer mode to match ahead of time.
75     //
76     //
77     //
78     //--------------------------------------------------------------
79 
80     /*
81      * Gets parent data for reconnecting to the parent.
82      * The WMBssDesc used for the connection must be 32-byte aligned.
83      * When reconnecting without using the parent's MAC address to rescan, make the KS/CS flags and the maximum send size match in advance for the parent and the child.
84      *
85      * All of these values may be 0 if you rescan before connecting.
86      */
87     MB_ReadMultiBootParentBssDesc(&gMBParentBssDesc, WH_PARENT_MAX_SIZE,        // Maximum parent send size
88                                   WH_CHILD_MAX_SIZE,    // Maximum child send size
89                                   0,   // Key sharing flag
90                                   0);  // Continuous transfer mode flag
91 
92     // When connecting without rescanning the parent, the tgid on the parent and child must match.
93     //
94     // In order to avoid connections from an unrelated IPL, it is necessary to change the tgid of the parent after the parent is restarted, along with the tgid of the child.
95     //
96     // In this demo, the parent and child are both incremented by 1.
97     gMBParentBssDesc.gameInfo.tgid++;
98 
99     // Initialize screen
100     DispInit();
101     // Initialize the heap
102     InitAllocateSystem();
103 
104     // Enable interrupts
105     (void)OS_EnableIrq();
106     (void)OS_EnableInterrupts();
107 
108     GInitDataShare();
109 
110     //********************************
111     // Initialize wireless
112     if(!WH_Initialize())
113     {
114         OS_Panic("WH_Initialize failed.");
115     }
116     //********************************
117 
118     // LCD display start
119     GX_DispOn();
120     GXS_DispOn();
121 
122     // Debug string output
123     OS_TPrintf("MB child: Simple DataSharing demo started.\n");
124 
125     // Empty call for getting key input data (strategy for pressing A button in the IPL)
126     ReadKey();
127 
128     // Main loop
129     for (gFrame = 0; TRUE; gFrame++)
130     {
131         // Get key input data
132         ReadKey();
133 
134         // Clear the screen
135         BgClear();
136 
137         // Distributes processes based on communication status
138         switch (WH_GetSystemState())
139         {
140         case WH_SYSSTATE_CONNECT_FAIL:
141             {
142                 // If WM_StartConnect fails, the WM internal state is invalid. Use WM_Reset to reset the state to the IDLE state.
143                 //
144                 WH_Reset();
145             }
146             break;
147         case WH_SYSSTATE_IDLE:
148             {
149                 static  retry = 0;
150                 enum
151                 {
152                     MAX_RETRY = 5
153                 };
154 
155                 if (retry < MAX_RETRY)
156                 {
157                     ModeConnect();
158                     retry++;
159                     break;
160                 }
161                 // If connection to parent is not possible after MAX_RETRY, display ERROR
162             }
163         case WH_SYSSTATE_ERROR:
164             ModeError();
165             break;
166         case WH_SYSSTATE_BUSY:
167         case WH_SYSSTATE_SCANNING:
168             ModeWorking();
169             break;
170 
171         case WH_SYSSTATE_CONNECTED:
172         case WH_SYSSTATE_KEYSHARING:
173         case WH_SYSSTATE_DATASHARING:
174             {
175                 BgPutString(8, 1, 0x2, "Child mode");
176                 GStepDataShare(gFrame);
177                 GMain();
178             }
179             break;
180         }
181 
182         // Display of signal strength
183         {
184             int     level;
185             level = WH_GetLinkLevel();
186             BgPrintStr(31, 23, 0xf, "%d", level);
187         }
188 
189         // Waiting for the V-Blank
190         OS_WaitVBlankIntr();
191     }
192 }
193 
194 /*---------------------------------------------------------------------------*
195   Name:         ModeConnect
196 
197   Description:  Connection start.
198 
199   Arguments:    None.
200 
201   Returns:      None.
202  *---------------------------------------------------------------------------*/
ModeConnect(void)203 static void ModeConnect(void)
204 {
205 //#define USE_DIRECT_CONNECT
206 
207     // When connecting directly without parent rescan
208 #ifdef USE_DIRECT_CONNECT
209     //********************************
210     (void)WH_ChildConnect(WH_CONNECTMODE_DS_CHILD, &gMBParentBssDesc);
211     // WH_ChildConnect(WH_CONNECTMODE_MP_CHILD, &gMBParentBssDesc, TRUE);
212     // WH_ChildConnect(WH_CONNECTMODE_KS_CHILD, &gMBParentBssDesc, TRUE);
213     //********************************
214 #else
215     WH_SetGgid(gMBParentBssDesc.gameInfo.ggid);
216     // When performing rescanning of the parent device
217     //********************************
218     (void)WH_ChildConnectAuto(WH_CONNECTMODE_DS_CHILD, gMBParentBssDesc.bssid,
219                               gMBParentBssDesc.channel);
220     // WH_ChildConnect(WH_CONNECTMODE_MP_CHILD, &gMBParentBssDesc, TRUE);
221     // WH_ChildConnect(WH_CONNECTMODE_KS_CHILD, &gMBParentBssDesc, TRUE);
222     //********************************
223 #endif
224 }
225 
226 /*---------------------------------------------------------------------------*
227   Name:         ModeError
228 
229   Description:  Displays error notification screen.
230 
231   Arguments:    None.
232 
233   Returns:      None.
234  *---------------------------------------------------------------------------*/
ModeError(void)235 static void ModeError(void)
236 {
237     static int over_max_entry_count = 0;
238 
239     if (WH_GetLastError() == WM_ERRCODE_OVER_MAX_ENTRY)
240     {
241         // Considering the possibility of another download child having connected to the parent while reconnecting to the parent, retry the connection several times.
242         //
243         // If the retry fails, it is really OVER_MAX_ENTRY.
244         if (over_max_entry_count < 10)
245         {
246             WH_Reset();
247 
248             while (WH_GetSystemState() != WH_SYSSTATE_IDLE)
249             {
250                 OS_WaitVBlankIntr();
251             }
252             {
253                 // If not scanning, and if the user has selected a parent, data sharing starts
254                 ModeConnect();
255 
256                 over_max_entry_count++;
257             }
258             return;
259         }
260         else
261         {
262             BgPrintStr(5, 13, 0xf, "OVER_MAX_ENTRY");
263         }
264     }
265 
266     BgPrintStr(5, 10, 0x1, "======= ERROR! =======");
267 }
268 
269 /*---------------------------------------------------------------------------*
270   Name:         ModeWorking
271 
272   Description:  Displays working screen
273 
274   Arguments:    None.
275 
276   Returns:      None.
277  *---------------------------------------------------------------------------*/
ModeWorking(void)278 static void ModeWorking(void)
279 {
280     BgPrintStr(9, 11, 0xf, "Now working...");
281 
282     if (IS_PAD_TRIGGER(PAD_BUTTON_START))
283     {
284         //********************************
285         (void)WH_Finalize();
286         //********************************
287     }
288 }
289