/*---------------------------------------------------------------------------* Project: TwlSDK - CHT - demos - wmscan File: chtmin.c Copyright 2003-2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2008-09-17 #$ $Rev: 8556 $ $Author: okubata_ryoma $ *---------------------------------------------------------------------------*/ #include #include "wmscan.h" // TODO: Not currently supported because the CHT library has not yet been implemented. //#define TWL_SUPPORT_CHT #if defined(TWL_SUPPORT_CHT) #include #endif static int sSysState = WS_SYSSTATE_STOP; // wmscan internal state static WSStartScanCallbackFunc sScanCallback = NULL; // Callback pointer when parent is discovered static WMBssDesc sBssDesc ATTRIBUTE_ALIGN(32); // Buffer to obtain parent data static WMScanParam sScanParam ATTRIBUTE_ALIGN(32); // Scan parameter structure static BOOL sContinuousScanFlag; // Continuous scan flag static BOOL sPictoCatchFlag = FALSE; // PictoCatch flag static u32 sGgid = 0; // GGID #define WS_ASSERT(exp) \ (void) ((exp) || (OSi_Panic(__FILE__, __LINE__, "Failed assertion " #exp), 0)) static void WS_ChangeSysState(int state); static void WS_StateOutInitialize(void *arg); static BOOL WS_StateInStartScan(void); static void WS_StateOutStartScan(void *arg); static BOOL WS_StateInEndScan(void); static void WS_StateOutEndScan(void *arg); static void WS_StateOutEnd(void *arg); /*---------------------------------------------------------------------------* Name: WS_ChangeSysState Description: Changes the WS status. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static inline void WS_ChangeSysState(int state) { sSysState = state; } /*---------------------------------------------------------------------------* Name: WS_GetSystemState Description: Obtains the WS state. Arguments: None. Returns: The WS state. *---------------------------------------------------------------------------*/ int WS_GetSystemState(void) { return sSysState; } /*---------------------------------------------------------------------------* Name: WS_Initialize Description: Initializes wireless. Arguments: buf: Buffer size passed to WM. A region the size of WM_SYSTEM_BUF_SIZE required. dmaNo: The DMA number used by wireless. Returns: If the process starts successfully, TRUE. If it did not start, FALSE. *---------------------------------------------------------------------------*/ BOOL WS_Initialize(void *buf, u16 dmaNo) { WMErrCode result; SDK_NULL_ASSERT(buf); WS_ChangeSysState(WS_SYSSTATE_BUSY); result = WM_Initialize(buf, WS_StateOutInitialize, dmaNo); if (result != WM_ERRCODE_OPERATING) { WS_ChangeSysState(WS_SYSSTATE_FATAL); return FALSE; } sScanParam.channel = 0; return TRUE; } /*---------------------------------------------------------------------------* Name: WS_StateOutInitialize Description: Initializes wireless. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void WS_StateOutInitialize(void *arg) { // State after power-on WMCallback *cb = (WMCallback *)arg; if (cb->errcode != WM_ERRCODE_SUCCESS) { WS_ChangeSysState(WS_SYSSTATE_FATAL); return; } // Changes the system state to idle (waiting) WS_ChangeSysState(WS_SYSSTATE_IDLE); // Does not set the next state, so the sequence ends here } /*---------------------------------------------------------------------------* Name: WS_TurnOnPictoCatch Description: Enables the Pictocatch feature. This will cause the callback function to be invoked when Pictochat is found while scanning with WS_StartScan. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void WS_TurnOnPictoCatch(void) { sPictoCatchFlag = TRUE; } /*---------------------------------------------------------------------------* Name: WS_TurnOffPictoCatch Description: Disables the pictocatch feature. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void WS_TurnOffPictoCatch(void) { sPictoCatchFlag = FALSE; } /*---------------------------------------------------------------------------* Name: WS_SetGgid Description: Sets the game group ID. Call before making a connection to the parent device. Arguments: ggid: The game group ID to configure Returns: None. *---------------------------------------------------------------------------*/ void WS_SetGgid(u32 ggid) { sGgid = ggid; } /*---------------------------------------------------------------------------* Name: WS_StartScan Description: Starts scanning for a parent. Arguments: callback: Callback when parent is found macAddr: Specifies the parent's MAC address When searching for all parents, specify FF:FF:FF:FF:FF:FF continuous: If this flag is set to TRUE, all valid channels will continue to be scanned until WS_EndScan is called If FALSE, while cycling between valid channels, it will stop scanning after each scan and transition to the WS_SYSSTATE_SCANIDLE state. Returns: If the process starts successfully, TRUE. If it did not start, FALSE. *---------------------------------------------------------------------------*/ BOOL WS_StartScan(WSStartScanCallbackFunc callback, const u8 *macAddr, BOOL continuous) { OSIntrMode enabled; enabled = OS_DisableInterrupts(); sScanCallback = callback; sContinuousScanFlag = continuous; // Sets the conditions for the MAC address to be searched for *(u16 *)(&sScanParam.bssid[4]) = *(u16 *)(macAddr + 4); *(u16 *)(&sScanParam.bssid[2]) = *(u16 *)(macAddr + 2); *(u16 *)(&sScanParam.bssid[0]) = *(u16 *)(macAddr); (void)OS_RestoreInterrupts(enabled); if (sSysState == WS_SYSSTATE_SCANNING) { return TRUE; } WS_ChangeSysState(WS_SYSSTATE_SCANNING); if (!WS_StateInStartScan()) { WS_ChangeSysState(WS_SYSSTATE_ERROR); return FALSE; } return TRUE; } /* ---------------------------------------------------------------------- state: StartScan ---------------------------------------------------------------------- */ static BOOL WS_StateInStartScan(void) { // When in this state, looks for a parent WMErrCode result; u16 chanpat; WS_ASSERT(sSysState == WS_SYSSTATE_SCANNING); chanpat = WM_GetAllowedChannel(); // Checks if wireless is usable if (chanpat == 0x8000) { // 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. // return FALSE; } if (chanpat == 0) { // In this state, wireless cannot be used return FALSE; } /* Search possible channels in ascending order from the current designation */ while (TRUE) { sScanParam.channel++; if (sScanParam.channel > 16) { sScanParam.channel = 1; } if (chanpat & (0x0001 << (sScanParam.channel - 1))) { break; } } sScanParam.maxChannelTime = WM_GetDispersionScanPeriod(); sScanParam.scanBuf = &sBssDesc; result = WM_StartScan(WS_StateOutStartScan, &sScanParam); if (result != WM_ERRCODE_OPERATING) { return FALSE; } return TRUE; } static void WS_StateOutStartScan(void *arg) { WMstartScanCallback *cb = (WMstartScanCallback *)arg; // If the scan command fails if (cb->errcode != WM_ERRCODE_SUCCESS) { WS_ChangeSysState(WS_SYSSTATE_ERROR); return; } if (sSysState != WS_SYSSTATE_SCANNING) { // End scan if the state has been changed if (!WS_StateInEndScan()) { WS_ChangeSysState(WS_SYSSTATE_ERROR); } return; } switch (cb->state) { case WM_STATECODE_PARENT_NOT_FOUND: break; case WM_STATECODE_PARENT_FOUND: // If a parent is found // Compares ggids and fails if different. // First, you must confirm WMBssDesc.gameInfoLength, and check to see if ggid has a valid value. // // Discards the BssDesc cache that is set in the buffer, because the BssDesc information is written from the ARM7 // DC_InvalidateRange(&sBssDesc, sizeof(WMbssDesc)); #if defined(TWL_SUPPORT_CHT) // Determines if the parent is using pictochat if (sPictoCatchFlag) { if (CHT_IsPictochatParent(&sBssDesc)) { // If the parent is using pictochat if (sScanCallback != NULL) { sScanCallback(&sBssDesc); } break; } } #endif if (cb->gameInfoLength < 8 || cb->gameInfo.ggid != sGgid) { // If GGIDs are different, this is ignored break; } // If the entry flag is not up, the child is not receiving, so this is ignored if (!(cb->gameInfo.gameNameCount_attribute & WM_ATTR_FLAG_ENTRY)) { break; } // Call if callback is necessary if (sScanCallback != NULL) { sScanCallback(&sBssDesc); } break; } if (!sContinuousScanFlag) { WS_ChangeSysState(WS_SYSSTATE_SCANIDLE); return; } // Changes the channel and starts another scan if (!WS_StateInStartScan()) { WS_ChangeSysState(WS_SYSSTATE_ERROR); } } /*---------------------------------------------------------------------------* Name: WS_EndScan Description: Function that terminates scanning Arguments: None. Returns: If the process starts successfully, TRUE. If it did not start, FALSE. *---------------------------------------------------------------------------*/ BOOL WS_EndScan(void) { if (sSysState == WS_SYSSTATE_SCANIDLE) { return WS_StateInEndScan(); } if (sSysState != WS_SYSSTATE_SCANNING) { return FALSE; } { OSIntrMode enabled = OS_DisableInterrupts(); sScanCallback = NULL; (void)OS_RestoreInterrupts(enabled); } WS_ChangeSysState(WS_SYSSTATE_BUSY); return TRUE; } static BOOL WS_StateInEndScan(void) { WMErrCode result; // In this state, scan end processing is carried out result = WM_EndScan(WS_StateOutEndScan); if (result != WM_ERRCODE_OPERATING) { return FALSE; } return TRUE; } static void WS_StateOutEndScan(void *arg) { WMCallback *cb = (WMCallback *)arg; if (cb->errcode != WM_ERRCODE_SUCCESS) { return; } WS_ChangeSysState(WS_SYSSTATE_IDLE); } /*---------------------------------------------------------------------------* Name: WS_End Description: Ends wireless communications. Arguments: None. Returns: If it succeeds returns TRUE. *---------------------------------------------------------------------------*/ BOOL WS_End(void) { WS_ASSERT(sSysState == WS_SYSSTATE_IDLE); WS_ChangeSysState(WS_SYSSTATE_BUSY); if (WM_End(WS_StateOutEnd) != WM_ERRCODE_OPERATING) { WS_ChangeSysState(WS_SYSSTATE_ERROR); return FALSE; } return TRUE; } /* ---------------------------------------------------------------------- state: WS_StateOutEnd ---------------------------------------------------------------------- */ static void WS_StateOutEnd(void *arg) { WMCallback *cb = (WMCallback *)arg; if (cb->errcode != WM_ERRCODE_SUCCESS) { WS_ChangeSysState(WS_SYSSTATE_FATAL); return; } WS_ChangeSysState(WS_SYSSTATE_STOP); }