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