1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - CHT - demos - wmscan
3 File: chtmin.c
4
5 Copyright 2003-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 #include <nitro.h>
18 #include "wmscan.h"
19
20 // TODO: Not currently supported because the CHT library has not yet been implemented.
21 //#define TWL_SUPPORT_CHT
22 #if defined(TWL_SUPPORT_CHT)
23 #include <nitro/cht.h>
24 #endif
25
26 static int sSysState = WS_SYSSTATE_STOP; // wmscan internal state
27 static WSStartScanCallbackFunc sScanCallback = NULL; // Callback pointer when parent is discovered
28 static WMBssDesc sBssDesc ATTRIBUTE_ALIGN(32); // Buffer to obtain parent data
29 static WMScanParam sScanParam ATTRIBUTE_ALIGN(32); // Scan parameter structure
30 static BOOL sContinuousScanFlag; // Continuous scan flag
31 static BOOL sPictoCatchFlag = FALSE; // PictoCatch flag
32 static u32 sGgid = 0; // GGID
33
34 #define WS_ASSERT(exp) \
35 (void) ((exp) || (OSi_Panic(__FILE__, __LINE__, "Failed assertion " #exp), 0))
36
37 static void WS_ChangeSysState(int state);
38 static void WS_StateOutInitialize(void *arg);
39 static BOOL WS_StateInStartScan(void);
40 static void WS_StateOutStartScan(void *arg);
41 static BOOL WS_StateInEndScan(void);
42 static void WS_StateOutEndScan(void *arg);
43 static void WS_StateOutEnd(void *arg);
44
45
46 /*---------------------------------------------------------------------------*
47 Name: WS_ChangeSysState
48 Description: Changes the WS status.
49 Arguments: None.
50 Returns: None.
51 *---------------------------------------------------------------------------*/
WS_ChangeSysState(int state)52 static inline void WS_ChangeSysState(int state)
53 {
54 sSysState = state;
55 }
56
57 /*---------------------------------------------------------------------------*
58 Name: WS_GetSystemState
59
60 Description: Obtains the WS state.
61
62 Arguments: None.
63
64 Returns: The WS state.
65 *---------------------------------------------------------------------------*/
WS_GetSystemState(void)66 int WS_GetSystemState(void)
67 {
68 return sSysState;
69 }
70
71 /*---------------------------------------------------------------------------*
72 Name: WS_Initialize
73
74 Description: Initializes wireless.
75
76 Arguments: buf: Buffer size passed to WM. A region the size of WM_SYSTEM_BUF_SIZE required.
77 dmaNo: The DMA number used by wireless.
78
79 Returns: If the process starts successfully, TRUE.
80 If it did not start, FALSE.
81 *---------------------------------------------------------------------------*/
WS_Initialize(void * buf,u16 dmaNo)82 BOOL WS_Initialize(void *buf, u16 dmaNo)
83 {
84 WMErrCode result;
85
86 SDK_NULL_ASSERT(buf);
87
88 WS_ChangeSysState(WS_SYSSTATE_BUSY);
89 result = WM_Initialize(buf, WS_StateOutInitialize, dmaNo);
90 if (result != WM_ERRCODE_OPERATING)
91 {
92 WS_ChangeSysState(WS_SYSSTATE_FATAL);
93 return FALSE;
94 }
95 sScanParam.channel = 0;
96 return TRUE;
97 }
98
99
100 /*---------------------------------------------------------------------------*
101 Name: WS_StateOutInitialize
102 Description: Initializes wireless.
103 Arguments: None.
104 Returns: None.
105 *---------------------------------------------------------------------------*/
WS_StateOutInitialize(void * arg)106 static void WS_StateOutInitialize(void *arg)
107 {
108 // State after power-on
109 WMCallback *cb = (WMCallback *)arg;
110
111 if (cb->errcode != WM_ERRCODE_SUCCESS)
112 {
113 WS_ChangeSysState(WS_SYSSTATE_FATAL);
114 return;
115 }
116
117 // Changes the system state to idle (waiting)
118 WS_ChangeSysState(WS_SYSSTATE_IDLE);
119
120 // Does not set the next state, so the sequence ends here
121 }
122
123 /*---------------------------------------------------------------------------*
124 Name: WS_TurnOnPictoCatch
125
126 Description: Enables the Pictocatch feature.
127 This will cause the callback function to be invoked when Pictochat is found while scanning with WS_StartScan.
128
129
130 Arguments: None.
131
132 Returns: None.
133 *---------------------------------------------------------------------------*/
WS_TurnOnPictoCatch(void)134 void WS_TurnOnPictoCatch(void)
135 {
136 sPictoCatchFlag = TRUE;
137 }
138
139 /*---------------------------------------------------------------------------*
140 Name: WS_TurnOffPictoCatch
141
142 Description: Disables the pictocatch feature.
143
144 Arguments: None.
145
146 Returns: None.
147 *---------------------------------------------------------------------------*/
WS_TurnOffPictoCatch(void)148 void WS_TurnOffPictoCatch(void)
149 {
150 sPictoCatchFlag = FALSE;
151 }
152
153 /*---------------------------------------------------------------------------*
154 Name: WS_SetGgid
155
156 Description: Sets the game group ID.
157 Call before making a connection to the parent device.
158
159 Arguments: ggid: The game group ID to configure
160
161 Returns: None.
162 *---------------------------------------------------------------------------*/
WS_SetGgid(u32 ggid)163 void WS_SetGgid(u32 ggid)
164 {
165 sGgid = ggid;
166 }
167
168
169 /*---------------------------------------------------------------------------*
170 Name: WS_StartScan
171
172 Description: Starts scanning for a parent.
173
174 Arguments: callback: Callback when parent is found
175 macAddr: Specifies the parent's MAC address
176 When searching for all parents, specify FF:FF:FF:FF:FF:FF
177 continuous: If this flag is set to TRUE, all valid channels will continue to be scanned until WS_EndScan is called
178
179 If FALSE, while cycling between valid channels, it will stop scanning after each scan and transition to the WS_SYSSTATE_SCANIDLE state.
180
181
182 Returns: If the process starts successfully, TRUE.
183 If it did not start, FALSE.
184 *---------------------------------------------------------------------------*/
WS_StartScan(WSStartScanCallbackFunc callback,const u8 * macAddr,BOOL continuous)185 BOOL WS_StartScan(WSStartScanCallbackFunc callback, const u8 *macAddr, BOOL continuous)
186 {
187 OSIntrMode enabled;
188
189 enabled = OS_DisableInterrupts();
190
191 sScanCallback = callback;
192 sContinuousScanFlag = continuous;
193
194 // Sets the conditions for the MAC address to be searched for
195 *(u16 *)(&sScanParam.bssid[4]) = *(u16 *)(macAddr + 4);
196 *(u16 *)(&sScanParam.bssid[2]) = *(u16 *)(macAddr + 2);
197 *(u16 *)(&sScanParam.bssid[0]) = *(u16 *)(macAddr);
198
199 (void)OS_RestoreInterrupts(enabled);
200
201 if (sSysState == WS_SYSSTATE_SCANNING)
202 {
203 return TRUE;
204 }
205
206 WS_ChangeSysState(WS_SYSSTATE_SCANNING);
207
208 if (!WS_StateInStartScan())
209 {
210 WS_ChangeSysState(WS_SYSSTATE_ERROR);
211 return FALSE;
212 }
213
214 return TRUE;
215 }
216
217 /* ----------------------------------------------------------------------
218 state: StartScan
219 ---------------------------------------------------------------------- */
WS_StateInStartScan(void)220 static BOOL WS_StateInStartScan(void)
221 {
222 // When in this state, looks for a parent
223 WMErrCode result;
224 u16 chanpat;
225
226 WS_ASSERT(sSysState == WS_SYSSTATE_SCANNING);
227
228 chanpat = WM_GetAllowedChannel();
229
230 // Checks if wireless is usable
231 if (chanpat == 0x8000)
232 {
233 // If 0x8000 is returned, it indicates that wireless is not initialized or there is some other abnormality with the wireless library. Therefore, set to an error.
234 //
235 return FALSE;
236 }
237 if (chanpat == 0)
238 {
239 // In this state, wireless cannot be used
240 return FALSE;
241 }
242
243 /* Search possible channels in ascending order from the current designation */
244 while (TRUE)
245 {
246 sScanParam.channel++;
247 if (sScanParam.channel > 16)
248 {
249 sScanParam.channel = 1;
250 }
251
252 if (chanpat & (0x0001 << (sScanParam.channel - 1)))
253 {
254 break;
255 }
256 }
257
258 sScanParam.maxChannelTime = WM_GetDispersionScanPeriod();
259 sScanParam.scanBuf = &sBssDesc;
260 result = WM_StartScan(WS_StateOutStartScan, &sScanParam);
261
262 if (result != WM_ERRCODE_OPERATING)
263 {
264 return FALSE;
265 }
266 return TRUE;
267 }
268
WS_StateOutStartScan(void * arg)269 static void WS_StateOutStartScan(void *arg)
270 {
271 WMstartScanCallback *cb = (WMstartScanCallback *)arg;
272
273 // If the scan command fails
274 if (cb->errcode != WM_ERRCODE_SUCCESS)
275 {
276 WS_ChangeSysState(WS_SYSSTATE_ERROR);
277 return;
278 }
279
280 if (sSysState != WS_SYSSTATE_SCANNING)
281 {
282 // End scan if the state has been changed
283 if (!WS_StateInEndScan())
284 {
285 WS_ChangeSysState(WS_SYSSTATE_ERROR);
286 }
287 return;
288 }
289
290 switch (cb->state)
291 {
292 case WM_STATECODE_PARENT_NOT_FOUND:
293 break;
294
295 case WM_STATECODE_PARENT_FOUND:
296 // If a parent is found
297 // Compares ggids and fails if different.
298 // First, you must confirm WMBssDesc.gameInfoLength, and check to see if ggid has a valid value.
299 //
300
301 // Discards the BssDesc cache that is set in the buffer, because the BssDesc information is written from the ARM7
302 //
303 DC_InvalidateRange(&sBssDesc, sizeof(WMbssDesc));
304
305 #if defined(TWL_SUPPORT_CHT)
306 // Determines if the parent is using pictochat
307 if (sPictoCatchFlag)
308 {
309 if (CHT_IsPictochatParent(&sBssDesc))
310 {
311 // If the parent is using pictochat
312 if (sScanCallback != NULL)
313 {
314 sScanCallback(&sBssDesc);
315 }
316 break;
317 }
318 }
319 #endif
320
321 if (cb->gameInfoLength < 8 || cb->gameInfo.ggid != sGgid)
322 {
323 // If GGIDs are different, this is ignored
324 break;
325 }
326
327 // If the entry flag is not up, the child is not receiving, so this is ignored
328 if (!(cb->gameInfo.gameNameCount_attribute & WM_ATTR_FLAG_ENTRY))
329 {
330 break;
331 }
332
333 // Call if callback is necessary
334 if (sScanCallback != NULL)
335 {
336 sScanCallback(&sBssDesc);
337 }
338
339 break;
340 }
341
342 if (!sContinuousScanFlag)
343 {
344 WS_ChangeSysState(WS_SYSSTATE_SCANIDLE);
345 return;
346 }
347
348 // Changes the channel and starts another scan
349 if (!WS_StateInStartScan())
350 {
351 WS_ChangeSysState(WS_SYSSTATE_ERROR);
352 }
353 }
354
355
356 /*---------------------------------------------------------------------------*
357 Name: WS_EndScan
358
359 Description: Function that terminates scanning
360
361 Arguments: None.
362
363 Returns: If the process starts successfully, TRUE.
364 If it did not start, FALSE.
365 *---------------------------------------------------------------------------*/
WS_EndScan(void)366 BOOL WS_EndScan(void)
367 {
368 if (sSysState == WS_SYSSTATE_SCANIDLE)
369 {
370 return WS_StateInEndScan();
371 }
372
373 if (sSysState != WS_SYSSTATE_SCANNING)
374 {
375 return FALSE;
376 }
377
378 {
379 OSIntrMode enabled = OS_DisableInterrupts();
380 sScanCallback = NULL;
381 (void)OS_RestoreInterrupts(enabled);
382 }
383
384 WS_ChangeSysState(WS_SYSSTATE_BUSY);
385 return TRUE;
386 }
387
388
WS_StateInEndScan(void)389 static BOOL WS_StateInEndScan(void)
390 {
391 WMErrCode result;
392
393 // In this state, scan end processing is carried out
394 result = WM_EndScan(WS_StateOutEndScan);
395 if (result != WM_ERRCODE_OPERATING)
396 {
397 return FALSE;
398 }
399
400 return TRUE;
401 }
402
WS_StateOutEndScan(void * arg)403 static void WS_StateOutEndScan(void *arg)
404 {
405 WMCallback *cb = (WMCallback *)arg;
406
407 if (cb->errcode != WM_ERRCODE_SUCCESS)
408 {
409 return;
410 }
411
412 WS_ChangeSysState(WS_SYSSTATE_IDLE);
413 }
414
415
416 /*---------------------------------------------------------------------------*
417 Name: WS_End
418
419 Description: Ends wireless communications.
420
421 Arguments: None.
422
423 Returns: If it succeeds returns TRUE.
424 *---------------------------------------------------------------------------*/
WS_End(void)425 BOOL WS_End(void)
426 {
427 WS_ASSERT(sSysState == WS_SYSSTATE_IDLE);
428
429 WS_ChangeSysState(WS_SYSSTATE_BUSY);
430 if (WM_End(WS_StateOutEnd) != WM_ERRCODE_OPERATING)
431 {
432 WS_ChangeSysState(WS_SYSSTATE_ERROR);
433
434 return FALSE;
435 }
436 return TRUE;
437 }
438
439 /* ----------------------------------------------------------------------
440 state: WS_StateOutEnd
441 ---------------------------------------------------------------------- */
WS_StateOutEnd(void * arg)442 static void WS_StateOutEnd(void *arg)
443 {
444 WMCallback *cb = (WMCallback *)arg;
445 if (cb->errcode != WM_ERRCODE_SUCCESS)
446 {
447 WS_ChangeSysState(WS_SYSSTATE_FATAL);
448 return;
449 }
450 WS_ChangeSysState(WS_SYSSTATE_STOP);
451 }
452