1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - MB - libraries
3 File: mb_wm.c
4
5 Copyright 2007-2008 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-09-18#$
14 $Rev: 8573 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17
18
19 #include <nitro.h>
20 #include "mb_common.h"
21 #include "mb_wm.h"
22 #include "mb_child.h"
23 #include "mb_wm_base.h"
24 #include "mb_block.h"
25
26 //===========================================================================
27 // Prototype Declarations
28 //===========================================================================
29
30 static BOOL IsSendEnabled(void);
31 static void MBi_WMStateOutStartConnect(void *arg);
32 static void ChildStateOutStartMP(void *arg);
33 static void ChildPortCallback(void *arg);
34 static void StateOutMPSendToParent(void *arg);
35
36 static void MBi_WMStateOutStartConnect(void *arg);
37
38 static void MBi_WMStateOutEndMP(void *arg);
39
40 static void MBi_WMStateOutDisconnect(void *arg);
41 static void MBi_WMStateInDisconnect(void);
42
43 static void MBi_WMStateOutReset(void *arg);
44
45 static void MBi_WMSendCallback(u16 type, void *arg);
46 static void MBi_WMErrorCallback(u16 apiid, u16 error_code);
47 static void MBi_WMApiErrorCallback(u16 apiid, u16 error_code);
48
49
50 //===========================================================================
51 // Variable Declarations
52 //===========================================================================
53
54 static MBWMWork *wmWork = NULL;
55
56
57 //===========================================================================
58 // Function Definitions
59 //===========================================================================
60
61 /*---------------------------------------------------------------------------*
62 Name: MBi_WMSetBuffer
63
64 Description: Sets the buffer that MB_WM uses for MP communication.
65 You must provide only the size of MBWMWork.
66
67 Arguments: buf: Pointer to the region used as a work buffer.
68
69 Returns: None.
70 *---------------------------------------------------------------------------*/
MBi_WMSetBuffer(void * buf)71 void MBi_WMSetBuffer(void *buf)
72 {
73 SDK_NULL_ASSERT(buf);
74 SDK_ASSERT(((u32)buf & 0x1f) == 0); // Whether 32-byte aligned or not.
75
76 wmWork = (MBWMWork *) buf;
77 wmWork->start_mp_busy = 0; // Prevent multiple parent StartMP calls.
78 wmWork->mpStarted = 0;
79 wmWork->child_bitmap = 0;
80 wmWork->mpBusy = 0;
81 wmWork->endReq = 0;
82 wmWork->sendBuf = NULL;
83 wmWork->recvBuf = NULL;
84 wmWork->mpCallback = NULL;
85 }
86
87
88 /*---------------------------------------------------------------------------*
89 Name: MBi_WMSetCallback
90
91 Description: Sets a callback.
92
93 Arguments: callback: Callback function.
94
95 Returns: None.
96 *---------------------------------------------------------------------------*/
MBi_WMSetCallback(MBWMCallbackFunc callback)97 void MBi_WMSetCallback(MBWMCallbackFunc callback)
98 {
99 OSIntrMode enabled = OS_DisableInterrupts();
100
101 wmWork->mpCallback = callback;
102
103 (void)OS_RestoreInterrupts(enabled);
104 }
105
106
107 /*---------------------------------------------------------------------------*
108 Name: MBi_WMStartConnect
109
110 Description: Begins a connection to a parent device.
111
112 Arguments: bssDesc: BssDesc of the parent device to connect.
113
114 Returns: None.
115 *---------------------------------------------------------------------------*/
MBi_WMStartConnect(WMBssDesc * bssDesc)116 void MBi_WMStartConnect(WMBssDesc *bssDesc)
117 {
118 WMErrCode result;
119
120 wmWork->mpStarted = 0;
121 wmWork->endReq = 0;
122
123 wmWork->sendBufSize = (u16)WM_SIZE_MP_CHILD_SEND_BUFFER(bssDesc->gameInfo.childMaxSize, FALSE);
124 wmWork->recvBufSize =
125 (u16)WM_SIZE_MP_CHILD_RECEIVE_BUFFER(bssDesc->gameInfo.parentMaxSize, FALSE);
126 wmWork->pSendLen = bssDesc->gameInfo.parentMaxSize;
127 wmWork->pRecvLen = bssDesc->gameInfo.childMaxSize;
128 wmWork->blockSizeMax = (u16)MB_COMM_CALC_BLOCK_SIZE(wmWork->pSendLen);
129 MBi_SetChildMPMaxSize(wmWork->pRecvLen);
130
131 result = WM_StartConnect(MBi_WMStateOutStartConnect, bssDesc, NULL);
132
133 if (result != WM_ERRCODE_OPERATING)
134 {
135 MBi_WMSendCallback(MB_CALLBACK_CONNECT_FAILED, NULL);
136 }
137 }
138
139
140 /*---------------------------------------------------------------------------*
141 Name: MBi_WMStateOutStartConnect
142
143 Description: Connection callback to the parent.
144
145 Arguments: arg: WM_StartConnect callback argument.
146
147 Returns: None.
148 *---------------------------------------------------------------------------*/
MBi_WMStateOutStartConnect(void * arg)149 static void MBi_WMStateOutStartConnect(void *arg)
150 {
151 WMStartConnectCallback *cb = (WMStartConnectCallback *)arg;
152
153 if (cb->errcode != WM_ERRCODE_SUCCESS)
154 {
155 MBi_WMSendCallback(MB_CALLBACK_CONNECT_FAILED, arg);
156 return;
157 }
158
159 switch (cb->state)
160 {
161 case WM_STATECODE_BEACON_LOST:
162 break;
163 case WM_STATECODE_CONNECT_START:
164 break;
165 case WM_STATECODE_DISCONNECTED:
166 MBi_WMSendCallback(MB_CALLBACK_DISCONNECTED_FROM_PARENT, NULL);
167 break;
168 case WM_STATECODE_DISCONNECTED_FROM_MYSELF:
169 // Do nothing if it disconnects itself.
170 break;
171 case WM_STATECODE_CONNECTED:
172 // When authentication is complete.
173 MBi_WMSendCallback(MB_CALLBACK_CONNECTED_TO_PARENT, arg);
174 break;
175 }
176 }
177
178
179 /*---------------------------------------------------------------------------*
180 Name: MBi_ChildStartMP
181
182 Description: Start MP communication
183
184 Arguments: sendBuf: Pointer to the region to set as the send buffer.
185 recvBuf: Pointer to the region to set as the receive buffer.
186
187 Returns: Error code, normally WM_ERRCODE_OPERATING.
188 *---------------------------------------------------------------------------*/
MBi_ChildStartMP(u16 * sendBuf,u16 * recvBuf)189 void MBi_ChildStartMP(u16 *sendBuf, u16 *recvBuf)
190 {
191 WMErrCode result;
192
193 wmWork->sendBuf = (u32 *)sendBuf;
194 wmWork->recvBuf = (u32 *)recvBuf;
195
196 result = WM_SetPortCallback(WM_PORT_BT, ChildPortCallback, NULL);
197 if (result != WM_ERRCODE_SUCCESS)
198 {
199 MBi_WMApiErrorCallback(WM_APIID_START_MP, result);
200 return;
201 }
202
203 result = WM_StartMPEx(ChildStateOutStartMP, recvBuf, wmWork->recvBufSize, sendBuf, wmWork->sendBufSize, 1, // mpFreq
204 0, // defaultRetryCount
205 FALSE, // minPollBmpMode
206 FALSE, // singlePacketMode
207 TRUE, // fixFrameMode
208 TRUE); // ignoreFatalError
209
210 if (result != WM_ERRCODE_OPERATING)
211 {
212 MBi_WMApiErrorCallback(WM_APIID_START_MP, result);
213 }
214 }
215
216 /*---------------------------------------------------------------------------*
217 Name: ChildStateOutStartMP
218
219 Description: Child WM_StartMPEx callback function.
220
221 Arguments: arg: WM_StartMP callback argument.
222
223 Returns: Error code, normally WM_ERRCODE_OPERATING.
224 *---------------------------------------------------------------------------*/
ChildStateOutStartMP(void * arg)225 static void ChildStateOutStartMP(void *arg)
226 {
227 WMStartMPCallback *cb = (WMStartMPCallback *)arg;
228
229 if (cb->errcode != WM_ERRCODE_SUCCESS)
230 {
231 // End when the error notification does not require error handling.
232 if (cb->errcode == WM_ERRCODE_SEND_FAILED)
233 {
234 return;
235 }
236 else if (cb->errcode == WM_ERRCODE_TIMEOUT)
237 {
238 return;
239 }
240 else if (cb->errcode == WM_ERRCODE_INVALID_POLLBITMAP)
241 {
242 return;
243 }
244
245 MBi_WMErrorCallback(cb->apiid, cb->errcode);
246 return;
247 }
248
249 switch (cb->state)
250 {
251 case WM_STATECODE_MP_START:
252 wmWork->mpStarted = 1; // Set the flag that indicates MP has started.
253 wmWork->mpBusy = 0;
254 wmWork->child_bitmap = 0;
255 MBi_WMSendCallback(MB_CALLBACK_MP_STARTED, NULL);
256 {
257 // MP send-enabled callback.
258 MBi_WMSendCallback(MB_CALLBACK_MP_SEND_ENABLE, NULL);
259 }
260 break;
261
262 case WM_STATECODE_MP_IND:
263 // None.
264 break;
265
266 case WM_STATECODE_MPACK_IND:
267 // None.
268 break;
269
270 case WM_STATECODE_MPEND_IND: // Only occurs on a parent device.
271 default:
272 MBi_WMErrorCallback(cb->apiid, WM_ERRCODE_FAILED);
273 break;
274 }
275 }
276
277 /*---------------------------------------------------------------------------*
278 Name: MBi_WMDisconnect
279
280 Description: Child MP disconnect processing. Disconnects from the parent after WM_EndMP completes.
281
282 Arguments: None.
283
284 Returns: None.
285 *---------------------------------------------------------------------------*/
MBi_WMDisconnect(void)286 void MBi_WMDisconnect(void)
287 {
288 WMErrCode result;
289
290 wmWork->endReq = 1;
291
292 result = WM_EndMP(MBi_WMStateOutEndMP);
293
294 if (result != WM_ERRCODE_OPERATING)
295 {
296 wmWork->endReq = 0;
297 MBi_WMApiErrorCallback(WM_APIID_END_MP, result);
298 }
299 }
300
301
302 /*---------------------------------------------------------------------------*
303 Name: MBi_WMStateOutEndMP
304
305 Description: The callback function for WM_EndMP.
306
307 Arguments: arg: The callback argument for WM_EndMP.
308
309 Returns: None.
310 *---------------------------------------------------------------------------*/
MBi_WMStateOutEndMP(void * arg)311 static void MBi_WMStateOutEndMP(void *arg)
312 {
313 WMCallback *cb = (WMCallback *)arg;
314
315 if (cb->errcode != WM_ERRCODE_SUCCESS)
316 {
317 wmWork->endReq = 0;
318 MBi_WMErrorCallback(cb->apiid, cb->errcode);
319 return;
320 }
321
322 wmWork->mpStarted = 0;
323 MBi_WMStateInDisconnect();
324 }
325
326
327 /*---------------------------------------------------------------------------*
328 Name: MBi_WMStateInDisconnect
329
330 Description: Disconnects a child from the parent and transitions to the IDLE state.
331
332 Arguments: None.
333
334 Returns: None.
335 *---------------------------------------------------------------------------*/
MBi_WMStateInDisconnect(void)336 static void MBi_WMStateInDisconnect(void)
337 {
338 WMErrCode result;
339
340 result = WM_Disconnect(MBi_WMStateOutDisconnect, 0);
341
342 if (result != WM_ERRCODE_OPERATING)
343 {
344 wmWork->endReq = 0;
345 MBi_WMApiErrorCallback(WM_APIID_DISCONNECT, result);
346 }
347 }
348
349
350 /*---------------------------------------------------------------------------*
351 Name: MBi_WMStateInDisconnect
352
353 Description: WM_Disconnect callback argument.
354
355 Arguments: arg: WM_Disconnect callback argument.
356
357 Returns: None.
358 *---------------------------------------------------------------------------*/
MBi_WMStateOutDisconnect(void * arg)359 static void MBi_WMStateOutDisconnect(void *arg)
360 {
361 WMCallback *cb = (WMCallback *)arg;
362
363 wmWork->endReq = 0;
364 if (cb->errcode != WM_ERRCODE_SUCCESS)
365 {
366 MBi_WMErrorCallback(cb->apiid, cb->errcode);
367 return;
368 }
369 MBi_WMSendCallback(MB_CALLBACK_DISCONNECT_COMPLETE, NULL);
370 }
371
372
373 /*---------------------------------------------------------------------------*
374 Name: MBi_WMReset
375
376 Description: Resets the child, and causes a transition to the IDLE state.
377
378 Arguments: None.
379
380 Returns: None.
381 *---------------------------------------------------------------------------*/
MBi_WMReset(void)382 void MBi_WMReset(void)
383 {
384 WMErrCode result;
385
386 result = WM_Reset(MBi_WMStateOutReset);
387 if (result != WM_ERRCODE_OPERATING)
388 {
389 MBi_WMApiErrorCallback(WM_APIID_RESET, result);
390 }
391 }
392
393
394 /*---------------------------------------------------------------------------*
395 Name: MBi_WMStateOutReset
396
397 Description: Resets the child, and causes a transition to the IDLE state.
398
399 Arguments: None.
400
401 Returns: None.
402 *---------------------------------------------------------------------------*/
MBi_WMStateOutReset(void * arg)403 static void MBi_WMStateOutReset(void *arg)
404 {
405 WMCallback *cb = (WMCallback *)arg;
406
407 if (cb->errcode != WM_ERRCODE_SUCCESS)
408 {
409 MBi_WMErrorCallback(cb->apiid, cb->errcode);
410 return;
411 }
412 // Reset sets to the idling (standby) state without starting the next state.
413 MBi_WMSendCallback(MB_CALLBACK_DISCONNECT_COMPLETE, NULL);
414 }
415
416
417 /*
418 * Check MP transmit permission
419
420 Added the mpBusy flag, which is set when SetMP is executed, to the determination elements, so that MP will not be set again after SetMP and before the callback returns.
421
422
423 */
424 /*---------------------------------------------------------------------------*
425 Name: IsSendEnabled
426
427 Description: This function determines whether or not it is OK to set new MP data at the present time.
428 Added the mpBusy flag, which is set when SetMP is executed, to the determination elements, so that MP will not be set again after SetMP and before the callback returns.
429
430
431 Arguments: None.
432
433 Returns: TRUE if it is OK to set new data.
434 Otherwise returns FALSE.
435 *---------------------------------------------------------------------------*/
IsSendEnabled(void)436 static BOOL IsSendEnabled(void)
437 {
438 return (wmWork->mpStarted == 1) && (wmWork->mpBusy == 0) && (wmWork->endReq == 0);
439 }
440
441
442 /*---------------------------------------------------------------------------*
443 Name: ChildPortCallback
444
445 Description: Child MP port callback function.
446
447 Arguments: arg: Port callback argument for MP communication.
448
449 Returns: None.
450 *---------------------------------------------------------------------------*/
ChildPortCallback(void * arg)451 static void ChildPortCallback(void *arg)
452 {
453 WMPortRecvCallback *cb = (WMPortRecvCallback *)arg;
454
455 if (cb->errcode != WM_ERRCODE_SUCCESS)
456 {
457 return;
458 }
459
460 switch (cb->state)
461 {
462 case WM_STATECODE_PORT_RECV:
463 // Notify the program that data was received.
464 MBi_WMSendCallback(MB_CALLBACK_MP_CHILD_RECV, cb);
465 break;
466 case WM_STATECODE_CONNECTED:
467 // Connection notification
468 break;
469 case WM_STATECODE_PORT_INIT:
470 case WM_STATECODE_DISCONNECTED:
471 case WM_STATECODE_DISCONNECTED_FROM_MYSELF:
472 break;
473 }
474 }
475
476
477 /*---------------------------------------------------------------------------*
478 Name: MBi_MPSendToParent
479
480 Description: Sends buffer contents to the parent.
481
482 Arguments: body_len: Data size.
483 pollbmp: Poll bitmap of the other party (irrelevant for a child).
484 sendbuf: Pointer to send data.
485 Returns: If send processing started successfully, returns WM_ERRCODE_OPERATING. If it failed, some other code is returned.
486
487 *---------------------------------------------------------------------------*/
MBi_MPSendToParent(u32 body_len,u16 pollbmp,u32 * sendbuf)488 WMErrCode MBi_MPSendToParent(u32 body_len, u16 pollbmp, u32 *sendbuf)
489 {
490 WMErrCode result;
491
492 // 32 byte align check
493 SDK_ASSERT(((u32)sendbuf & 0x1F) == 0);
494
495 DC_FlushRange(sendbuf, sizeof(body_len));
496 DC_WaitWriteBufferEmpty();
497
498 if (!IsSendEnabled())
499 {
500 return WM_ERRCODE_FAILED;
501 }
502
503 result = WM_SetMPDataToPort(StateOutMPSendToParent,
504 (u16 *)sendbuf,
505 (u16)body_len, pollbmp, WM_PORT_BT, WM_PRIORITY_LOW);
506 if (result != WM_ERRCODE_OPERATING)
507 {
508 return result;
509 }
510
511 wmWork->mpBusy = 1;
512 return WM_ERRCODE_OPERATING;
513 }
514
515
516 /*---------------------------------------------------------------------------*
517 Name: StateOutMPSendToParent
518
519 Description: Notification callback for a completed MP transmission.
520
521 Arguments: arg: WM_SetMPDataToPort callback argument.
522
523 Returns: None.
524 *---------------------------------------------------------------------------*/
StateOutMPSendToParent(void * arg)525 static void StateOutMPSendToParent(void *arg)
526 {
527 WMCallback *cb = (WMCallback *)arg;
528
529 wmWork->mpBusy = 0;
530 if (cb->errcode == WM_ERRCODE_SUCCESS)
531 {
532 MBi_WMSendCallback(MB_CALLBACK_MP_CHILD_SENT, arg);
533 }
534 else if (cb->errcode == WM_ERRCODE_TIMEOUT)
535 {
536 MBi_WMSendCallback(MB_CALLBACK_MP_CHILD_SENT_TIMEOUT, arg);
537 }
538 else
539 {
540 MBi_WMSendCallback(MB_CALLBACK_MP_CHILD_SENT_ERR, arg);
541 }
542 // Allow the next transmission.
543 MBi_WMSendCallback(MB_CALLBACK_MP_SEND_ENABLE, NULL);
544 }
545
546
547 /*---------------------------------------------------------------------------*
548 Name: MBi_WMSendCallback
549
550 Description: Performs callback notification in the WM layer.
551
552 Arguments: type The callback type
553 arg : Callback argument
554
555 Returns: None.
556 *---------------------------------------------------------------------------*/
MBi_WMSendCallback(u16 type,void * arg)557 static inline void MBi_WMSendCallback(u16 type, void *arg)
558 {
559 if (wmWork->mpCallback == NULL)
560 {
561 return;
562 }
563 wmWork->mpCallback(type, arg);
564 }
565
566 /*---------------------------------------------------------------------------*
567 Name: MBi_WMErrorCallback
568
569 Description: Performs error notification in the WM layer.
570
571 Arguments: apiid: WM_APIID that was the cause.
572 error_code Error code
573
574 Returns: None.
575 *---------------------------------------------------------------------------*/
MBi_WMErrorCallback(u16 apiid,u16 error_code)576 static inline void MBi_WMErrorCallback(u16 apiid, u16 error_code)
577 {
578 MBErrorCallback arg;
579
580 if (wmWork->mpCallback == NULL)
581 {
582 return;
583 }
584
585 arg.apiid = apiid;
586 arg.errcode = error_code;
587
588 wmWork->mpCallback(MB_CALLBACK_ERROR, &arg);
589 }
590
591 /*---------------------------------------------------------------------------*
592 Name: MBi_WMApiErrorCallback
593
594 Description: Performs a notification when an error occurs with the return value of a WM API call.
595
596 Arguments: apiid: WM_APIID that was the cause.
597 error_code Error code
598
599 Returns: None.
600 *---------------------------------------------------------------------------*/
MBi_WMApiErrorCallback(u16 apiid,u16 error_code)601 static inline void MBi_WMApiErrorCallback(u16 apiid, u16 error_code)
602 {
603 MBErrorCallback arg;
604
605 if (wmWork->mpCallback == NULL)
606 {
607 return;
608 }
609
610 arg.apiid = apiid;
611 arg.errcode = error_code;
612
613 wmWork->mpCallback(MB_CALLBACK_API_ERROR, &arg);
614 }
615
616
617 /*---------------------------------------------------------------------------*
618 Name: MBi_WMApiErrorCallback
619
620 Description: Performs a notification when an error occurs with the return value of a WM API call.
621
622 Arguments: apiid: WM_APIID that was the cause.
623 error_code Error code
624
625 Returns: None.
626 *---------------------------------------------------------------------------*/
MBi_WMClearCallback(void)627 void MBi_WMClearCallback(void)
628 {
629 (void)WM_SetPortCallback(WM_PORT_BT, NULL, NULL);
630 }
631