/*---------------------------------------------------------------------------* Project: TwlSDK - wireless_shared - demos - mbp File: mbp.c Copyright 2006-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-10-02#$ $Rev: 8827 $ $Author: yosizaki $ *---------------------------------------------------------------------------*/ #include #include #include #include "mbp.h" //============================================================================ // Prototype Declarations //============================================================================ static BOOL MBP_RegistFile(const MBGameRegistry *gameInfo); static inline void MBP_AddBitmap(u16 *pBitmap, u16 aid); static inline void MBP_RemoveBitmap(u16 *pBitmap, u16 aid); static inline void MBP_DisconnectChild(u16 aid); static inline void MBP_DisconnectChildFromBmp(u16 aid); static void ParentStateCallback(u16 child_aid, u32 status, void *arg); static void MBP_ChangeState(u16 state); // Callbacks are run by IRQs, so it is safer to set a slightly large IRQ stack size in the LCF file when running complex processes within a callback. // // // Because OS_Printf() in particular consumes a large amount of stack, try using the lighter version, OS_TPrintf(), in callbacks whenever possible. // #define MBP_DEBUG #if defined( MBP_DEBUG ) #define MBP_Printf OS_TPrintf // #else #define MBP_Printf(...) ((void)0) #endif //============================================================================ // Variable Definitions //============================================================================ // Child connection information static MBPState mbpState; static MBPChildInfo childInfo[MBP_CHILD_MAX]; /* The work region to be allocated to the MB library */ static u32 *sCWork = NULL; /* Buffer for child device startup binary transmission */ static u8 *sFilebuf = NULL; //============================================================================ // Function definitions //============================================================================ /*---------------------------------------------------------------------------* Name: MBP_Init Description: Initializes the multiboot parent information. Arguments: ggid Specifies the parent's GGID when distributing a game tgid Specifies the parent's TGID when distributing a game Returns: None. *---------------------------------------------------------------------------*/ void MBP_Init(u32 ggid, u16 tgid) { /* For the configuration of the parent device information to be displayed to the child device screen */ MBUserInfo myUser; /* It is not precisely determined what type of value needs to be specified as the parent information to display on the MB child screen. * Here, user information registered with the IPL is set as the MB parent information, but the name established within the game may be set. * However, this must be set as 2-byte code. * * */ OSOwnerInfo info; OS_GetOwnerInfo(&info); myUser.favoriteColor = info.favoriteColor; myUser.nameLength = (u8)info.nickNameLength; MI_CpuCopy8(info.nickName, myUser.name, (u32)(info.nickNameLength * 2)); myUser.playerNo = 0; // The parent is number 0 // Initialize the status information mbpState = (const MBPState) { MBP_STATE_STOP, 0, 0, 0, 0, 0, 0}; /* Begin MB parent device control */ // Allocate the MB work area #if !defined(MBP_USING_MB_EX) sCWork = OS_Alloc(MB_SYSTEM_BUF_SIZE); #else /* A small work size does not matter if WM initialization has been finished externally */ sCWork = OS_Alloc(MB_SYSTEM_BUF_SIZE - WM_SYSTEM_BUF_SIZE); #endif if (MB_Init(sCWork, &myUser, ggid, tgid, MBP_DMA_NO) != MB_SUCCESS) { OS_Panic("ERROR in MB_Init\n"); } // Set the maximum number of children to be connected (set a value that excludes the parent) (void)MB_SetParentCommParam(MB_COMM_PARENT_SEND_MIN, MBP_CHILD_MAX); MB_CommSetParentStateCallback(ParentStateCallback); MBP_ChangeState(MBP_STATE_IDLE); } /*---------------------------------------------------------------------------* Name: MBP_Start Description: Starts multiboot parent. Arguments: gameInfo Distribution binary information channel Channel to be used Returns: None. *---------------------------------------------------------------------------*/ void MBP_Start(const MBGameRegistry *gameInfo, u16 channel) { SDK_ASSERT(MBP_GetState() == MBP_STATE_IDLE); MBP_ChangeState(MBP_STATE_ENTRY); #if !defined(MBP_USING_MB_EX) if (MB_StartParent(channel) != MB_SUCCESS) #else /* Transfer the WM library to an IDLE state, and directly begin */ if (MB_StartParentFromIdle(channel) != MB_SUCCESS) #endif { MBP_Printf("MB_StartParent fail\n"); MBP_ChangeState(MBP_STATE_ERROR); return; } /* --------------------------------------------------------------------- * * This will have been initialized when MB_StartParent() is called. * Use MB_RegisterFile() for registration after MB_StartParent(). * --------------------------------------------------------------------- */ /* Register the download program file information */ if (!MBP_RegistFile(gameInfo)) { OS_Panic("Illegal multiboot gameInfo\n"); } } /*---------------------------------------------------------------------------* Name: MBP_RegistFile Description: Registers the multiboot binary. Arguments: gameInfo Pointer to the multiboot binary information. Of these members, a romFilePathp value of NULL will cause operations to be the same as when a clone boot has been specified. Returns: Returns TRUE if the file open was successful. If failed, returns FALSE. *---------------------------------------------------------------------------*/ static BOOL MBP_RegistFile(const MBGameRegistry *gameInfo) { FSFile file, *p_file; u32 bufferSize; BOOL ret = FALSE; /* --------------------------------------------------------------------- * * This will already be initialized when MB_StartParent() is called, even if before that binary data was registered with MB_RegisterFile(). * * Use MB_RegisterFile() for registration after MB_StartParent(). * --------------------------------------------------------------------- */ /* * As given by this function's specifications, this will operate as a clone boot if romFilePathp is NULL. * * If not, the specified file will be treated as a child program. */ if (!gameInfo->romFilePathp) { p_file = NULL; } else { /* * The program file must be read using FS_ReadFile(). * Usually, programs are maintained as files in CARD-ROM and pose no problems. If you anticipate a special multi-boot system, however, use FSArchive to build an original archive to handle it. * * */ FS_InitFile(&file); if (!FS_OpenFileEx(&file, gameInfo->romFilePathp, FS_FILEMODE_R)) { /* Cannot open file */ OS_Warning("Cannot Register file\n"); return FALSE; } p_file = &file; } /* * Get the size of the segment information. * If this is not a valid download program, 0 will be returned for this size. * */ bufferSize = MB_GetSegmentLength(p_file); if (bufferSize == 0) { OS_Warning("specified file may be invalid format.\"%s\"\n", gameInfo->romFilePathp ? gameInfo->romFilePathp : "(cloneboot)"); } else { /* * Allocate memory for loading the download program's segment information. * If file registration succeeded, this region will be used until MB_End() is called. * This memory may be prepared statically as long as it is large enough. * */ sFilebuf = OS_Alloc(bufferSize); if (sFilebuf == NULL) { /* Failed to allocate buffer that stores segment information */ OS_Warning("can't allocate Segment buffer size.\n"); } else { /* * Extract segment information from the file. * The extracted segment information must stay resident in main memory while the download program is being distributed. * */ if (!MB_ReadSegment(p_file, sFilebuf, bufferSize)) { /* * Failed to extract segments because the file is invalid. * If extraction fails here even though the size was obtained successfully, it may be because the file handle was changed in some way. * (The file was closed, a seek to some location was run, and so on) * */ OS_Warning(" Can't Read Segment\n"); } else { /* * Register the download program in the MBGameRegistry with the extracted segment information. * */ if (!MB_RegisterFile(gameInfo, sFilebuf)) { /* Registration failed because of incorrect program information */ OS_Warning(" Illegal program info\n"); } else { /* Process completed correctly */ ret = TRUE; } } if (!ret) OS_Free(sFilebuf); } } /* Close file if not clone boot */ if (p_file == &file) { (void)FS_CloseFile(&file); } return ret; } /*---------------------------------------------------------------------------* Name: MBP_AcceptChild Description: Accepts a request from a child. Arguments: child_aid AID of a connected child. Returns: None. *---------------------------------------------------------------------------*/ void MBP_AcceptChild(u16 child_aid) { if (!MB_CommResponseRequest(child_aid, MB_COMM_RESPONSE_REQUEST_ACCEPT)) { // If the request fails, disconnect that child MBP_DisconnectChild(child_aid); return; } MBP_Printf("accept child %d\n", child_aid); } /*---------------------------------------------------------------------------* Name: MBP_KickChild Description: Kicks the connected child. Arguments: child_aid AID of a connected child Returns: None. *---------------------------------------------------------------------------*/ void MBP_KickChild(u16 child_aid) { if (!MB_CommResponseRequest(child_aid, MB_COMM_RESPONSE_REQUEST_KICK)) { // If the request fails, disconnect that child MBP_DisconnectChild(child_aid); return; } { OSIntrMode enabled = OS_DisableInterrupts(); mbpState.requestChildBmp &= ~(1 << child_aid); mbpState.connectChildBmp &= ~(1 << child_aid); (void)OS_RestoreInterrupts(enabled); } } /*---------------------------------------------------------------------------* Name: MBP_StartDownload Description: Sends the download start signals to the child. Arguments: child_aid AID of a connected child Returns: None. *---------------------------------------------------------------------------*/ void MBP_StartDownload(u16 child_aid) { if (!MB_CommStartSending(child_aid)) { // If the request fails, disconnect that child MBP_DisconnectChild(child_aid); return; } { OSIntrMode enabled = OS_DisableInterrupts(); mbpState.entryChildBmp &= ~(1 << child_aid); mbpState.downloadChildBmp |= 1 << child_aid; (void)OS_RestoreInterrupts(enabled); } } /*---------------------------------------------------------------------------* Name: MBP_StartDownloadAll Description: Starts the data transfer to all of the children currently being entered. After this, it does not accept entries from children. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void MBP_StartDownloadAll(void) { u16 i; // Stop accepting entries MBP_ChangeState(MBP_STATE_DATASENDING); for (i = 1; i < 16; i++) { if (!(mbpState.connectChildBmp & (1 << i))) { continue; } #ifdef MBP_USING_PREVIOUS_DOWNLOAD /* When data transfer has started immediately after entry */ // Disconnect children that are not being entered if (MBP_GetChildState(i) == MBP_CHILDSTATE_CONNECTING) { MBP_DisconnectChild(i); continue; } #else /* When starting to send data to all child devices at once */ if (mbpState.requestChildBmp & (1 << i)) { // The child currently being entered will be processed after it becomes ready continue; } // Disconnect children that are not being entered if (!(mbpState.entryChildBmp & (1 << i))) { MBP_DisconnectChild(i); continue; } // Children that are being entered start downloading MBP_StartDownload(i); #endif } } /*---------------------------------------------------------------------------* Name: MBP_IsBootableAll Description: Checks whether all the connected child devices are in a bootable state. Arguments: None. Returns: TRUE if all of the children are bootable. FALSE if there is at least one child that is not bootable. *---------------------------------------------------------------------------*/ BOOL MBP_IsBootableAll(void) { u16 i; if (mbpState.connectChildBmp == 0) { return FALSE; } for (i = 1; i < 16; i++) { if (!(mbpState.connectChildBmp & (1 << i))) { continue; } if (!MB_CommIsBootable(i)) { return FALSE; } } return TRUE; } /*---------------------------------------------------------------------------* Name: MBP_StartRebootAll Description: Boots all of the connected children that are bootable. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void MBP_StartRebootAll(void) { u16 i; u16 sentChild = 0; for (i = 1; i < 16; i++) { if (!(mbpState.bootableChildBmp & (1 << i))) { continue; } if (!MB_CommBootRequest(i)) { // If the request fails, disconnect that child MBP_DisconnectChild(i); continue; } sentChild |= (1 << i); } // If the connected child becomes 0, terminate with an error if (sentChild == 0) { MBP_ChangeState(MBP_STATE_ERROR); return; } // Changes the state and stops accepting data transfer MBP_ChangeState(MBP_STATE_REBOOTING); } /*---------------------------------------------------------------------------* Name: MBP_Cancel Description: Cancels multiboot. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void MBP_Cancel(void) { MBP_ChangeState(MBP_STATE_CANCEL); #if !defined(MBP_USING_MB_EX) MB_End(); #else MB_EndToIdle(); #endif } /*---------------------------------------------------------------------------* Name: MBPi_CheckAllReboot Description: Determines whether all connected children are in the MB_COMM_PSTATE_BOOT_STARTABLE state and starts to shut down the MB library if they are. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void MBPi_CheckAllReboot(void) { if ((mbpState.state == MBP_STATE_REBOOTING) && (mbpState.connectChildBmp == mbpState.rebootChildBmp)) { MBP_Printf("call MB_End()\n"); #if !defined(MBP_USING_MB_EX) MB_End(); #else MB_EndToIdle(); #endif } } /*---------------------------------------------------------------------------* Name: ParentStateCallback Description: Parent state notification callback Arguments: child_aid AID of the child status Callback status arg Option argument Returns: None. *---------------------------------------------------------------------------*/ static void ParentStateCallback(u16 child_aid, u32 status, void *arg) { #if defined( MBP_DEBUG ) // For debug output static const char *MB_CALLBACK_TABLE[] = { "MB_COMM_PSTATE_NONE", "MB_COMM_PSTATE_INIT_COMPLETE", "MB_COMM_PSTATE_CONNECTED", "MB_COMM_PSTATE_DISCONNECTED", "MB_COMM_PSTATE_KICKED", "MB_COMM_PSTATE_REQ_ACCEPTED", "MB_COMM_PSTATE_SEND_PROCEED", "MB_COMM_PSTATE_SEND_COMPLETE", "MB_COMM_PSTATE_BOOT_REQUEST", "MB_COMM_PSTATE_BOOT_STARTABLE", "MB_COMM_PSTATE_REQUESTED", "MB_COMM_PSTATE_MEMBER_FULL", "MB_COMM_PSTATE_END", "MB_COMM_PSTATE_ERROR", "MB_COMM_PSTATE_WAIT_TO_SEND", }; #endif MBP_Printf("get callback %s %d\n", MB_CALLBACK_TABLE[status], child_aid); switch (status) { //----------------------------------------------------------- // Notification that the initialization process completed with the parent case MB_COMM_PSTATE_INIT_COMPLETE: // None. break; //----------------------------------------------------------- // Notification of the moment the child attempts to connect case MB_COMM_PSTATE_CONNECTED: { // Connection is not accepted if the parent is not in entry accepting state if (MBP_GetState() != MBP_STATE_ENTRY) { break; } MBP_AddBitmap(&mbpState.connectChildBmp, child_aid); // Saves a child's MacAddress WM_CopyBssid(((WMStartParentCallback *)arg)->macAddress, childInfo[child_aid - 1].macAddress); childInfo[child_aid - 1].playerNo = child_aid; } break; //----------------------------------------------------------- // Notification when the child device has terminated connection case MB_COMM_PSTATE_DISCONNECTED: { // Deletes the entry if it was disconnected by the condition other than rebooting of a child if (MBP_GetChildState(child_aid) != MBP_CHILDSTATE_REBOOT) { MBP_DisconnectChildFromBmp(child_aid); // Based on that, it determines whether every child has booted MBPi_CheckAllReboot(); } } break; //----------------------------------------------------------- // Notification of the moment the entry request came from a child case MB_COMM_PSTATE_REQUESTED: { const MBUserInfo *userInfo; userInfo = (MBUserInfo *)arg; OS_TPrintf("callback playerNo = %d\n", userInfo->playerNo); // Unequivocally kick child devices that requested entry when the parent device is not accepting entries // if (MBP_GetState() != MBP_STATE_ENTRY) { MBP_KickChild(child_aid); break; } // Accepts child's entry mbpState.requestChildBmp |= 1 << child_aid; MBP_AcceptChild(child_aid); // UserInfo has still not been set during MB_COMM_PSTATE_CONNECTED, so it is meaningless to call MB_CommGetChildUser before the REQUESTED state // userInfo = MB_CommGetChildUser(child_aid); if (userInfo != NULL) { MI_CpuCopy8(userInfo, &childInfo[child_aid - 1].user, sizeof(MBUserInfo)); } MBP_Printf("playerNo = %d\n", userInfo->playerNo); } break; //----------------------------------------------------------- // Notify ACK for ACCEPT to a child case MB_COMM_PSTATE_REQ_ACCEPTED: // No processing needed break; //----------------------------------------------------------- // Notification when received the download request from a child case MB_COMM_PSTATE_WAIT_TO_SEND: { // Changes the status of a child from entered to download standby. // Because this is the process in the interrupt, change it without prohibiting interrupt. mbpState.requestChildBmp &= ~(1 << child_aid); mbpState.entryChildBmp |= 1 << child_aid; // Starts the data transmission when MBP_StartDownload() is called from main routine. // If it is already in data transmission state, it starts the data transmission to the child. #ifdef MBP_USING_PREVIOUS_DOWNLOAD /* When starting to send data immediately after entry */ MBP_StartDownload(child_aid); #else /* When starting to send data to all child devices at once */ if (MBP_GetState() == MBP_STATE_DATASENDING) { MBP_StartDownload(child_aid); } #endif } break; //----------------------------------------------------------- // Notification when kicking a child case MB_COMM_PSTATE_KICKED: // None. break; //----------------------------------------------------------- // Notification when starting the binary transmission to a child case MB_COMM_PSTATE_SEND_PROCEED: // None. break; //----------------------------------------------------------- // Notification when the binary transmission to the child completed case MB_COMM_PSTATE_SEND_COMPLETE: { // Because this is the process in the interrupt, change it without prohibiting interrupt mbpState.downloadChildBmp &= ~(1 << child_aid); mbpState.bootableChildBmp |= 1 << child_aid; } break; //----------------------------------------------------------- // Notify of a child when boot had completed properly case MB_COMM_PSTATE_BOOT_STARTABLE: { // Because this is the process in the interrupt, change it without prohibiting interrupt mbpState.bootableChildBmp &= ~(1 << child_aid); mbpState.rebootChildBmp |= 1 << child_aid; // When all of the children completed booting, starts the reconnection process with the parent MBPi_CheckAllReboot(); } break; //----------------------------------------------------------- // Notify when the boot request transmission to the target child has started. // It does not return as a callback. case MB_COMM_PSTATE_BOOT_REQUEST: // None. break; //----------------------------------------------------------- // Notification when the members are full case MB_COMM_PSTATE_MEMBER_FULL: // None. break; //----------------------------------------------------------- // Notify when ending multiboot case MB_COMM_PSTATE_END: { if (MBP_GetState() == MBP_STATE_REBOOTING) // When reboot process ends, it ends MB and reconnects with a child { MBP_ChangeState(MBP_STATE_COMPLETE); } else // Shut down completed, and restore the STOP state { MBP_ChangeState(MBP_STATE_STOP); } // Clears the buffer used for distributing games. // Work memory will have been released when the MB_COMM_PSTATE_END callback returns, so we can free memory. // if (sFilebuf) { OS_Free(sFilebuf); sFilebuf = NULL; } if (sCWork) { OS_Free(sCWork); sCWork = NULL; } /* MB_UnregisterFile can be omitted because initialization will be caused by calling MB_End and releasing work memory * */ } break; //----------------------------------------------------------- // Notify that the error occurred case MB_COMM_PSTATE_ERROR: { MBErrorStatus *cb = (MBErrorStatus *)arg; switch (cb->errcode) { //------------------------------ // Notification level error. No process is necessary. case MB_ERRCODE_WM_FAILURE: // None. break; //------------------------------ // Error at the level that requires wireless to be reset case MB_ERRCODE_INVALID_PARAM: case MB_ERRCODE_INVALID_STATE: case MB_ERRCODE_FATAL: MBP_ChangeState(MBP_STATE_ERROR); break; } } break; //----------------------------------------------------------- default: OS_Panic("Get illegal parent state.\n"); } } /*---------------------------------------------------------------------------* Name: MBP_ChangeState Description: Changes the parent state. Arguments: state State to change Returns: None. *---------------------------------------------------------------------------*/ static void MBP_ChangeState(u16 state) { #if defined( MBP_DEBUG ) // For debug output static const char *STATE_NAME[] = { "MBP_STATE_STOP", "MBP_STATE_IDLE", "MBP_STATE_ENTRY", "MBP_STATE_DATASENDING", "MBP_STATE_REBOOTING", "MBP_STATE_COMPLETE", "MBP_STATE_CANCEL", "MBP_STATE_ERROR" }; #endif SDK_ASSERT(state < MBP_STATE_NUM); MBP_Printf("%s -> %s\n", STATE_NAME[mbpState.state], STATE_NAME[state]); mbpState.state = state; } /*---------------------------------------------------------------------------* Name: MBP_GetState Description: Gets the parent state. Arguments: None. Returns: Parent state. *---------------------------------------------------------------------------*/ u16 MBP_GetState(void) { return mbpState.state; } /*---------------------------------------------------------------------------* Name: MBP_GetConnectState Description: Gets the connection information. Arguments: Buffer area for getting the current connection state Returns: None. *---------------------------------------------------------------------------*/ void MBP_GetConnectState(MBPState * state) { MI_CpuCopy8(&mbpState, state, sizeof(MBPState)); } /*---------------------------------------------------------------------------* Name: MBP_GetChildBmp Description: Gets the connection bitmap of a child. Arguments: Type of the connection bitmap to get Returns: Child state. *---------------------------------------------------------------------------*/ u16 MBP_GetChildBmp(MBPBmpType bmpType) { u16 tmpBitmap; static const u16 *BITMAP_TABLE[MBP_BMPTYPE_NUM] = { &mbpState.connectChildBmp, &mbpState.requestChildBmp, &mbpState.entryChildBmp, &mbpState.downloadChildBmp, &mbpState.bootableChildBmp, &mbpState.rebootChildBmp, }; SDK_ASSERT(bmpType < MBP_BMPTYPE_NUM); tmpBitmap = *(BITMAP_TABLE[bmpType]); return tmpBitmap; } /*---------------------------------------------------------------------------* Name: MBP_GetChildState Description: Gets the connection state of a child. Arguments: aid Number for the connected child Returns: Child state. *---------------------------------------------------------------------------*/ MBPChildState MBP_GetChildState(u16 aid) { MBPState tmpState; u16 bitmap = (u16)(1 << aid); // Because an interrupt may change the connection state unexpectedly, prohibit interrupts and get a snapshot of the state at that time // OSIntrMode enabled = OS_DisableInterrupts(); if ((mbpState.connectChildBmp & bitmap) == 0) { (void)OS_RestoreInterrupts(enabled); return MBP_CHILDSTATE_NONE; // Not connected } MI_CpuCopy8(&mbpState, &tmpState, sizeof(MBPState)); (void)OS_RestoreInterrupts(enabled); // Determining the connection status if (tmpState.requestChildBmp & bitmap) { return MBP_CHILDSTATE_REQUEST; // Requesting connection } if (tmpState.entryChildBmp & bitmap) { return MBP_CHILDSTATE_ENTRY; // Undergoing entry } if (tmpState.downloadChildBmp & bitmap) { return MBP_CHILDSTATE_DOWNLOADING; // Downloading } if (tmpState.bootableChildBmp & bitmap) { return MBP_CHILDSTATE_BOOTABLE; // Boot preparation completed } if (tmpState.rebootChildBmp & bitmap) { return MBP_CHILDSTATE_REBOOT; // Rebooted } return MBP_CHILDSTATE_CONNECTING; // Connecting } /*---------------------------------------------------------------------------* Name: MBP_AddBitmap Description: Adds a child to the connection state bitmap. Arguments: pBitmap Pointer to the bitmap to add aid AID of the child to be added Returns: None. *---------------------------------------------------------------------------*/ static inline void MBP_AddBitmap(u16 *pBitmap, u16 aid) { // Prohibit interrupts to prevent an unexpected interrupt from breaking the state while values are being changed // OSIntrMode enabled = OS_DisableInterrupts(); *pBitmap |= (1 << aid); (void)OS_RestoreInterrupts(enabled); } /*---------------------------------------------------------------------------* Name: MBP_RemoveBitmap Description: Delete a child from the connection state bitmap. Arguments: pBitmap Pointer to the bitmap to delete aid AID of the child to be deleted Returns: None. *---------------------------------------------------------------------------*/ static inline void MBP_RemoveBitmap(u16 *pBitmap, u16 aid) { // Prohibit interrupts to prevent an unexpected interrupt from breaking the state while values are being changed // OSIntrMode enabled = OS_DisableInterrupts(); *pBitmap &= ~(1 << aid); (void)OS_RestoreInterrupts(enabled); } /*---------------------------------------------------------------------------* Name: MBP_DisconnectChildFromBmp Description: Deletes the child device flag from all bitmaps when a child device is disconnected. Arguments: aid AID of the child that was disconnected Returns: None. *---------------------------------------------------------------------------*/ static inline void MBP_DisconnectChildFromBmp(u16 aid) { u16 aidMask = (u16)~(1 << aid); OSIntrMode enabled = OS_DisableInterrupts(); mbpState.connectChildBmp &= aidMask; mbpState.requestChildBmp &= aidMask; mbpState.entryChildBmp &= aidMask; mbpState.downloadChildBmp &= aidMask; mbpState.bootableChildBmp &= aidMask; mbpState.rebootChildBmp &= aidMask; (void)OS_RestoreInterrupts(enabled); } /*---------------------------------------------------------------------------* Name: MBP_DisconnectChild Description: Disconnects a child. Arguments: aid AID of the child to be disconnected Returns: None. *---------------------------------------------------------------------------*/ static inline void MBP_DisconnectChild(u16 aid) { // MB_Disconnect may be provided in the future MBP_Printf(" WM_Disconnect %d\n", aid); MBP_DisconnectChildFromBmp(aid); MB_DisconnectChild(aid); } /*---------------------------------------------------------------------------* Name: MBP_GetChildInfo Description: Gets a pointer to the user information on a child. Arguments: child_aid AID of the child Returns: A pointer to user information. *---------------------------------------------------------------------------*/ const MBPChildInfo *MBP_GetChildInfo(u16 child_aid) { if (!(mbpState.connectChildBmp & (1 << child_aid))) { return NULL; } return &childInfo[child_aid - 1]; } /*---------------------------------------------------------------------------* Name: MBP_GetPlayerNo Description: Allows you to search for and obtain the player number (AID) used by a child device when it was a multiboot child, based on its MAC address, after that child has been rebooted and reconnected. Arguments: macAddress MAC address of a child Returns: Child AID at the time of multiboot connection. *---------------------------------------------------------------------------*/ u16 MBP_GetPlayerNo(const u8 *macAddress) { u16 i; for (i = 1; i < MBP_CHILD_MAX + 1; i++) { if ((mbpState.connectChildBmp & (1 << i)) == 0) { continue; } if (WM_IsBssidEqual(macAddress, childInfo[i - 1].macAddress)) { return childInfo[i - 1].playerNo; } } return 0; } /*---------------------------------------------------------------------------* Name: MBP_GetChildMacAddress Description: Gets MAC address of the multiboot child. Arguments: aid AID of the child Returns: Pointer to MAC address. *---------------------------------------------------------------------------*/ const u8 *MBP_GetChildMacAddress(u16 aid) { if (!(mbpState.connectChildBmp & (1 << aid))) { return NULL; } return childInfo[aid - 1].macAddress; }