1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WXC - libraries -
3   File:     wxc_protocol_impl_wxc.c
4 
5   Copyright 2005-2009 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-12-16#$
14   $Rev: 9661 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 #include <nitro.h>
19 
20 #include <nitro/wxc/common.h>
21 #include <nitro/wxc/protocol.h>
22 #include <nitro/wxc/wxc_protocol_impl_wxc.h>
23 
24 
25 /*****************************************************************************/
26 /* Declaration */
27 
28 static void WXCi_BeaconSendHook(WXCProtocolContext * protocol, WMParentParam *p_param);
29 static BOOL WXCi_BeaconRecvHook(WXCProtocolContext * protocol, const WMBssDesc *p_desc);
30 static void WXCi_PacketSendHook(WXCProtocolContext * protocol, WXCPacketInfo * packet);
31 static BOOL WXCi_PacketRecvHook(WXCProtocolContext * protocol, const WXCPacketInfo * packet);
32 static void WXCi_InitSequence(WXCProtocolContext * protocol, u16 send_max, u16 recv_max);
33 static BOOL WXCi_AddData(WXCProtocolContext * protocol, const void *send_buf, u32 send_size,
34                          void *recv_buf, u32 recv_max);
35 static BOOL WXCi_IsExecuting(WXCProtocolContext * protocol);
36 
37 
38 /*****************************************************************************/
39 /* Variables */
40 
41 /* Work buffer for WXC protocol */
42 static WXCImplWorkWxc impl_wxc_work;
43 
44 /* WXC protocol interface */
45 static WXCProtocolImpl impl_wxc = {
46     "WXC",
47     WXCi_BeaconSendHook,
48     WXCi_BeaconRecvHook,
49     NULL,
50     WXCi_PacketSendHook,
51     WXCi_PacketRecvHook,
52     WXCi_InitSequence,
53     WXCi_AddData,
54     WXCi_IsExecuting,
55     &impl_wxc_work,
56 };
57 
58 
59 /*****************************************************************************/
60 /* Functions */
61 
62 /*---------------------------------------------------------------------------*
63   Name:         WXCi_GetProtocolImplWXC
64 
65   Description:  Gets the interface for the WXC chance encounter communication protocol.
66 
67   Arguments:    None.
68 
69   Returns:      None.
70  *---------------------------------------------------------------------------*/
WXCi_GetProtocolImplWXC(void)71 WXCProtocolImpl* WXCi_GetProtocolImplWXC(void)
72 {
73     return &impl_wxc;
74 }
75 
76 /*---------------------------------------------------------------------------*
77   Name:         WXCi_BeaconSendHook
78 
79   Description:  Hook called at beacon update.
80 
81   Arguments:    protocol: WXCProtocolContext structure
82                 p_param: WMParentParam structure used for next beacon
83                               Change inside the function as necessary.
84 
85   Returns:      None.
86  *---------------------------------------------------------------------------*/
WXCi_BeaconSendHook(WXCProtocolContext * protocol,WMParentParam * p_param)87 void WXCi_BeaconSendHook(WXCProtocolContext * protocol, WMParentParam *p_param)
88 {
89 #pragma unused(protocol)
90 #pragma unused(p_param)
91 
92     /*
93      * UserGameInfo is not currently used in the WXC library.
94      * This is planned to be extended as necessary in the future when GGID net masking, common GGID mode, and other features are adopted.
95      *
96      */
97 }
98 
99 /*---------------------------------------------------------------------------*
100   Name:         WXCi_BeaconRecvHook
101 
102   Description:  Hook called for individual scanned beacons.
103 
104   Arguments:    protocol: WXCProtocolContext structure
105                 p_desc: Scanned WMBssDesc structure
106 
107   Returns:      If it is seen as connection target, return TRUE. Otherwise, return FALSE.
108  *---------------------------------------------------------------------------*/
WXCi_BeaconRecvHook(WXCProtocolContext * protocol,const WMBssDesc * p_desc)109 BOOL WXCi_BeaconRecvHook(WXCProtocolContext * protocol, const WMBssDesc *p_desc)
110 {
111 #pragma unused(protocol)
112 #pragma unused(p_desc)
113 
114     /* Only the "local mode," which distinguishes only based on GGID */
115 
116     return TRUE;
117 }
118 
119 /*---------------------------------------------------------------------------*
120   Name:         WXCi_PacketSendHook
121 
122   Description:  Hook called at MP packet transmission.
123 
124   Arguments:    protocol: WXCProtocolContext structure
125                 packet: WXCPacketInfo pointer configuring transmission packet information
126 
127   Returns:      None.
128  *---------------------------------------------------------------------------*/
WXCi_PacketSendHook(WXCProtocolContext * protocol,WXCPacketInfo * packet)129 void WXCi_PacketSendHook(WXCProtocolContext * protocol, WXCPacketInfo * packet)
130 {
131     WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work;
132     WXCBlockHeader *p_header = (WXCBlockHeader *) packet->buffer;
133 
134     WXC_PACKET_LOG("--SEND:ACK=(%3d,%d,%04X),REQ=(%3d,%d,%04X)\n",
135                    wxc_work->ack.phase, wxc_work->ack.command, wxc_work->ack.index,
136                    wxc_work->req.phase, wxc_work->req.command, wxc_work->req.index);
137 
138     /* Set packet header to the send buffer */
139     p_header->req = wxc_work->req;
140     p_header->ack = wxc_work->ack;
141 
142     /* Send response data only when the phase matches */
143     if (wxc_work->ack.phase == wxc_work->req.phase)
144     {
145         u8     *p_body = packet->buffer + sizeof(WXCBlockHeader);
146 
147         switch (wxc_work->ack.command)
148         {
149         case WXC_BLOCK_COMMAND_INIT:
150             /* Send initial information (size + checksum) */
151             WXC_PACKET_LOG("       INIT(%6d)\n", protocol->send.length);
152             *(u16 *)(p_body + 0) = (u16)protocol->send.length;
153             *(u16 *)(p_body + 2) = protocol->send.checksum;
154             break;
155         case WXC_BLOCK_COMMAND_SEND:
156             /* Send last requested index */
157             {
158                 int     offset = (wxc_work->ack.index * wxc_work->send_unit);
159                 u32     len = (u32)(protocol->send.length - offset);
160                 if (len > wxc_work->send_unit)
161                 {
162                     len = wxc_work->send_unit;
163                 }
164                 MI_CpuCopy8((const u8 *)protocol->send.buffer + offset, p_body, len);
165             }
166             break;
167         }
168     }
169 
170     /* Specify packet size */
171     packet->length = (u16)MATH_ROUNDUP(sizeof(WXCBlockHeader) + wxc_work->send_unit, 2);
172 }
173 
174 /*---------------------------------------------------------------------------*
175   Name:         WXCi_MergeBlockData
176 
177   Description:  Saves the received block data fragment.
178 
179   Arguments:    protocol: WXCProtocolContext structure
180                 index: Receive data index
181                 src: Receive data buffer
182 
183   Returns:      None.
184  *---------------------------------------------------------------------------*/
WXCi_MergeBlockData(WXCProtocolContext * protocol,int index,const void * src)185 static void WXCi_MergeBlockData(WXCProtocolContext * protocol, int index, const void *src)
186 {
187     WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work;
188     if (index < wxc_work->recv_total)
189     {
190         u32    *bmp = wxc_work->recv_bitmap_buf + (index >> 5);
191         u32     bit = (u32)(1 << (index & 31));
192         if ((*bmp & bit) == 0)
193         {
194             int     offset = (index * wxc_work->recv_unit);
195             u32     len = (u32)(protocol->recv.length - offset);
196             if (len > wxc_work->recv_unit)
197             {
198                 len = wxc_work->recv_unit;
199             }
200             /* Don't save if recv.buffer is NULL */
201             if (protocol->recv.buffer != NULL)
202             {
203                 MI_CpuCopy8(src, (u8 *)protocol->recv.buffer + offset, len);
204             }
205             *bmp |= bit;
206             /* If data reception is finished, set as DONE */
207             if (--wxc_work->recv_rest == 0)
208             {
209                 wxc_work->req.command = WXC_BLOCK_COMMAND_DONE;
210             }
211             /* If not, search for the non-received index */
212             else
213             {
214                 int     i;
215                 /* Use the previously requested index as a base point */
216                 int     count = wxc_work->recent_index[0];
217                 int     last_count = count;
218                 if (last_count >= wxc_work->recv_total)
219                 {
220                     last_count = (int)wxc_work->recv_total - 1;
221                 }
222                 for (;;)
223                 {
224                     /* Loop to the beginning once the end point is reached */
225                     if (++count >= wxc_work->recv_total)
226                     {
227                         count = 0;
228                     }
229                     /* Reselect from history once the search finishes a single loop */
230                     if (count == last_count)
231                     {
232                         count = wxc_work->recent_index[WXC_RECENT_SENT_LIST_MAX - 1];
233                         break;
234                     }
235                     /* Determine if it is received yet */
236                     if ((*(wxc_work->recv_bitmap_buf + (count >> 5)) & (1 << (count & 31))) == 0)
237                     {
238                         /* Determine whether it is a recently requested index */
239                         for (i = 0; i < WXC_RECENT_SENT_LIST_MAX; ++i)
240                         {
241                             if (count == wxc_work->recent_index[i])
242                             {
243                                 break;
244                             }
245                         }
246                         if (i >= WXC_RECENT_SENT_LIST_MAX)
247                         {
248                             break;
249                         }
250                     }
251                 }
252                 /* Update the index request history */
253                 for (i = WXC_RECENT_SENT_LIST_MAX; --i > 0;)
254                 {
255                     wxc_work->recent_index[i] = wxc_work->recent_index[i - 1];
256                 }
257                 wxc_work->recent_index[0] = (u16)count;
258                 wxc_work->req.index = wxc_work->recent_index[0];
259             }
260         }
261     }
262 }
263 
264 /*---------------------------------------------------------------------------*
265   Name:         WXCi_PacketRecvHook
266 
267   Description:  Hook called at MP packet reception.
268 
269   Arguments:    protocol: WXCProtocolContext structure
270                 packet: WXCPacketInfo pointer configuring reception packet information
271 
272   Returns:      If a single data exchange is completed, return TRUE.
273  *---------------------------------------------------------------------------*/
WXCi_PacketRecvHook(WXCProtocolContext * protocol,const WXCPacketInfo * packet)274 BOOL WXCi_PacketRecvHook(WXCProtocolContext * protocol, const WXCPacketInfo * packet)
275 {
276     WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work;
277     int     ret = FALSE;
278 
279     WXCBlockHeader *p_header = (WXCBlockHeader *) packet->buffer;
280 
281     if (packet->length >= wxc_work->recv_unit)
282     {
283         WXC_PACKET_LOG("--RECV:REQ=(%3d,%d,%04X),ACK=(%3d,%d,%04X)\n",
284                        p_header->req.phase, p_header->req.command, p_header->req.index,
285                        p_header->ack.phase, p_header->ack.command, p_header->ack.index);
286 
287         /* Save requested data only for targets with a same phase */
288         if (p_header->req.phase == wxc_work->req.phase)
289         {
290             wxc_work->ack = p_header->req;
291         }
292 
293         /* View response data only for targets with a same phase */
294         if (p_header->ack.phase == wxc_work->req.phase)
295         {
296             u8     *p_body = packet->buffer + sizeof(WXCBlockHeader);
297 
298             /* Data receive process for each command */
299             switch (p_header->ack.command)
300             {
301             case WXC_BLOCK_COMMAND_QUIT:
302                 /* Disconnect protocol */
303                 wxc_work->executing = FALSE;
304                 break;
305             case WXC_BLOCK_COMMAND_INIT:
306                 /* Receive initial information (size + checksum) */
307                 protocol->recv.length = *(u16 *)(p_body + 0);
308                 protocol->recv.checksum = *(u16 *)(p_body + 2);
309                 wxc_work->recv_total =
310                     (u16)((protocol->recv.length + wxc_work->recv_unit - 1) / wxc_work->recv_unit);
311                 wxc_work->recv_rest = wxc_work->recv_total;
312                 wxc_work->req.index = 0;
313                 /* Transition to WXC_BLOCK_COMMAND_DONE if size is 0 */
314                 if (wxc_work->recv_total > 0)
315                 {
316                     wxc_work->req.command = WXC_BLOCK_COMMAND_SEND;
317                 }
318                 else
319                 {
320                     wxc_work->req.command = WXC_BLOCK_COMMAND_DONE;
321                 }
322                 WXC_PACKET_LOG("       INIT(%6d)\n", protocol->recv.length);
323                 break;
324             case WXC_BLOCK_COMMAND_SEND:
325                 /* Store the received data of an actual response */
326                 WXCi_MergeBlockData(protocol, p_header->ack.index, p_body);
327                 break;
328             }
329         }
330 
331         /* Data exchange completed in both directions */
332         if ((p_header->ack.phase == wxc_work->req.phase) &&
333             (p_header->ack.command == WXC_BLOCK_COMMAND_DONE) &&
334             (wxc_work->ack.command == WXC_BLOCK_COMMAND_DONE))
335         {
336             /* Increment data exchange phase and reinitialize */
337             ++wxc_work->req.phase;
338             /* Have so that it will become !executing if the communication is continued */
339             wxc_work->req.command = WXC_BLOCK_COMMAND_QUIT;
340             ret = TRUE;
341         }
342     }
343     return ret;
344 }
345 
346 /*---------------------------------------------------------------------------*
347   Name:         WXCi_InitSequence
348 
349   Description:  Reinitializes the WXC library protocol.
350 
351   Arguments:    protocol: WXCProtocolContext structure
352                 send_max: Maximum send packet size
353                 recv_max: Maximum receive packet size
354 
355   Returns:      None.
356  *---------------------------------------------------------------------------*/
WXCi_InitSequence(WXCProtocolContext * protocol,u16 send_max,u16 recv_max)357 void WXCi_InitSequence(WXCProtocolContext * protocol, u16 send_max, u16 recv_max)
358 {
359     WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work;
360 
361     /* Initialize send buffer */
362     protocol->send.buffer = NULL;
363     protocol->send.length = 0;
364     protocol->send.checksum = 0;
365     protocol->recv.buffer = NULL;
366     protocol->recv.length = 0;
367     protocol->recv.buffer_max = 0;
368 
369     /* Calculate the split size for the block transfer */
370     wxc_work->send_unit = (u16)(send_max - sizeof(WXCBlockHeader));
371     wxc_work->recv_unit = (u16)(recv_max - sizeof(WXCBlockHeader));
372 
373     /* Initialize the send management information */
374     {
375         int     i;
376         for (i = 0; i < WXC_RECENT_SENT_LIST_MAX; ++i)
377         {
378             wxc_work->recent_index[i] = 0;
379         }
380     }
381     /* Initialize the data receive management information */
382     wxc_work->req.phase = 0;
383     wxc_work->recv_total = 0;
384 
385     /*
386      * Initialize this so that if communication is started without even calling the AddData function, the !IsExecuting function will become true
387      *
388      */
389     wxc_work->req.command = WXC_BLOCK_COMMAND_QUIT;
390     /*
391      * 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)
392      *
393      */
394     wxc_work->ack.phase = 0;
395     wxc_work->ack.command = WXC_BLOCK_COMMAND_IDLE;
396 
397     MI_CpuClear32(wxc_work->recv_bitmap_buf, sizeof(wxc_work->recv_bitmap_buf));
398 
399     wxc_work->executing = TRUE;
400 
401 }
402 
403 /*---------------------------------------------------------------------------*
404   Name:         WXCi_AddData
405 
406   Description:  Configures the block data exchange.
407 
408   Arguments:    protocol: WXCProtocolContext structure
409                 send_buf: Send buffer
410                 send_size: Send buffer size
411                 recv_buf: Receive buffer
412                 recv_max: Receive buffer size
413 
414   Returns:      If registration is possible, return TRUE after configuration.
415  *---------------------------------------------------------------------------*/
WXCi_AddData(WXCProtocolContext * protocol,const void * send_buf,u32 send_size,void * recv_buf,u32 recv_max)416 BOOL WXCi_AddData(WXCProtocolContext * protocol, const void *send_buf, u32 send_size,
417                   void *recv_buf, u32 recv_max)
418 {
419     WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work;
420 
421     if (wxc_work->req.command == WXC_BLOCK_COMMAND_QUIT)
422     {
423         wxc_work->req.command = WXC_BLOCK_COMMAND_INIT;
424 
425         protocol->send.buffer = (void *)send_buf;
426         protocol->send.length = (u16)send_size;
427         protocol->send.checksum = MATH_CalcChecksum8(send_buf, send_size);
428 
429         protocol->recv.buffer = recv_buf;
430         protocol->recv.buffer_max = (u16)recv_max;
431         MI_CpuClear32(wxc_work->recv_bitmap_buf, sizeof(wxc_work->recv_bitmap_buf));
432         return TRUE;
433     }
434     else
435     {
436         return FALSE;
437     }
438 }
439 
440 /*---------------------------------------------------------------------------*
441   Name:         WXCi_IsExecuting
442 
443   Description:  Checks whether data is currently being exchanged.
444 
445   Arguments:    None.
446 
447   Returns:      Return TRUE if data is currently being exchanged.
448  *---------------------------------------------------------------------------*/
WXCi_IsExecuting(WXCProtocolContext * protocol)449 BOOL WXCi_IsExecuting(WXCProtocolContext * protocol)
450 {
451     WXCImplWorkWxc *wxc_work = WXC_GetCurrentBlockImpl(protocol)->impl_work;
452 
453     return wxc_work->executing;
454 }
455