1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WM - libraries
3   File:     wm_sync.c
4 
5   Copyright 2003-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-11-19#$
14   $Rev: 9342 $
15   $Author: okajima_manabu $
16  *---------------------------------------------------------------------------*/
17 
18 #include    <nitro/wm.h>
19 #include    "wm_arm9_private.h"
20 
21 
22 /*---------------------------------------------------------------------------*
23   Name:         WM_SetIndCallback
24 
25   Description:  Sets a function that is called to the status notification from WM7.
26 
27   Arguments:    callback    -   Specifies the callback function called during status notification from the wireless firmware.
28 
29 
30   Returns:      WMErrCode   -   Returns the processing result.
31  *---------------------------------------------------------------------------*/
WM_SetIndCallback(WMCallbackFunc callback)32 WMErrCode WM_SetIndCallback(WMCallbackFunc callback)
33 {
34     WMErrCode result;
35     OSIntrMode e;
36 
37     // Disable interrupts
38     e = OS_DisableInterrupts();
39 
40     // Confirm that initialized
41     result = WMi_CheckInitialized();
42     if (result != WM_ERRCODE_SUCCESS)
43     {
44         // End disabling of interrupts
45         (void)OS_RestoreInterrupts(e);
46         return result;
47     }
48 
49     // Set the callback for Indication
50     WMi_GetSystemWork()->indCallback = callback;
51     // End disabling of interrupts
52     (void)OS_RestoreInterrupts(e);
53 
54     return WM_ERRCODE_SUCCESS;
55 }
56 
57 /*---------------------------------------------------------------------------*
58   Name:         WM_SetPortCallback
59 
60   Description:  Sets a function that is called for the communication frame reception notification from WM7.
61 
62   Arguments:    port        -   Port number
63                 callback: The callback function invoked when there is a receive notification.
64                 arg         -   Argument passed to the callback function as WMPortRecvCallback.arg
65 
66 
67   Returns:      WMErrCode   -   Returns the processing result.
68  *---------------------------------------------------------------------------*/
WM_SetPortCallback(u16 port,WMCallbackFunc callback,void * arg)69 WMErrCode WM_SetPortCallback(u16 port, WMCallbackFunc callback, void *arg)
70 {
71     WMErrCode result;
72     OSIntrMode e;
73     WMPortRecvCallback cb_Port;
74 
75     // Check parameters
76 #ifdef SDK_DEBUG
77     if (port >= WM_NUM_OF_PORT)
78     {
79         WM_WARNING("Parameter \"port\" must be less than 16.\n");
80         return WM_ERRCODE_INVALID_PARAM;
81     }
82 #endif
83 
84     if (callback != NULL)
85     {
86         MI_CpuClear8(&cb_Port, sizeof(WMPortRecvCallback));
87         cb_Port.apiid = WM_APIID_PORT_RECV;
88         cb_Port.errcode = WM_ERRCODE_SUCCESS;
89         cb_Port.state = WM_STATECODE_PORT_INIT;
90         cb_Port.port = port;
91         cb_Port.recvBuf = NULL;
92         cb_Port.data = NULL;
93         cb_Port.length = 0;
94         cb_Port.seqNo = 0xffff;
95         cb_Port.arg = arg;
96         cb_Port.aid = 0;
97         OS_GetMacAddress(cb_Port.macAddress);
98     }
99 
100     // Disable interrupts
101     e = OS_DisableInterrupts();
102     // Confirm that initialized
103     result = WMi_CheckInitialized();
104     if (result != WM_ERRCODE_SUCCESS)
105     {
106         // End disabling of interrupts
107         (void)OS_RestoreInterrupts(e);
108         return result;
109     }
110 
111     // Set the callback for data reception
112     {
113         WMArm9Buf *p = WMi_GetSystemWork();
114 
115         p->portCallbackTable[port] = callback;
116         p->portCallbackArgument[port] = arg;
117     }
118 
119     if (callback != NULL)
120     {
121         cb_Port.connectedAidBitmap = WM_GetConnectedAIDs();
122         cb_Port.myAid = WM_GetAID();
123         (*callback) ((void *)&cb_Port);
124     }
125 
126     // End disabling of interrupts
127     (void)OS_RestoreInterrupts(e);
128 
129     return WM_ERRCODE_SUCCESS;
130 }
131 
132 /*---------------------------------------------------------------------------*
133   Name:         WM_ReadStatus
134 
135   Description:  Obtains the structure that indicates the status of the wireless library.
136 
137   Arguments:    statusBuf   -   Pointer to the variable that obtains the status.
138 
139   Returns:      WMErrCode   -   Returns the processing result.
140  *---------------------------------------------------------------------------*/
WM_ReadStatus(WMStatus * statusBuf)141 WMErrCode WM_ReadStatus(WMStatus *statusBuf)
142 {
143     WMErrCode result;
144     WMArm9Buf *p = WMi_GetSystemWork();
145 
146     // Confirm that initialized
147     result = WMi_CheckInitialized();
148     WM_CHECK_RESULT(result);
149 
150     // Check parameters
151     if (statusBuf == NULL)
152     {
153         WM_WARNING("Parameter \"statusBuf\" must not be NULL.\n");
154         return WM_ERRCODE_INVALID_PARAM;
155     }
156 
157     // Copy the WMStatus structure to the CPU
158     DC_InvalidateRange(p->status, sizeof(WMStatus));
159     MI_CpuCopyFast(p->status, statusBuf, sizeof(WMStatus));
160 
161     return WM_ERRCODE_SUCCESS;
162 }
163 
164 /*---------------------------------------------------------------------------*
165   Name:         WM_GetMPSendBufferSize
166 
167   Description:  Calculates the size of the send buffer for MP communications.
168                 At this time, StartParent and StartConnect must be finished.
169 
170   Arguments:    None.
171 
172   Returns:      int      - Send buffer size to be passed to WM_StartMP.
173  *---------------------------------------------------------------------------*/
WM_GetMPSendBufferSize(void)174 int WM_GetMPSendBufferSize(void)
175 {
176     WMErrCode result;
177     int     maxSendSize;
178     WMArm9Buf *p = WMi_GetSystemWork();
179 
180     // Check the state
181     result = WMi_CheckStateEx(2, WM_STATE_PARENT, WM_STATE_CHILD);
182     if (result != WM_ERRCODE_SUCCESS)
183     {
184         return 0;
185     }
186 
187     // Confirm MP status
188     DC_InvalidateRange(&(p->status->mp_flag), 4);       // Invalidates the ARM7 status region cache
189     if (p->status->mp_flag == TRUE)
190     {
191         WM_WARNING("Already started MP protocol. So can't execute request.\n");
192         return 0;
193     }
194 
195     // Reference the MWStatus structure for information needed for the calculation
196     DC_InvalidateRange(&(p->status->mp_maxSendSize), 4);
197     maxSendSize = p->status->mp_maxSendSize;
198 
199     return ((maxSendSize + 31) & ~0x1f);
200 }
201 
202 /*---------------------------------------------------------------------------*
203   Name:         WM_GetMPReceiveBufferSize
204 
205   Description:  Calculates the size of the Receive buffer for MP communications.
206                 At this time, StartParent and StartConnect must be finished.
207 
208   Arguments:    None.
209 
210   Returns:      int      - Receive buffer size to be passed to WM_StartMP.
211  *---------------------------------------------------------------------------*/
WM_GetMPReceiveBufferSize(void)212 int WM_GetMPReceiveBufferSize(void)
213 {
214     WMErrCode result;
215     BOOL    isParent;
216     int     maxReceiveSize;
217     int     maxEntry;
218     WMArm9Buf *p = WMi_GetSystemWork();
219 
220     // Check the state
221     result = WMi_CheckStateEx(2, WM_STATE_PARENT, WM_STATE_CHILD);
222     if (result != WM_ERRCODE_SUCCESS)
223     {
224         return 0;
225     }
226 
227     // Confirm MP status
228     DC_InvalidateRange(&(p->status->mp_flag), 4);
229     if (p->status->mp_flag == TRUE)
230     {
231         WM_WARNING("Already started MP protocol. So can't execute request.\n");
232         return 0;
233     }
234 
235     // Reference the MWStatus structure for information needed for the calculation
236     DC_InvalidateRange(&(p->status->aid), 2);
237     isParent = (p->status->aid == 0) ? TRUE : FALSE;
238     DC_InvalidateRange(&(p->status->mp_maxRecvSize), 2);
239     maxReceiveSize = p->status->mp_maxRecvSize;
240     if (isParent == TRUE)
241     {
242         DC_InvalidateRange(&(p->status->pparam.maxEntry), 2);
243         maxEntry = p->status->pparam.maxEntry;
244         return (int)((sizeof(WMmpRecvHeader) - sizeof(WMmpRecvData) +
245                       ((sizeof(WMmpRecvData) + maxReceiveSize - 2 + 2 /*MACBUG*/) * maxEntry)
246                       + 31) & ~0x1f) * 2;
247     }
248     else
249     {
250         return (int)((sizeof(WMMpRecvBuf) + maxReceiveSize - 4 + 31) & ~0x1f) * 2;
251     }
252 }
253 
254 /*---------------------------------------------------------------------------*
255   Name:         WM_ReadMPData
256 
257   Description:  Extracts only the data of the specified child from the entire received data.
258 
259   Arguments:    header      -   Pointer that indicates the entire received data.
260                 aid         -   AID of the child to extract data.
261 
262   Returns:      WMMpRecvData* - Returns a pointer to the data received from the corresponding child.
263                                 Returns NULL if extraction fails.
264  *---------------------------------------------------------------------------*/
WM_ReadMPData(const WMMpRecvHeader * header,u16 aid)265 WMMpRecvData *WM_ReadMPData(const WMMpRecvHeader *header, u16 aid)
266 {
267     int     i;
268     WMErrCode result;
269     WMMpRecvData *recvdata_p[WM_NUM_MAX_CHILD]; // Array of pointers to data starting position for all child devices (up to 15 devices).
270     WMArm9Buf *p = WMi_GetSystemWork();
271 
272     // Check if initialized
273     result = WMi_CheckInitialized();
274     if (result != WM_ERRCODE_SUCCESS)
275     {
276         return NULL;
277     }
278 
279     // Check parameters
280     if ((aid < 1) || (aid > WM_NUM_MAX_CHILD))
281     {
282         WM_WARNING("Parameter \"aid\" must be between 1 and %d.\n", WM_NUM_MAX_CHILD);
283         return NULL;
284     }
285 
286     // Does child with that AID exist?
287     DC_InvalidateRange(&(p->status->child_bitmap), 2);
288     if (0 == (p->status->child_bitmap & (0x0001 << aid)))
289     {
290         return NULL;
291     }
292 
293     // Is there any received data?
294     if (header->count == 0)
295     {
296         return NULL;
297     }
298 
299     // Calculate starting position for child data
300     recvdata_p[0] = (WMMpRecvData *)(header->data);
301 
302     i = 0;
303     do
304     {
305         // If it is the specified AID's child data, it returns its pointer.
306         if (recvdata_p[i]->aid == aid)
307             return recvdata_p[i];
308 
309         ++i;
310         recvdata_p[i] = (WMMpRecvData *)((u32)(recvdata_p[i - 1]) + header->length);
311     }
312     while (i < header->count);
313 
314     return NULL;
315 }
316 
317 /*---------------------------------------------------------------------------*
318   Name:         WM_GetAllowedChannel
319 
320   Description:  Obtains the channel that was permitted to use for the communication.
321 
322   Arguments:    None.
323 
324   Returns:      u16 -   Returns the bit field of the permitted channel.
325                         The least significant bit indicates channel 1, and the most significant bit indicates channel 16.
326                         A channel can be used if its corresponding bit is set to 1 and is prohibited from being used if its corresponding bit is set to 0.
327                         Typically, a value is returned with several of the bits corresponding to channels 1-13 set to 1.
328                         When 0x0000 is returned, no channels can be used and wireless features are themselves prohibited.
329 
330                         Also, in case the function failed, such as when it is not yet initialized, 0x8000 is returned.
331  *---------------------------------------------------------------------------*/
WM_GetAllowedChannel(void)332 u16 WM_GetAllowedChannel(void)
333 {
334 #ifdef WM_PRECALC_ALLOWEDCHANNEL
335     WMErrCode result;
336 
337     #ifdef SDK_TWL // Return an error if the TWL System Settings are configured not to use wireless.
338     if( OS_IsRunOnTwl() )
339     {
340         if( WMi_CheckEnableFlag() == FALSE )
341         {
342             return 0;
343         }
344     }
345     #endif
346 
347     // Check if initialized
348     result = WMi_CheckInitialized();
349     if (result != WM_ERRCODE_SUCCESS)
350     {
351         return WM_GET_ALLOWED_CHANNEL_BEFORE_INIT;
352     }
353     return *((u16 *)((u32)(OS_GetSystemWork()->nvramUserInfo) +
354                      ((sizeof(NVRAMConfig) + 3) & ~0x00000003) + 6));
355 #else
356     WMErrCode result;
357     WMArm9Buf *p = WMi_GetSystemWork();
358 
359     #ifdef SDK_TWL // Return an error if the TWL System Settings are configured not to use wireless.
360     if( OS_IsRunOnTwl() )
361     {
362         if( WMi_CheckEnableFlag() == FALSE )
363         {
364             return 0;
365         }
366     }
367     #endif
368 
369     // Confirm that wireless hardware has started
370     result = WMi_CheckIdle();
371     if (result != WM_ERRCODE_SUCCESS)
372     {
373         return WM_GET_ALLOWED_CHANNEL_BEFORE_INIT;
374     }
375 
376     DC_InvalidateRange(&(p->status->allowedChannel), 2);
377     return p->status->allowedChannel;
378 #endif
379 }
380 
381 #ifdef  WM_PRECALC_ALLOWEDCHANNEL
382 /*---------------------------------------------------------------------------*
383   Name:         WM_IsExistAllowedChannel
384 
385   Description:  Checks if the channel that was permitted to be used for communication actually exists.
386                 Possible to determine it properly even before the initialization of WM library.
387 
388   Arguments:    None.
389 
390   Returns:      BOOL - Returns TRUE if there is a usable channel and FALSE otherwise.
391 
392  *---------------------------------------------------------------------------*/
WM_IsExistAllowedChannel(void)393 BOOL WM_IsExistAllowedChannel(void)
394 {
395     u16     allowedChannel;
396 
397     allowedChannel = *((u16 *)((u32)(OS_GetSystemWork()->nvramUserInfo) +
398                      ((sizeof(NVRAMConfig) + 3) & ~0x00000003) + 6));
399     if (allowedChannel)
400     {
401         return TRUE;
402     }
403     return FALSE;
404 }
405 #endif
406 
407 /*---------------------------------------------------------------------------*
408   Name:         WM_GetLinkLevel
409 
410   Description:  Gets link level during communication. Synchronous function.
411 
412   Arguments:    None.
413 
414   Returns:      WMLinkLevel -   Returns the link level rated in four levels.
415  *---------------------------------------------------------------------------*/
WM_GetLinkLevel(void)416 WMLinkLevel WM_GetLinkLevel(void)
417 {
418     WMErrCode result;
419     WMArm9Buf *p = WMi_GetSystemWork();
420 
421     // Check if initialized
422     result = WMi_CheckInitialized();
423     if (result != WM_ERRCODE_SUCCESS)
424     {
425         return WM_LINK_LEVEL_0;        // Lowest radio strength
426     }
427 
428     DC_InvalidateRange(&(p->status->state), 2);
429     switch (p->status->state)
430     {
431     case WM_STATE_MP_PARENT:
432         // For parent
433         DC_InvalidateRange(&(p->status->child_bitmap), 2);
434         if (p->status->child_bitmap == 0)
435         {
436             // When there is no child
437             return WM_LINK_LEVEL_0;    // Lowest radio strength
438         }
439     case WM_STATE_MP_CHILD:
440     case WM_STATE_DCF_CHILD:
441         // For child
442         DC_InvalidateRange(&(p->status->linkLevel), 2);
443         return (WMLinkLevel)(p->status->linkLevel);
444     }
445 
446     // When unconnected
447     return WM_LINK_LEVEL_0;            // Lowest radio strength
448 }
449 
450 /*---------------------------------------------------------------------------*
451   Name:         WM_GetDispersionBeaconPeriod
452 
453   Description:  Obtains the beacon interval value that should be set when operating as a parent.
454 
455   Arguments:    None.
456 
457   Returns:      u16 -   Beacon interval value that should be set (ms).
458  *---------------------------------------------------------------------------*/
WM_GetDispersionBeaconPeriod(void)459 u16 WM_GetDispersionBeaconPeriod(void)
460 {
461     u8      mac[6];
462     u16     ret;
463     s32     i;
464 
465     OS_GetMacAddress(mac);
466     for (i = 0, ret = 0; i < 6; i++)
467     {
468         ret += mac[i];
469     }
470     ret += OS_GetVBlankCount();
471     ret *= 7;
472     return (u16)(WM_DEFAULT_BEACON_PERIOD + (ret % 20));
473 }
474 
475 /*---------------------------------------------------------------------------*
476   Name:         WM_GetDispersionScanPeriod
477 
478   Description:  Obtains the search limit time that should be set for a child to search for a parent.
479 
480   Arguments:    None.
481 
482   Returns:      u16 -   Search limit time that should be set (ms).
483  *---------------------------------------------------------------------------*/
WM_GetDispersionScanPeriod(void)484 u16 WM_GetDispersionScanPeriod(void)
485 {
486     u8      mac[6];
487     u16     ret;
488     s32     i;
489 
490     OS_GetMacAddress(mac);
491     for (i = 0, ret = 0; i < 6; i++)
492     {
493         ret += mac[i];
494     }
495     ret += OS_GetVBlankCount();
496     ret *= 13;
497     return (u16)(WM_DEFAULT_SCAN_PERIOD + (ret % 10));
498 }
499 
500 /*---------------------------------------------------------------------------*
501   Name:         WM_GetOtherElements
502 
503   Description:  Gets the extended elements in the beacon.
504                 Synchronous function.
505 
506   Arguments:    bssDesc - Parent information structure.
507                           Specifies the structure obtained with WM_StartScan(Ex).
508 
509   Returns:      WMOtherElements - Extended element structure.
510  *---------------------------------------------------------------------------*/
WM_GetOtherElements(WMBssDesc * bssDesc)511 WMOtherElements WM_GetOtherElements(WMBssDesc *bssDesc)
512 {
513     WMOtherElements elems;
514     u8     *p_elem;
515     int     i;
516     u16      curr_elem_len;
517     u16      elems_len;                 // Length of all elements
518     u16      elems_len_counter;         // Counter for checking the length of elements
519 
520     // Ends when gameInfo is included
521     if (bssDesc->gameInfoLength != 0)
522     {
523         elems.count = 0;
524         return elems;
525     }
526 
527     // Get otherElement count and terminate if 0.
528     elems.count = (u8)(bssDesc->otherElementCount);
529     if (elems.count == 0)
530         return elems;
531 
532     // The maximum allowed number of elems is limited to WM_SCAN_OTHER_ELEMENT_MAX.
533     if (elems.count > WM_SCAN_OTHER_ELEMENT_MAX)
534         elems.count = WM_SCAN_OTHER_ELEMENT_MAX;
535 
536     // First set the start of elements into gameInfo.
537     p_elem = (u8 *)&(bssDesc->gameInfo);
538 
539     // Get length of all elements and initialize counter used for checking.
540     elems_len = (u16)((bssDesc->length * sizeof(u16)) - 64);
541     elems_len_counter = 0;
542 
543     // Loop only 'elems' times
544     for (i = 0; i < elems.count; ++i)
545     {
546         elems.element[i].id = p_elem[0];
547         elems.element[i].length = p_elem[1];
548         elems.element[i].body = (u8 *)&(p_elem[2]);
549 
550         // Calculate current element length and add to the check counter.
551         curr_elem_len = (u16)(elems.element[i].length + 2);
552         elems_len_counter += curr_elem_len;
553 
554         // OS_Printf("eles_len        =%d\n", elems_len);
555         // OS_Printf("eles_len_counter=%d\n", elems_len_counter);
556 
557         // An error results if the length of all elements is exceeded, and notify that there were no element.
558         //
559         if (elems_len_counter > elems_len)
560         {
561             WM_WARNING("Elements length error.\n");
562             elems.count = 0;
563             return elems;
564         }
565 
566         // Calculate the lead address of the next element
567         p_elem = (u8 *)(p_elem + curr_elem_len);
568     }
569 
570     return elems;
571 }
572 
573 /*---------------------------------------------------------------------------*
574   Name:         WM_GetNextTgid
575 
576   Description:  Gets the automatically generated, unique TGID value.
577                 Synchronous function.
578 
579   Arguments:    None.
580 
581   Returns:      The first time it is called, it returns a TGID that was generated based on the RTC; thereafter, it returns the value returned the previous time incremented by 1.
582 
583  *---------------------------------------------------------------------------*/
WM_GetNextTgid(void)584 u16 WM_GetNextTgid(void)
585 {
586     enum
587     { TGID_DEFAULT = (1 << 16) };
588     static u32 tgid_bak = (u32)TGID_DEFAULT;
589     /* Use the RTC time value the first time so as to preserve the integrity of the unit's own time */
590     if (tgid_bak == (u32)TGID_DEFAULT)
591     {
592         RTCTime rt[1];
593         RTC_Init();
594         if (RTC_GetTime(rt) == RTC_RESULT_SUCCESS)
595         {
596             tgid_bak = (u16)(rt->second + (rt->minute << 8));
597         }
598         else
599         {
600             OS_Warning("failed to get RTC-data to create unique TGID!\n");
601         }
602     }
603     /* Use the unique value and increment each time */
604     tgid_bak = (u16)(tgid_bak + 1);
605     return (u16)tgid_bak;
606 }
607 
608 
609 /*---------------------------------------------------------------------------*
610     End of file
611  *---------------------------------------------------------------------------*/
612