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