1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WXC - libraries -
3   File:     wxc_driver.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/driver.h>
22 
23 
24 /*****************************************************************************/
25 /* Declaration */
26 
27 /* Error check function group */
28 static void WXCi_RecoverWmApiFailure(WXCDriverWork *, WMApiid id, WMErrCode err);
29 static BOOL WXCi_CheckWmApiResult(WXCDriverWork * driver, WMApiid id, WMErrCode err);
30 static BOOL WXCi_CheckWmCallbackResult(WXCDriverWork *, void *arg);
31 static void WXCi_ErrorQuit(WXCDriverWork *);
32 
33 /*
34  * Continuous transition procedure between wireless states.
35  * It is first called with an argument of NULL and then makes repeated callbacks to the same function.
36  * An event notification callback occurs when the intended state is reached.
37  *
38  * Note:
39  *   These functions have been designed to ultimately make threading easy, so during maintenance you should not split up individual WM function calls within these functions nor separate them into StateIn- and StateOut-.
40  *
41  *
42  */
43 static void WXCi_InitProc(void *arg);  /* (end) -> STOP             */
44 static void WXCi_StartProc(void *arg); /* STOP -> IDLE              */
45 static void WXCi_StopProc(void *arg);  /* IDLE -> STOP              */
46 static void WXCi_EndProc(void *arg);   /* STOP  -> (end)            */
47 static void WXCi_ResetProc(void *arg); /* (any) -> IDLE             */
48 static void WXCi_StartParentProc(void *arg);    /* IDLE  -> MP_PARENT        */
49 static void WXCi_StartChildProc(void *arg);     /* IDLE  -> MP_CHILD         */
50 static void WXCi_ScanProc(void *arg);  /* IDLE -> SCAN -> IDLE      */
51 static void WXCi_MeasureProc(void *arg);        /* IDLE -> (measure) -> IDLE */
52 
53 /* Status transition control */
54 static void WXCi_OnStateChanged(WXCDriverWork *, WXCDriverState state, void *arg);
55 
56 /* Other callbacks or indicators */
57 static void WXCi_IndicateCallback(void *arg);
58 static void WXCi_PortCallback(void *arg);
59 static void WXCi_MPSendCallback(void *arg);
60 static void WXCi_ParentIndicate(void *arg);
61 static void WXCi_ChildIndicate(void *arg);
62 
63 /*****************************************************************************/
64 /* Constants */
65 
66 /* After SDK 3.0 RC, it was changed so that an indicator is generated even when disconnecting itself */
67 #define VERSION_TO_INT(major, minor, relstep) \
68     (((major) << 24) | ((minor) << 16) | ((relstep) << 0))
69 #if VERSION_TO_INT(SDK_VERSION_MAJOR, SDK_VERSION_MINOR, SDK_VERSION_RELSTEP) < VERSION_TO_INT(3, 0, 20100)
70 #define WM_STATECODE_DISCONNECTED_FROM_MYSELF ((WMStateCode)26)
71 #endif
72 
73 
74 /*****************************************************************************/
75 /* Variables */
76 
77 /*
78  * Work memory for the wireless driver
79  * - This variable has been provided to use as "this" only in WM callbacks.
80  *   (Normally, WXCDriverWork is taken as an argument to specify the invocation target whenever possible.)
81  * - Because directly referencing a global pointer causes it to be treated as semi-volatile and is inefficient, it is better to temporarily copy this pointer into a local variable in functions that use it frequently.
82  *
83  */
84 static WXCDriverWork *work;
85 
86 
87 /*****************************************************************************/
88 /* Functions */
89 
90 /*---------------------------------------------------------------------------*
91   Name:         WXCi_ErrorQuit
92 
93   Description:  Reset operation when an error is detected.
94 
95   Arguments:    driver: WXCDriverWork structure
96 
97   Returns:      None.
98  *---------------------------------------------------------------------------*/
WXCi_ErrorQuit(WXCDriverWork * driver)99 static void WXCi_ErrorQuit(WXCDriverWork * driver)
100 {
101     /* It usually becomes an unusual finish operation, so BUSY is ignored */
102     if (driver->state == WXC_DRIVER_STATE_BUSY)
103     {
104         driver->state = driver->target;
105     }
106     WXCi_End(driver);
107 }
108 
109 /*---------------------------------------------------------------------------*
110   Name:         WXCi_RecoverWmApiFailure
111 
112   Description:  Attempts to recover from the WM function's error.
113 
114   Arguments:    driver: WXCDriverWork structure
115                 id: WM function types
116                 err: Error code returned from the function
117 
118   Returns:      None.
119  *---------------------------------------------------------------------------*/
WXCi_RecoverWmApiFailure(WXCDriverWork * driver,WMApiid id,WMErrCode err)120 static void WXCi_RecoverWmApiFailure(WXCDriverWork * driver, WMApiid id, WMErrCode err)
121 {
122     /* Just in case, success is also determined here */
123     if (err == WM_ERRCODE_SUCCESS)
124     {
125         return;
126     }
127 
128     switch (id)
129     {
130     default:
131         /* Functions which should not be used in WXC */
132         OS_TWarning("WXC library error (unknown WM API : %d)\n", id);
133         WXCi_ErrorQuit(driver);
134         break;
135 
136     case WM_APIID_ENABLE:
137     case WM_APIID_POWER_ON:
138     case WM_APIID_POWER_OFF:
139     case WM_APIID_DISABLE:
140     case WM_APIID_RESET:
141         /* Ends if it failed to even initialize */
142         WXCi_ErrorQuit(driver);
143         break;
144 
145     case WM_APIID_MEASURE_CHANNEL:
146     case WM_APIID_SET_P_PARAM:
147     case WM_APIID_START_PARENT:
148     case WM_APIID_START_MP:
149     case WM_APIID_START_SCAN_EX:
150     case WM_APIID_END_SCAN:
151     case WM_APIID_DISCONNECT:
152         /* Ends when an unexpected failure occurs with major status transition functions */
153         WXCi_ErrorQuit(driver);
154         break;
155 
156     case WM_APIID_START_CONNECT:
157         /* Connection failure when StartConnect ends is possible, so it goes to IDLE again */
158         if ((err == WM_ERRCODE_FAILED) ||
159             (err == WM_ERRCODE_NO_ENTRY) || (err == WM_ERRCODE_OVER_MAX_ENTRY))
160         {
161             /* Only for this moment, BUSY is released */
162             driver->state = WXC_DRIVER_STATE_CHILD;
163             WXCi_Reset(driver);
164         }
165         /* Everything else is determined as a fatal error, and it ends */
166         else
167         {
168             WXCi_ErrorQuit(driver);
169         }
170         break;
171 
172     case WM_APIID_INDICATION:
173         /* Ends when a fatal notification such as FIFO_ERROR or FLASH_ERROR is received */
174         WXCi_ErrorQuit(driver);
175         break;
176 
177     case WM_APIID_SET_MP_DATA:
178     case WM_APIID_PORT_SEND:
179         /*
180          * The following are cases in which SetMPData fails.
181          *   ILLEGAL_STATE,INVALID_PARAM,FIFO_ERROR: Always
182          *   NO_CHILD: When the function is called
183          *   SEND_QUEUE_FULL,SEND_FAILED: During a callback
184          * This problem is resolved by a retry and is ignored.
185          */
186         break;
187 
188     }
189 }
190 
191 /*---------------------------------------------------------------------------*
192   Name:         WXCi_CheckWmApiResult
193 
194   Description:  Determines the call return value of WM functions.
195 
196   Arguments:    driver: WXCDriverWork Structure
197                 id: WM function types
198                 err: Error code returned from the function
199 
200   Returns:      If WM_ERRCODE_SUCCESS: TRUE.
201                 Otherwise, output error: FALSE.
202  *---------------------------------------------------------------------------*/
WXCi_CheckWmApiResult(WXCDriverWork * driver,WMApiid id,WMErrCode err)203 static BOOL WXCi_CheckWmApiResult(WXCDriverWork * driver, WMApiid id, WMErrCode err)
204 {
205     BOOL    ret = WXC_CheckWmApiResult(id, err);
206     /* Return operation for each API when there is an error */
207     if (!ret)
208     {
209         WXCi_RecoverWmApiFailure(driver, id, err);
210     }
211     return ret;
212 }
213 
214 /*---------------------------------------------------------------------------*
215   Name:         WXCi_CheckWmCallbackResult
216 
217   Description:  Determines the return value of WM callbacks.
218 
219   Arguments:    driver: WXCDriverWork structure
220                 arg: Argument returned from the function
221 
222   Returns:      If WM_ERRCODE_SUCCESS: TRUE.
223                 Otherwise, output error: FALSE.
224  *---------------------------------------------------------------------------*/
WXCi_CheckWmCallbackResult(WXCDriverWork * driver,void * arg)225 static BOOL WXCi_CheckWmCallbackResult(WXCDriverWork * driver, void *arg)
226 {
227     BOOL    ret = WXC_CheckWmCallbackResult(arg);
228     /* Return operation for each API when there is an error */
229     if (!ret)
230     {
231         const WMCallback *cb = (const WMCallback *)arg;
232         WXCi_RecoverWmApiFailure(driver, (WMApiid)cb->apiid, (WMErrCode)cb->errcode);
233     }
234     return ret;
235 }
236 
237 /*---------------------------------------------------------------------------*
238   Name:         WXCi_CallDriverEvent
239 
240   Description:  Notifies of a wireless driver event.
241 
242   Arguments:    driver: WXCDriverWork Structure
243                 event: Notified event
244                 arg: Function assigned to each event
245 
246   Returns:      u32 event result value assigned to each event.
247  *---------------------------------------------------------------------------*/
WXCi_CallDriverEvent(WXCDriverWork * driver,WXCDriverEvent event,void * arg)248 static inline u32 WXCi_CallDriverEvent(WXCDriverWork * driver, WXCDriverEvent event, void *arg)
249 {
250     u32     result = 0;
251     if (driver->callback)
252     {
253         result = (*driver->callback) (event, arg);
254     }
255     return result;
256 }
257 
258 /*---------------------------------------------------------------------------*
259   Name:         WXCi_CallSendEvent
260 
261   Description:  Callback function for the data send callback event.
262 
263   Arguments:    driver: WXCDriverWork structure
264 
265   Returns:      None.
266  *---------------------------------------------------------------------------*/
WXCi_CallSendEvent(WXCDriverWork * driver)267 static void WXCi_CallSendEvent(WXCDriverWork * driver)
268 {
269     if (!driver->send_busy)
270     {
271         /*
272          * Set information for the send packet buffer
273          * TODO:
274          * Would this be more efficient if it saved once when MP communications are established?
275          * The same process actually exists in wxc_api.c.
276          */
277         const u16 max_length = (driver->own_aid == 0) ?
278             driver->parent_param->parentMaxSize : driver->target_bss->gameInfo.childMaxSize;
279         WXCPacketInfo packet;
280         packet.bitmap = driver->peer_bitmap;
281         packet.length = max_length;
282         packet.buffer = driver->current_send_buf;
283         /* Uses the user settings on send data */
284         (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_DATA_SEND, &packet);
285         /* Send data */
286         if (packet.length <= max_length)
287         {
288             WMErrCode ret;
289             ret = WM_SetMPDataToPort(WXCi_MPSendCallback,
290                                      (u16 *)packet.buffer, packet.length,
291                                      packet.bitmap, WXC_DEFAULT_PORT, WXC_DEFAULT_PORT_PRIO);
292             driver->send_busy = WXCi_CheckWmApiResult(driver, WM_APIID_SET_MP_DATA, ret);
293         }
294     }
295 }
296 
297 /*---------------------------------------------------------------------------*
298   Name:         WXCi_OnStateChanged
299 
300   Description:  Operation when it stabilizes in the specified state.
301 
302   Arguments:    driver: WXCDriverWork structure
303                 state: Transition is the defined state
304                 arg: Argument for each event
305 
306   Returns:      u32 event result value assigned to each event.
307  *---------------------------------------------------------------------------*/
WXCi_OnStateChanged(WXCDriverWork * driver,WXCDriverState state,void * arg)308 static void WXCi_OnStateChanged(WXCDriverWork * driver, WXCDriverState state, void *arg)
309 {
310     driver->state = state;
311 
312     /* Notify the user if the current state is the transition target */
313     if (driver->target == state)
314     {
315         switch (state)
316         {
317         case WXC_DRIVER_STATE_END:
318             (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_STATE_END, NULL);
319             break;
320 
321         case WXC_DRIVER_STATE_STOP:
322             (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_STATE_STOP, NULL);
323             break;
324 
325         case WXC_DRIVER_STATE_IDLE:
326             (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_STATE_IDLE, NULL);
327             break;
328 
329         case WXC_DRIVER_STATE_PARENT:
330             driver->send_busy = FALSE;
331             (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_STATE_PARENT, NULL);
332             break;
333 
334         case WXC_DRIVER_STATE_CHILD:
335             driver->send_busy = FALSE;
336             (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_STATE_CHILD, NULL);
337             /* Here, the connection with the parent is notified */
338             driver->peer_bitmap |= (u16)(1 << 0);
339             (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_CONNECTED, arg);
340             WXCi_CallSendEvent(driver);
341             break;
342         }
343     }
344 
345     /*
346      * Otherwise, continue transitioning
347      * +-----+      +------+       +------+                     +--------+
348      * |     > Init |      > Start >      > Measure/StartParent > PARENT |
349      * |     |      |      |       |      <               Reset <        |
350      * |     |      |      |       |      |                     +--------+
351      * | END |      | STOP |       | IDLE > Scan/StartChild     > CHILD  |
352      * |     |      |      |       |      <               Reset <        |
353      * |     |      |      <  Stop <      |                     +--------+
354      * |     <  End <      <   End <      |
355      * +-----+      +------+       +------+
356      */
357     else
358     {
359         switch (state)
360         {
361 
362         case WXC_DRIVER_STATE_END:
363             WXCi_InitProc(NULL);
364             break;
365 
366         case WXC_DRIVER_STATE_STOP:
367             switch (driver->target)
368             {
369             case WXC_DRIVER_STATE_END:
370                 WXCi_EndProc(NULL);
371                 break;
372             case WXC_DRIVER_STATE_IDLE:
373             case WXC_DRIVER_STATE_PARENT:
374             case WXC_DRIVER_STATE_CHILD:
375                 WXCi_StartProc(NULL);
376                 break;
377             }
378             break;
379 
380         case WXC_DRIVER_STATE_IDLE:
381             switch (driver->target)
382             {
383             case WXC_DRIVER_STATE_END:
384             case WXC_DRIVER_STATE_STOP:
385                 WXCi_StopProc(NULL);
386                 break;
387             case WXC_DRIVER_STATE_PARENT:
388                 driver->need_measure_channel = TRUE;
389                 if (driver->need_measure_channel)
390                 {
391                     WXCi_MeasureProc(NULL);
392                 }
393                 break;
394             case WXC_DRIVER_STATE_CHILD:
395                 WXCi_ScanProc(NULL);
396                 break;
397             }
398             break;
399 
400         case WXC_DRIVER_STATE_PARENT:
401         case WXC_DRIVER_STATE_CHILD:
402             WXCi_ResetProc(NULL);
403             break;
404 
405         }
406     }
407 }
408 
409 /*---------------------------------------------------------------------------*
410   Name:         WXCi_MPSendCallback
411 
412   Description:  The callback function to WM_SetMPData.
413 
414   Arguments:    arg: Pointer to the callback structure
415 
416   Returns:      None.
417  *---------------------------------------------------------------------------*/
WXCi_MPSendCallback(void * arg)418 static void WXCi_MPSendCallback(void *arg)
419 {
420     WXCDriverWork *const driver = work;
421 
422     (void)WXCi_CheckWmCallbackResult(driver, arg);
423     driver->send_busy = FALSE;
424     if (driver->peer_bitmap != 0)
425     {
426         WXCi_CallSendEvent(driver);
427     }
428 }
429 
430 /*---------------------------------------------------------------------------*
431   Name:         WXCi_IndicateCallback
432 
433   Description:  The callback function called when Indicate occurs.
434 
435   Arguments:    arg: Pointer to the callback structure
436 
437   Returns:      None.
438  *---------------------------------------------------------------------------*/
WXCi_IndicateCallback(void * arg)439 static void WXCi_IndicateCallback(void *arg)
440 {
441     /* TODO: Can't this be integrated with CheckError? */
442     WXCDriverWork *const driver = work;
443     WMIndCallback *cb = (WMIndCallback *)arg;
444     if (cb->errcode == WM_ERRCODE_FIFO_ERROR)
445     {
446         WXC_DRIVER_LOG("WM_ERRCODE_FIFO_ERROR Indication!\n");
447         /* Unrecoverable error */
448         driver->target = WXC_DRIVER_STATE_ERROR;
449         driver->state = WXC_DRIVER_STATE_ERROR;
450     }
451 }
452 
453 /*---------------------------------------------------------------------------*
454   Name:         WXCi_PortCallback
455 
456   Description:  The reception notification to the port.
457 
458   Arguments:    arg: Pointer to the callback structure
459 
460   Returns:      None.
461  *---------------------------------------------------------------------------*/
WXCi_PortCallback(void * arg)462 static void WXCi_PortCallback(void *arg)
463 {
464     WXCDriverWork *const driver = work;
465 
466     if (WXCi_CheckWmCallbackResult(driver, arg))
467     {
468         WMPortRecvCallback *cb = (WMPortRecvCallback *)arg;
469         switch (cb->state)
470         {
471         case WM_STATECODE_PORT_RECV:
472             {
473                 WXCPacketInfo packet;
474                 packet.bitmap = (u16)(1 << cb->aid);
475                 packet.length = cb->length;
476                 packet.buffer = (u8 *)cb->data;
477                 (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_DATA_RECV, &packet);
478             }
479             break;
480         case WM_STATECODE_CONNECTED:
481             break;
482         case WM_STATECODE_DISCONNECTED_FROM_MYSELF:
483         case WM_STATECODE_DISCONNECTED:
484             WXC_DRIVER_LOG("disconnected(%02X-=%02X)\n", driver->peer_bitmap, (1 << cb->aid));
485             driver->peer_bitmap &= (u16)~(1 << cb->aid);
486             (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_DISCONNECTED,
487                                        (void *)(1 << cb->aid));
488             break;
489         }
490     }
491 }
492 
493 /*---------------------------------------------------------------------------*
494   Name:         WXCi_InitProc
495 
496   Description:  READY -> Continues transition to STOP.
497 
498   Arguments:    arg: Callback argument (specify NULL on invocation)
499 
500   Returns:      None.
501  *---------------------------------------------------------------------------*/
WXCi_InitProc(void * arg)502 static void WXCi_InitProc(void *arg)
503 {
504     WXCDriverWork *const driver = work;
505     WMCallback *cb = (WMCallback *)arg;
506 
507     if (!arg || WXCi_CheckWmCallbackResult(driver, arg))
508     {
509         WMErrCode wmResult = WM_ERRCODE_SUCCESS;
510         /* (outof) -> STOP */
511         if (!arg)
512         {
513             /* Currently, MeasureChannel only runs once at startup */
514             driver->need_measure_channel = TRUE;
515             driver->state = WXC_DRIVER_STATE_BUSY;
516             wmResult = WM_Init(driver->wm_work, driver->wm_dma);
517             (void)WXCi_CheckWmApiResult(driver, WM_APIID_INITIALIZE, wmResult);
518             wmResult = WM_Enable(WXCi_InitProc);
519             (void)WXCi_CheckWmApiResult(driver, WM_APIID_ENABLE, wmResult);
520         }
521         /* End */
522         else if (cb->apiid == WM_APIID_ENABLE)
523         {
524             /* Receive each type of notification */
525             wmResult = WM_SetIndCallback(WXCi_IndicateCallback);
526             if (WXCi_CheckWmApiResult(driver, WM_APIID_INDICATION, wmResult))
527             {
528                 /* Sets the port callback */
529                 wmResult = WM_SetPortCallback(WXC_DEFAULT_PORT, WXCi_PortCallback, NULL);
530                 if (WXCi_CheckWmApiResult(driver, WM_APIID_PORT_SEND, wmResult))
531                 {
532                     WXCi_OnStateChanged(driver, WXC_DRIVER_STATE_STOP, NULL);
533                 }
534             }
535         }
536     }
537 }
538 
539 /*---------------------------------------------------------------------------*
540   Name:         WXCi_StartProc
541 
542   Description:  STOP -> Continues transition to IDLE.
543 
544   Arguments:    arg: Callback argument (specify NULL on invocation)
545 
546   Returns:      None.
547  *---------------------------------------------------------------------------*/
WXCi_StartProc(void * arg)548 static void WXCi_StartProc(void *arg)
549 {
550     WXCDriverWork *const driver = work;
551     WMCallback *cb = (WMCallback *)arg;
552 
553     if (!arg || WXCi_CheckWmCallbackResult(driver, arg))
554     {
555         WMErrCode wmResult = WM_ERRCODE_SUCCESS;
556         /* STOP -> IDLE */
557         if (!arg)
558         {
559             driver->state = WXC_DRIVER_STATE_BUSY;
560             wmResult = WM_PowerOn(WXCi_StartProc);
561             (void)WXCi_CheckWmApiResult(driver, WM_APIID_POWER_ON, wmResult);
562         }
563         /* End */
564         else if (cb->apiid == WM_APIID_POWER_ON)
565         {
566             WXCi_OnStateChanged(driver, WXC_DRIVER_STATE_IDLE, NULL);
567         }
568     }
569 }
570 
571 /*---------------------------------------------------------------------------*
572   Name:         WXCi_StopProc
573 
574   Description:  IDLE -> Continues transition to STOP.
575 
576   Arguments:    arg: Callback argument (specify NULL on invocation)
577 
578   Returns:      None.
579  *---------------------------------------------------------------------------*/
WXCi_StopProc(void * arg)580 static void WXCi_StopProc(void *arg)
581 {
582     WXCDriverWork *const driver = work;
583     WMCallback *cb = (WMCallback *)arg;
584 
585     if (!arg || WXCi_CheckWmCallbackResult(driver, arg))
586     {
587         WMErrCode wmResult = WM_ERRCODE_SUCCESS;
588         /* IDLE -> STOP */
589         if (!arg)
590         {
591             driver->state = WXC_DRIVER_STATE_BUSY;
592             wmResult = WM_PowerOff(WXCi_StopProc);
593             (void)WXCi_CheckWmApiResult(driver, WM_APIID_POWER_OFF, wmResult);
594         }
595         /* End */
596         else if (cb->apiid == WM_APIID_POWER_OFF)
597         {
598             WXCi_OnStateChanged(driver, WXC_DRIVER_STATE_STOP, NULL);
599         }
600     }
601 }
602 
603 /*---------------------------------------------------------------------------*
604   Name:         WXCi_EndProc
605 
606   Description:  STOP -> Continues transition to READY.
607 
608   Arguments:    arg: Callback argument (specify NULL on invocation)
609 
610   Returns:      None.
611  *---------------------------------------------------------------------------*/
WXCi_EndProc(void * arg)612 static void WXCi_EndProc(void *arg)
613 {
614     WXCDriverWork *const driver = work;
615     WMCallback *cb = (WMCallback *)arg;
616 
617     if (!arg || WXCi_CheckWmCallbackResult(driver, arg))
618     {
619         WMErrCode wmResult = WM_ERRCODE_SUCCESS;
620         /* STOP -> READY */
621         if (!arg)
622         {
623             driver->state = WXC_DRIVER_STATE_BUSY;
624             wmResult = WM_Disable(WXCi_EndProc);
625             (void)WXCi_CheckWmApiResult(driver, WM_APIID_DISABLE, wmResult);
626         }
627         /* End */
628         else if (cb->apiid == WM_APIID_DISABLE)
629         {
630             /* Notification of a complete release of wireless */
631             wmResult = WM_Finish();
632             if (WXCi_CheckWmApiResult(driver, WM_APIID_END, wmResult))
633             {
634                 work = NULL;
635                 WXCi_OnStateChanged(driver, WXC_DRIVER_STATE_END, NULL);
636             }
637         }
638     }
639 }
640 
641 /*---------------------------------------------------------------------------*
642   Name:         WXCi_ResetProc
643 
644   Description:  (any) -> Continues transition to IDLE.
645 
646   Arguments:    arg: Callback argument (specify NULL on invocation)
647 
648   Returns:      None.
649  *---------------------------------------------------------------------------*/
WXCi_ResetProc(void * arg)650 static void WXCi_ResetProc(void *arg)
651 {
652     WXCDriverWork *const driver = work;
653     WMCallback *cb = (WMCallback *)arg;
654 
655     if (!arg || WXCi_CheckWmCallbackResult(driver, arg))
656     {
657         WMErrCode wmResult = WM_ERRCODE_SUCCESS;
658         /* (any) -> IDLE */
659         if (!arg)
660         {
661             driver->state = WXC_DRIVER_STATE_BUSY;
662             wmResult = WM_Reset(WXCi_ResetProc);
663             (void)WXCi_CheckWmApiResult(driver, WM_APIID_RESET, wmResult);
664         }
665         /* End */
666         else if (cb->apiid == WM_APIID_RESET)
667         {
668             driver->own_aid = 0;
669             WXCi_OnStateChanged(driver, WXC_DRIVER_STATE_IDLE, NULL);
670         }
671     }
672 }
673 
674 /*---------------------------------------------------------------------------*
675   Name:         WXCi_ParentIndicate
676 
677   Description:  Parent device's StartParent indicator.
678 
679   Arguments:    arg: Callback argument
680 
681   Returns:      None.
682  *---------------------------------------------------------------------------*/
WXCi_ParentIndicate(void * arg)683 static void WXCi_ParentIndicate(void *arg)
684 {
685     WXCDriverWork *const driver = work;
686     WMStartParentCallback *cb = (WMStartParentCallback *)arg;
687 
688     /* When making single status transitions, ignore this and continue the sequence */
689     if (cb->state == WM_STATECODE_PARENT_START)
690     {
691         WXCi_StartParentProc(arg);
692     }
693     /* Otherwise, they're indicators, so hook to wxc_api.c */
694     else if (cb->errcode == WM_ERRCODE_SUCCESS)
695     {
696         switch (cb->state)
697         {
698         case WM_STATECODE_PARENT_START:
699             break;
700         case WM_STATECODE_CONNECTED:
701             {
702                 BOOL    mp_start = (driver->peer_bitmap == 0);
703                 WXC_DRIVER_LOG("connected(%02X+=%02X)\n", driver->peer_bitmap, (1 << cb->aid));
704                 driver->peer_bitmap |= (u16)(1 << cb->aid);
705                 (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_CONNECTED, cb);
706                 /* If it's the first child device, notify the startup timing */
707                 if (mp_start)
708                 {
709                     WXCi_CallSendEvent(driver);
710                 }
711             }
712             break;
713         case WM_STATECODE_DISCONNECTED_FROM_MYSELF:
714         case WM_STATECODE_DISCONNECTED:
715             /* Disconnect notification operations were unified in PortCallback */
716             break;
717         case WM_STATECODE_BEACON_SENT:
718             (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_BEACON_SEND, driver->parent_param);
719             break;
720         }
721     }
722 }
723 
724 /*---------------------------------------------------------------------------*
725   Name:         WXCi_StartParentProc
726 
727   Description:  IDLE -> PARENT -> Continues transition to MP_PARENT.
728 
729   Arguments:    arg: Callback argument (specify NULL on invocation)
730 
731   Returns:      None.
732  *---------------------------------------------------------------------------*/
WXCi_StartParentProc(void * arg)733 static void WXCi_StartParentProc(void *arg)
734 {
735     WXCDriverWork *const driver = work;
736     WMCallback *cb = (WMCallback *)arg;
737 
738     if (!arg || WXCi_CheckWmCallbackResult(driver, arg))
739     {
740         WMErrCode wmResult = WM_ERRCODE_SUCCESS;
741         /* IDLE -> IDLE (WM_SetParentParameter) */
742         if (!arg)
743         {
744             driver->state = WXC_DRIVER_STATE_BUSY;
745             /* Updates channels and startup information */
746             driver->parent_param->channel = driver->current_channel;
747             driver->parent_param->tgid = WM_GetNextTgid();
748             WXC_DRIVER_LOG("start parent. (%2dch, TGID=%02X, GGID=%04X)\n",
749                            driver->current_channel, driver->parent_param->tgid,
750                            driver->parent_param->ggid);
751             wmResult = WM_SetParentParameter(WXCi_StartParentProc, driver->parent_param);
752             (void)WXCi_CheckWmApiResult(driver, WM_APIID_SET_P_PARAM, wmResult);
753         }
754         /* IDLE -> PARENT */
755         else if (cb->apiid == WM_APIID_SET_P_PARAM)
756         {
757             /*
758              * Because of the indicator, redirect the callback to WXCi_ParentIndicate()
759              *
760              */
761             wmResult = WM_StartParent(WXCi_ParentIndicate);
762             (void)WXCi_CheckWmApiResult(driver, WM_APIID_START_PARENT, wmResult);
763         }
764         /* PARENT -> MP_PARENT */
765         else if (cb->apiid == WM_APIID_START_PARENT)
766         {
767             /*
768              * WM_STATECODE_PARENT_START is always the only notification sent from WXCi_ParentIndicate() here
769              *
770              */
771             driver->own_aid = 0;
772             driver->peer_bitmap = 0;
773             wmResult = WM_StartMP(WXCi_StartParentProc,
774                                   (u16 *)driver->mp_recv_work, driver->recv_size_max,
775                                   (u16 *)driver->mp_send_work, driver->send_size_max,
776                                   (u16)(driver->parent_param->CS_Flag ? 0 : 1));
777             (void)WXCi_CheckWmApiResult(driver, WM_APIID_START_MP, wmResult);
778         }
779         /* End */
780         else if (cb->apiid == WM_APIID_START_MP)
781         {
782             WMStartMPCallback *cb = (WMStartMPCallback *)arg;
783             switch (cb->state)
784             {
785             case WM_STATECODE_MP_START:
786                 WXCi_OnStateChanged(driver, WXC_DRIVER_STATE_PARENT, NULL);
787                 break;
788             }
789         }
790     }
791 }
792 
793 /*---------------------------------------------------------------------------*
794   Name:         WXCi_ChildIndicate
795 
796   Description:  Child device's StartConnect indicator.
797 
798   Arguments:    arg: Callback argument
799 
800   Returns:      None.
801  *---------------------------------------------------------------------------*/
WXCi_ChildIndicate(void * arg)802 static void WXCi_ChildIndicate(void *arg)
803 {
804     WXCDriverWork *const driver = work;
805 
806     if (WXCi_CheckWmCallbackResult(driver, arg))
807     {
808         WMStartConnectCallback *cb = (WMStartConnectCallback *)arg;
809         switch (cb->state)
810         {
811         case WM_STATECODE_CONNECT_START:
812         case WM_STATECODE_BEACON_LOST:
813             break;
814 
815         case WM_STATECODE_CONNECTED:
816             /* When making status transitions, ignore this and continue the sequence */
817             if (driver->state != WXC_DRIVER_STATE_CHILD)
818             {
819                 WXCi_StartChildProc(arg);
820             }
821             break;
822 
823         case WM_STATECODE_DISCONNECTED_FROM_MYSELF:
824         case WM_STATECODE_DISCONNECTED:
825             /* If not in a transition, it resets here */
826             if (driver->state != WXC_DRIVER_STATE_BUSY)
827             {
828                 driver->target = WXC_DRIVER_STATE_PARENT;
829                 WXCi_ResetProc(NULL);
830             }
831             else
832             {
833                 driver->target = WXC_DRIVER_STATE_IDLE;
834             }
835             break;
836 
837         default:
838             WXCi_ErrorQuit(driver);
839             break;
840         }
841     }
842 }
843 
844 /*---------------------------------------------------------------------------*
845   Name:         WXCi_StartChildProc
846 
847   Description:  IDLE -> CHILD -> Continues transition to MP_CHILD.
848 
849   Arguments:    arg: Callback argument (specify NULL on invocation)
850 
851   Returns:      None.
852  *---------------------------------------------------------------------------*/
WXCi_StartChildProc(void * arg)853 static void WXCi_StartChildProc(void *arg)
854 {
855     WXCDriverWork *const driver = work;
856     WMCallback *cb = (WMCallback *)arg;
857 
858     if (!arg || WXCi_CheckWmCallbackResult(driver, arg))
859     {
860         WMErrCode wmResult = WM_ERRCODE_SUCCESS;
861         /* IDLE -> CHILD */
862         if (!arg)
863         {
864             /*
865              * Hook invocation to set the SSID and other information before connecting
866              */
867             u8      ssid_bak[WM_SIZE_BSSID];
868             MI_CpuCopy8(driver->target_bss->ssid, ssid_bak, sizeof(ssid_bak));
869             (void)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_CONNECTING, driver->target_bss);
870             MI_CpuCopy8(driver->target_bss->ssid + 8, driver->ssid, WM_SIZE_CHILD_SSID);
871             MI_CpuCopy8(ssid_bak, driver->target_bss->ssid, sizeof(ssid_bak));
872             /*
873              * Because of the indicator, redirect the callback to WXCi_ChildIndicate()
874              *
875              */
876             driver->state = WXC_DRIVER_STATE_BUSY;
877             wmResult = WM_StartConnect(WXCi_ChildIndicate, driver->target_bss, driver->ssid);
878             (void)WXCi_CheckWmApiResult(driver, WM_APIID_START_CONNECT, wmResult);
879         }
880         /* CHILD -> MP_CHILD */
881         else if (cb->apiid == WM_APIID_START_CONNECT)
882         {
883             WMStartConnectCallback *cb = (WMStartConnectCallback *)arg;
884             /*
885              * WM_STATECODE_CONNECTED is always the only notification sent from WXCi_ChildIndicate() here
886              *
887              */
888             driver->own_aid = cb->aid;
889             wmResult = WM_StartMP(WXCi_StartChildProc,
890                                   (u16 *)driver->mp_recv_work, driver->recv_size_max,
891                                   (u16 *)driver->mp_send_work, driver->send_size_max,
892                                   (u16)(driver->parent_param->CS_Flag ? 0 : 1));
893             (void)WXCi_CheckWmApiResult(driver, WM_APIID_START_MP, wmResult);
894         }
895         /* End */
896         else if (cb->apiid == WM_APIID_START_MP)
897         {
898             WMStartMPCallback *cb = (WMStartMPCallback *)arg;
899             switch (cb->state)
900             {
901             case WM_STATECODE_MP_START:
902                 WXCi_OnStateChanged(driver, WXC_DRIVER_STATE_CHILD, cb);
903                 break;
904             }
905         }
906     }
907 }
908 
909 /*---------------------------------------------------------------------------*
910   Name:         WXCi_MeasureProc
911 
912   Description:  IDLE -> (measure) -> Continues transition to IDLE.
913 
914   Arguments:    arg: Callback argument (specify NULL on invocation)
915 
916   Returns:      None.
917  *---------------------------------------------------------------------------*/
WXCi_MeasureProc(void * arg)918 static void WXCi_MeasureProc(void *arg)
919 {
920     WXCDriverWork *const driver = work;
921     WMMeasureChannelCallback *cb = (WMMeasureChannelCallback *)arg;
922     u16     channel = 0;
923 
924     /* Initializes the measurement value */
925     if (!arg)
926     {
927         driver->state = WXC_DRIVER_STATE_BUSY;
928         driver->current_channel = 0;
929         driver->measure_ratio_min = WXC_MAX_RATIO + 1;
930     }
931     else if (WXCi_CheckWmCallbackResult(driver, cb))
932         /* Measurement complete callback */
933     {
934         channel = cb->channel;
935         /* Get a channel with a lower usage rate (initial value is 101%, so be sure to select the top) */
936         if (driver->measure_ratio_min > cb->ccaBusyRatio)
937         {
938             driver->measure_ratio_min = cb->ccaBusyRatio;
939             driver->current_channel = channel;
940         }
941         /* All channels measurement completed */
942         if (channel == (32 - MATH_CountLeadingZeros(WM_GetAllowedChannel())))
943         {
944             driver->need_measure_channel = FALSE;
945             /* If PARENT is currently the target, it transitions to connection */
946             //WXCi_OnStateChanged(driver, WXC_DRIVER_STATE_IDLE, NULL);
947             WXCi_StartParentProc(NULL);
948             return;
949         }
950     }
951     /* Measurement failure (to error end) */
952     else
953     {
954         driver->need_measure_channel = FALSE;
955     }
956 
957     /* Measures all channels in order from the last */
958     if (driver->need_measure_channel)
959     {
960         /* The time interval in ms for picking up the signal for making one communication for one frame */
961         const u16 WH_MEASURE_TIME = 30;
962         /* The logical OR of the carrier sense and the ED value */
963         const u16 WH_MEASURE_CS_OR_ED = 3;
964         /* The recommended ED threshold value that has been empirically shown to be effective */
965         const u16 WH_MEASURE_ED_THRESHOLD = 17;
966         WMErrCode ret;
967 
968         channel = WXC_GetNextAllowedChannel(channel);
969         ret = WM_MeasureChannel(WXCi_MeasureProc,
970                                 WH_MEASURE_CS_OR_ED, WH_MEASURE_ED_THRESHOLD,
971                                 channel, WH_MEASURE_TIME);
972         (void)WXCi_CheckWmApiResult(driver, WM_APIID_MEASURE_CHANNEL, ret);
973     }
974 
975 }
976 
977 /*---------------------------------------------------------------------------*
978   Name:         WXCi_ScanProc
979 
980   Description:  IDLE -> SCAN -> Continues transition to IDLE.
981 
982   Arguments:    arg: Callback argument (specify NULL on invocation)
983 
984   Returns:      None.
985  *---------------------------------------------------------------------------*/
WXCi_ScanProc(void * arg)986 static void WXCi_ScanProc(void *arg)
987 {
988     WXCDriverWork *const driver = work;
989     WMCallback *cb = (WMCallback *)arg;
990 
991     static u16 scan_channelList;
992 
993     if (!arg || WXCi_CheckWmCallbackResult(driver, arg))
994     {
995         WMErrCode wmResult = WM_ERRCODE_SUCCESS;
996 
997         /* IDLE -> SCAN */
998         if (!arg)
999         {
1000             driver->state = WXC_DRIVER_STATE_BUSY;
1001             driver->scan_found_num = 0;
1002             /* Searches for all channels using the broadcast addresses */
1003             driver->scan_param->scanBuf = (WMBssDesc *)driver->scan_buf;
1004             driver->scan_param->scanBufSize = WM_SIZE_SCAN_EX_BUF;
1005 
1006             /* Set to single channel per search */
1007             scan_channelList = WM_GetAllowedChannel();
1008             driver->scan_param->channelList = (u16)MATH_GetLeastSignificantBit(scan_channelList);
1009             scan_channelList = (u16)(scan_channelList ^ MATH_GetLeastSignificantBit(scan_channelList));
1010 
1011             driver->scan_param->maxChannelTime = WXC_SCAN_TIME_MAX;
1012             MI_CpuFill8(driver->scan_param->bssid, 0xFF, sizeof(driver->scan_param->bssid));
1013             driver->scan_param->scanType = WM_SCANTYPE_PASSIVE;
1014             driver->scan_param->ssidLength = 0;
1015             MI_CpuFill8(driver->scan_param->ssid, 0xFF, sizeof(driver->scan_param->ssid));
1016             wmResult = WM_StartScanEx(WXCi_ScanProc, driver->scan_param);
1017             (void)WXCi_CheckWmApiResult(driver, WM_APIID_START_SCAN_EX, wmResult);
1018         }
1019         /* SCAN -> IDLE */
1020         else if (cb->apiid == WM_APIID_START_SCAN_EX)
1021         {
1022             WMStartScanExCallback *cb = (WMStartScanExCallback *)arg;
1023             /* Saves if the beacon is detected */
1024             if (cb->state == WM_STATECODE_PARENT_FOUND)
1025             {
1026                 DC_InvalidateRange(driver->scan_buf, WM_SIZE_SCAN_EX_BUF);
1027                 driver->scan_found_num = cb->bssDescCount;
1028             }
1029             wmResult = WM_EndScan(WXCi_ScanProc);
1030             (void)WXCi_CheckWmApiResult(driver, WM_APIID_END_SCAN, wmResult);
1031         }
1032         /* End */
1033         else if (cb->apiid == WM_APIID_END_SCAN)
1034         {
1035             BOOL    ret = FALSE;
1036             /* Determines BssDesc if the target is still CHILD */
1037             if (driver->target == WXC_DRIVER_STATE_CHILD)
1038             {
1039                 int     i;
1040                 const u8 *scan_buf = driver->scan_buf;
1041 
1042                 WXC_DRIVER_LOG("found:%d beacons\n", driver->scan_found_num);
1043                 for (i = 0; i < driver->scan_found_num; ++i)
1044                 {
1045                     const WMBssDesc *p_desc = (const WMBssDesc *)scan_buf;
1046                     const int len = p_desc->length * 2;
1047                     BOOL    is_valid;
1048                     is_valid = WM_IsValidGameBeacon(p_desc);
1049                     WXC_DRIVER_LOG("   GGID=%08X(%2dch:%3dBYTE)\n",
1050                                    is_valid ? p_desc->gameInfo.ggid : 0xFFFFFFFF,
1051                                    p_desc->channel, len);
1052                     if (is_valid)
1053                     {
1054                         /* Callback for each BssDesc */
1055                         ret =
1056                             (BOOL)WXCi_CallDriverEvent(driver, WXC_DRIVER_EVENT_BEACON_RECV,
1057                                                        (void *)p_desc);
1058                         if (ret)
1059                         {
1060                             WXC_DRIVER_LOG("     -> matched!\n");
1061                             MI_CpuCopy8(p_desc, driver->target_bss, sizeof(WMBssDesc));
1062                             break;
1063                         }
1064                     }
1065                     scan_buf += MATH_ROUNDUP(len, 4);
1066                 }
1067                 /* The target is not yet determined. Search if there is still an unsearched channel */
1068                 if((ret == FALSE)&&(MATH_GetLeastSignificantBit(scan_channelList) != 0))
1069                 {
1070                     driver->scan_found_num = 0;
1071                     driver->scan_param->channelList = (u16)MATH_GetLeastSignificantBit(scan_channelList);
1072                     scan_channelList = (u16)(scan_channelList ^ MATH_GetLeastSignificantBit(scan_channelList));
1073                     wmResult = WM_StartScanEx(WXCi_ScanProc, driver->scan_param);
1074                     (void)WXCi_CheckWmApiResult(driver, WM_APIID_START_SCAN_EX, wmResult);
1075                     return;
1076                 }
1077             }
1078             /* If there is a target, a connection is started */
1079             if (ret)
1080             {
1081                 WXCi_StartChildProc(NULL);
1082             }
1083             /* If there is no target, it selects the next mode */
1084             else
1085             {
1086                 if (driver->target == WXC_DRIVER_STATE_CHILD)
1087                 {
1088                     driver->target = WXC_DRIVER_STATE_IDLE;
1089                 }
1090                 WXCi_OnStateChanged(driver, WXC_DRIVER_STATE_IDLE, NULL);
1091             }
1092         }
1093     }
1094 }
1095 
1096 /*---------------------------------------------------------------------------*
1097   Name:         WXC_InitDriver
1098 
1099   Description:  Initializes wireless and starts the transition to IDLE.
1100 
1101   Arguments:    driver: Used as an internal work memory buffer
1102                         Pointer to WXCDriverWork structure
1103                         This must be 32-byte aligned.
1104                 pp: Parent parameters
1105                 func: Event notification callback
1106                 dma: DMA channel assigned to wireless
1107 
1108   Returns:      None.
1109  *---------------------------------------------------------------------------*/
WXC_InitDriver(WXCDriverWork * driver,WMParentParam * pp,WXCDriverEventFunc func,u32 dma)1110 void WXC_InitDriver(WXCDriverWork * driver, WMParentParam *pp, WXCDriverEventFunc func, u32 dma)
1111 {
1112     /* Gets the first TGID outside of the interrupt handler */
1113     {
1114         OSIntrMode bak_cpsr = OS_EnableInterrupts();
1115         (void)WM_GetNextTgid();
1116         (void)OS_RestoreInterrupts(bak_cpsr);
1117     }
1118     /* Work variable initialization */
1119     work = driver;
1120     MI_CpuClear32(driver, sizeof(WXCDriverWork));
1121     driver->own_aid = 0;
1122     driver->send_busy = TRUE;
1123     driver->callback = func;
1124     driver->wm_dma = (u16)dma;
1125     driver->send_size_max = (u16)sizeof(driver->mp_send_work);
1126     driver->recv_size_max = (u16)sizeof(driver->mp_recv_work);
1127     driver->state = WXC_DRIVER_STATE_END;
1128     driver->parent_param = pp;
1129     driver->parent_param->entryFlag = 1;
1130     driver->parent_param->beaconPeriod = WXC_BEACON_PERIOD;
1131     driver->parent_param->channel = 1;
1132 }
1133 
1134 /*---------------------------------------------------------------------------*
1135   Name:         WXC_SetDriverTarget
1136 
1137   Description:  Starts transition of a special status to the target.
1138 
1139   Arguments:    driver: WXCDriverWork Structure
1140                 target: State of the transition target
1141 
1142   Returns:      None.
1143  *---------------------------------------------------------------------------*/
WXC_SetDriverTarget(WXCDriverWork * driver,WXCDriverState target)1144 void WXC_SetDriverTarget(WXCDriverWork * driver, WXCDriverState target)
1145 {
1146     driver->target = target;
1147     /* Transition starts here if it is stable in another state */
1148     if ((driver->state != WXC_DRIVER_STATE_BUSY) && (driver->state != driver->target))
1149     {
1150         WXCi_OnStateChanged(driver, driver->state, NULL);
1151     }
1152 }
1153 
1154 /*---------------------------------------------------------------------------*
1155   Name:         WXC_SetDriverSsid
1156 
1157   Description:  Configures the SSID at connection.
1158 
1159   Arguments:    driver: WXCDriverWork structure
1160                 buffer: SSID data to configure
1161                 length: SSID data length.
1162                         Must be less than WM_SIZE_CHILD_SSID.
1163 
1164   Returns:      None.
1165  *---------------------------------------------------------------------------*/
WXC_SetDriverSsid(WXCDriverWork * driver,const void * buffer,u32 length)1166 void WXC_SetDriverSsid(WXCDriverWork * driver, const void *buffer, u32 length)
1167 {
1168     length = (u32)MATH_MIN(length, WM_SIZE_CHILD_SSID);
1169     MI_CpuCopy8(buffer, driver->ssid, length);
1170     MI_CpuFill8(driver->ssid + length, 0x00, (u32)(WM_SIZE_CHILD_SSID - length));
1171 }
1172 
1173 
1174 /*---------------------------------------------------------------------------*
1175   End of file
1176  *---------------------------------------------------------------------------*/
1177