/*---------------------------------------------------------------------------* Project: TwlSDK - WXC - libraries - File: wxc_protocol_impl_wxc.c Copyright 2005-2009 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-12-16#$ $Rev: 9661 $ $Author: okubata_ryoma $ *---------------------------------------------------------------------------*/ #include #include #include #include /*****************************************************************************/ /* Declaration */ static void WXCi_BeaconSendHook(WXCProtocolContext * protocol, WMParentParam *p_param); static BOOL WXCi_BeaconRecvHook(WXCProtocolContext * protocol, const WMBssDesc *p_desc); static void WXCi_PacketSendHook(WXCProtocolContext * protocol, WXCPacketInfo * packet); static BOOL WXCi_PacketRecvHook(WXCProtocolContext * protocol, const WXCPacketInfo * packet); static void WXCi_InitSequence(WXCProtocolContext * protocol, u16 send_max, u16 recv_max); static BOOL WXCi_AddData(WXCProtocolContext * protocol, const void *send_buf, u32 send_size, void *recv_buf, u32 recv_max); static BOOL WXCi_IsExecuting(WXCProtocolContext * protocol); /*****************************************************************************/ /* Variables */ /* Work buffer for WXC protocol */ static WXCImplWorkWxc impl_wxc_work; /* WXC protocol interface */ static WXCProtocolImpl impl_wxc = { "WXC", WXCi_BeaconSendHook, WXCi_BeaconRecvHook, NULL, WXCi_PacketSendHook, WXCi_PacketRecvHook, WXCi_InitSequence, WXCi_AddData, WXCi_IsExecuting, &impl_wxc_work, }; /*****************************************************************************/ /* Functions */ /*---------------------------------------------------------------------------* Name: WXCi_GetProtocolImplWXC Description: Gets the interface for the WXC chance encounter communication protocol. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ WXCProtocolImpl* WXCi_GetProtocolImplWXC(void) { return &impl_wxc; } /*---------------------------------------------------------------------------* Name: WXCi_BeaconSendHook Description: Hook called at beacon update. Arguments: protocol: WXCProtocolContext structure p_param: WMParentParam structure used for next beacon Change inside the function as necessary. Returns: None. *---------------------------------------------------------------------------*/ void WXCi_BeaconSendHook(WXCProtocolContext * protocol, WMParentParam *p_param) { #pragma unused(protocol) #pragma unused(p_param) /* * UserGameInfo is not currently used in the WXC library. * This is planned to be extended as necessary in the future when GGID net masking, common GGID mode, and other features are adopted. * */ } /*---------------------------------------------------------------------------* Name: WXCi_BeaconRecvHook Description: Hook called for individual scanned beacons. Arguments: protocol: WXCProtocolContext structure p_desc: Scanned WMBssDesc structure Returns: If it is seen as connection target, return TRUE. Otherwise, return FALSE. *---------------------------------------------------------------------------*/ BOOL WXCi_BeaconRecvHook(WXCProtocolContext * protocol, const WMBssDesc *p_desc) { #pragma unused(protocol) #pragma unused(p_desc) /* Only the "local mode," which distinguishes only based on GGID */ return TRUE; } /*---------------------------------------------------------------------------* Name: WXCi_PacketSendHook Description: Hook called at MP packet transmission. Arguments: protocol: WXCProtocolContext structure packet: WXCPacketInfo pointer configuring transmission packet information Returns: None. *---------------------------------------------------------------------------*/ void WXCi_PacketSendHook(WXCProtocolContext * protocol, WXCPacketInfo * packet) { WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work; WXCBlockHeader *p_header = (WXCBlockHeader *) packet->buffer; WXC_PACKET_LOG("--SEND:ACK=(%3d,%d,%04X),REQ=(%3d,%d,%04X)\n", wxc_work->ack.phase, wxc_work->ack.command, wxc_work->ack.index, wxc_work->req.phase, wxc_work->req.command, wxc_work->req.index); /* Set packet header to the send buffer */ p_header->req = wxc_work->req; p_header->ack = wxc_work->ack; /* Send response data only when the phase matches */ if (wxc_work->ack.phase == wxc_work->req.phase) { u8 *p_body = packet->buffer + sizeof(WXCBlockHeader); switch (wxc_work->ack.command) { case WXC_BLOCK_COMMAND_INIT: /* Send initial information (size + checksum) */ WXC_PACKET_LOG(" INIT(%6d)\n", protocol->send.length); *(u16 *)(p_body + 0) = (u16)protocol->send.length; *(u16 *)(p_body + 2) = protocol->send.checksum; break; case WXC_BLOCK_COMMAND_SEND: /* Send last requested index */ { int offset = (wxc_work->ack.index * wxc_work->send_unit); u32 len = (u32)(protocol->send.length - offset); if (len > wxc_work->send_unit) { len = wxc_work->send_unit; } MI_CpuCopy8((const u8 *)protocol->send.buffer + offset, p_body, len); } break; } } /* Specify packet size */ packet->length = (u16)MATH_ROUNDUP(sizeof(WXCBlockHeader) + wxc_work->send_unit, 2); } /*---------------------------------------------------------------------------* Name: WXCi_MergeBlockData Description: Saves the received block data fragment. Arguments: protocol: WXCProtocolContext structure index: Receive data index src: Receive data buffer Returns: None. *---------------------------------------------------------------------------*/ static void WXCi_MergeBlockData(WXCProtocolContext * protocol, int index, const void *src) { WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work; if (index < wxc_work->recv_total) { u32 *bmp = wxc_work->recv_bitmap_buf + (index >> 5); u32 bit = (u32)(1 << (index & 31)); if ((*bmp & bit) == 0) { int offset = (index * wxc_work->recv_unit); u32 len = (u32)(protocol->recv.length - offset); if (len > wxc_work->recv_unit) { len = wxc_work->recv_unit; } /* Don't save if recv.buffer is NULL */ if (protocol->recv.buffer != NULL) { MI_CpuCopy8(src, (u8 *)protocol->recv.buffer + offset, len); } *bmp |= bit; /* If data reception is finished, set as DONE */ if (--wxc_work->recv_rest == 0) { wxc_work->req.command = WXC_BLOCK_COMMAND_DONE; } /* If not, search for the non-received index */ else { int i; /* Use the previously requested index as a base point */ int count = wxc_work->recent_index[0]; int last_count = count; if (last_count >= wxc_work->recv_total) { last_count = (int)wxc_work->recv_total - 1; } for (;;) { /* Loop to the beginning once the end point is reached */ if (++count >= wxc_work->recv_total) { count = 0; } /* Reselect from history once the search finishes a single loop */ if (count == last_count) { count = wxc_work->recent_index[WXC_RECENT_SENT_LIST_MAX - 1]; break; } /* Determine if it is received yet */ if ((*(wxc_work->recv_bitmap_buf + (count >> 5)) & (1 << (count & 31))) == 0) { /* Determine whether it is a recently requested index */ for (i = 0; i < WXC_RECENT_SENT_LIST_MAX; ++i) { if (count == wxc_work->recent_index[i]) { break; } } if (i >= WXC_RECENT_SENT_LIST_MAX) { break; } } } /* Update the index request history */ for (i = WXC_RECENT_SENT_LIST_MAX; --i > 0;) { wxc_work->recent_index[i] = wxc_work->recent_index[i - 1]; } wxc_work->recent_index[0] = (u16)count; wxc_work->req.index = wxc_work->recent_index[0]; } } } } /*---------------------------------------------------------------------------* Name: WXCi_PacketRecvHook Description: Hook called at MP packet reception. Arguments: protocol: WXCProtocolContext structure packet: WXCPacketInfo pointer configuring reception packet information Returns: If a single data exchange is completed, return TRUE. *---------------------------------------------------------------------------*/ BOOL WXCi_PacketRecvHook(WXCProtocolContext * protocol, const WXCPacketInfo * packet) { WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work; int ret = FALSE; WXCBlockHeader *p_header = (WXCBlockHeader *) packet->buffer; if (packet->length >= wxc_work->recv_unit) { WXC_PACKET_LOG("--RECV:REQ=(%3d,%d,%04X),ACK=(%3d,%d,%04X)\n", p_header->req.phase, p_header->req.command, p_header->req.index, p_header->ack.phase, p_header->ack.command, p_header->ack.index); /* Save requested data only for targets with a same phase */ if (p_header->req.phase == wxc_work->req.phase) { wxc_work->ack = p_header->req; } /* View response data only for targets with a same phase */ if (p_header->ack.phase == wxc_work->req.phase) { u8 *p_body = packet->buffer + sizeof(WXCBlockHeader); /* Data receive process for each command */ switch (p_header->ack.command) { case WXC_BLOCK_COMMAND_QUIT: /* Disconnect protocol */ wxc_work->executing = FALSE; break; case WXC_BLOCK_COMMAND_INIT: /* Receive initial information (size + checksum) */ protocol->recv.length = *(u16 *)(p_body + 0); protocol->recv.checksum = *(u16 *)(p_body + 2); wxc_work->recv_total = (u16)((protocol->recv.length + wxc_work->recv_unit - 1) / wxc_work->recv_unit); wxc_work->recv_rest = wxc_work->recv_total; wxc_work->req.index = 0; /* Transition to WXC_BLOCK_COMMAND_DONE if size is 0 */ if (wxc_work->recv_total > 0) { wxc_work->req.command = WXC_BLOCK_COMMAND_SEND; } else { wxc_work->req.command = WXC_BLOCK_COMMAND_DONE; } WXC_PACKET_LOG(" INIT(%6d)\n", protocol->recv.length); break; case WXC_BLOCK_COMMAND_SEND: /* Store the received data of an actual response */ WXCi_MergeBlockData(protocol, p_header->ack.index, p_body); break; } } /* Data exchange completed in both directions */ if ((p_header->ack.phase == wxc_work->req.phase) && (p_header->ack.command == WXC_BLOCK_COMMAND_DONE) && (wxc_work->ack.command == WXC_BLOCK_COMMAND_DONE)) { /* Increment data exchange phase and reinitialize */ ++wxc_work->req.phase; /* Have so that it will become !executing if the communication is continued */ wxc_work->req.command = WXC_BLOCK_COMMAND_QUIT; ret = TRUE; } } return ret; } /*---------------------------------------------------------------------------* Name: WXCi_InitSequence Description: Reinitializes the WXC library protocol. Arguments: protocol: WXCProtocolContext structure send_max: Maximum send packet size recv_max: Maximum receive packet size Returns: None. *---------------------------------------------------------------------------*/ void WXCi_InitSequence(WXCProtocolContext * protocol, u16 send_max, u16 recv_max) { WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work; /* Initialize send buffer */ protocol->send.buffer = NULL; protocol->send.length = 0; protocol->send.checksum = 0; protocol->recv.buffer = NULL; protocol->recv.length = 0; protocol->recv.buffer_max = 0; /* Calculate the split size for the block transfer */ wxc_work->send_unit = (u16)(send_max - sizeof(WXCBlockHeader)); wxc_work->recv_unit = (u16)(recv_max - sizeof(WXCBlockHeader)); /* Initialize the send management information */ { int i; for (i = 0; i < WXC_RECENT_SENT_LIST_MAX; ++i) { wxc_work->recent_index[i] = 0; } } /* Initialize the data receive management information */ wxc_work->req.phase = 0; wxc_work->recv_total = 0; /* * Initialize this so that if communication is started without even calling the AddData function, the !IsExecuting function will become true * */ wxc_work->req.command = WXC_BLOCK_COMMAND_QUIT; /* * If this is done for the ACK signal to the communication partner, however, the process will shut down immediately. As a result, set IDLE (no response) * */ wxc_work->ack.phase = 0; wxc_work->ack.command = WXC_BLOCK_COMMAND_IDLE; MI_CpuClear32(wxc_work->recv_bitmap_buf, sizeof(wxc_work->recv_bitmap_buf)); wxc_work->executing = TRUE; } /*---------------------------------------------------------------------------* Name: WXCi_AddData Description: Configures the block data exchange. Arguments: protocol: WXCProtocolContext structure send_buf: Send buffer send_size: Send buffer size recv_buf: Receive buffer recv_max: Receive buffer size Returns: If registration is possible, return TRUE after configuration. *---------------------------------------------------------------------------*/ BOOL WXCi_AddData(WXCProtocolContext * protocol, const void *send_buf, u32 send_size, void *recv_buf, u32 recv_max) { WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work; if (wxc_work->req.command == WXC_BLOCK_COMMAND_QUIT) { wxc_work->req.command = WXC_BLOCK_COMMAND_INIT; protocol->send.buffer = (void *)send_buf; protocol->send.length = (u16)send_size; protocol->send.checksum = MATH_CalcChecksum8(send_buf, send_size); protocol->recv.buffer = recv_buf; protocol->recv.buffer_max = (u16)recv_max; MI_CpuClear32(wxc_work->recv_bitmap_buf, sizeof(wxc_work->recv_bitmap_buf)); return TRUE; } else { return FALSE; } } /*---------------------------------------------------------------------------* Name: WXCi_IsExecuting Description: Checks whether data is currently being exchanged. Arguments: None. Returns: Return TRUE if data is currently being exchanged. *---------------------------------------------------------------------------*/ BOOL WXCi_IsExecuting(WXCProtocolContext * protocol) { WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work; return wxc_work->executing; }