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:: 2009-06-19#$
14   $Rev: 10786 $
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: 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     // Prohibit interrupts
38     e = OS_DisableInterrupts();
39 
40     // Confirm that initialized
41     result = WMi_CheckInitialized();
42     if (result != WM_ERRCODE_SUCCESS)
43     {
44         // End prohibiting 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 prohibiting 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: 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     // Prohibit interrupts
101     e = OS_DisableInterrupts();
102     // Confirm that initialized
103     result = WMi_CheckInitialized();
104     if (result != WM_ERRCODE_SUCCESS)
105     {
106         // End prohibiting 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 prohibiting of interrupts
127     (void)OS_RestoreInterrupts(e);
128 
129     return WM_ERRCODE_SUCCESS;
130 }
131 
132 /*---------------------------------------------------------------------------*
133   Name:         WM_ReadStatus
134 
135   Description:  Gets the structure that indicates the status of the wireless library.
136 
137   Arguments:    statusBuf: Pointer to the variable that gets 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? || Is the 'count' field value erroneous?
294     if (header->count == 0 || header->count > WM_NUM_MAX_CHILD)
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         {
308             return recvdata_p[i];
309         }
310         ++i;
311         recvdata_p[i] = (WMMpRecvData *)((u32)(recvdata_p[i - 1]) + header->length);
312     }
313     while (i < header->count);
314 
315     return NULL;
316 }
317 
318 /*---------------------------------------------------------------------------*
319   Name:         WM_GetAllowedChannel
320 
321   Description:  Gets the channel that was permitted to use for the communication.
322 
323   Arguments:    None.
324 
325   Returns:      u16: Returns the bit field of the permitted channel. 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                         Also, in case the function failed, such as when it is not yet initialized, 0x8000 is returned.
330 
331 
332  *---------------------------------------------------------------------------*/
WM_GetAllowedChannel(void)333 u16 WM_GetAllowedChannel(void)
334 {
335 #ifdef WM_PRECALC_ALLOWEDCHANNEL
336     WMErrCode result;
337 
338     #ifdef SDK_TWL // Return an error if the TWL System Settings are configured not to use wireless
339     if( OS_IsRunOnTwl() )
340     {
341         if( WMi_CheckEnableFlag() == FALSE )
342         {
343             return 0;
344         }
345     }
346     #endif
347 
348     // Check if initialized
349     result = WMi_CheckInitialized();
350     if (result != WM_ERRCODE_SUCCESS)
351     {
352         return WM_GET_ALLOWED_CHANNEL_BEFORE_INIT;
353     }
354     return *((u16 *)((u32)(OS_GetSystemWork()->nvramUserInfo) +
355                      ((sizeof(NVRAMConfig) + 3) & ~0x00000003) + 6));
356 #else
357     WMErrCode result;
358     WMArm9Buf *p = WMi_GetSystemWork();
359 
360     #ifdef SDK_TWL // Return an error if the TWL System Settings are configured not to use wireless
361     if( OS_IsRunOnTwl() )
362     {
363         if( WMi_CheckEnableFlag() == FALSE )
364         {
365             return 0;
366         }
367     }
368     #endif
369 
370     // Confirm that wireless hardware has started
371     result = WMi_CheckIdle();
372     if (result != WM_ERRCODE_SUCCESS)
373     {
374         return WM_GET_ALLOWED_CHANNEL_BEFORE_INIT;
375     }
376 
377     DC_InvalidateRange(&(p->status->allowedChannel), 2);
378     return p->status->allowedChannel;
379 #endif
380 }
381 
382 #ifdef  WM_PRECALC_ALLOWEDCHANNEL
383 /*---------------------------------------------------------------------------*
384   Name:         WM_IsExistAllowedChannel
385 
386   Description:  Checks whether the channel that was permitted to be used for communication actually exists.
387                 Possible to determine it properly even before the initialization of WM library.
388 
389   Arguments:    None.
390 
391   Returns:      BOOL: Returns TRUE if there is a usable channel and FALSE otherwise.
392 
393  *---------------------------------------------------------------------------*/
WM_IsExistAllowedChannel(void)394 BOOL WM_IsExistAllowedChannel(void)
395 {
396     u16     allowedChannel;
397 
398     allowedChannel = *((u16 *)((u32)(OS_GetSystemWork()->nvramUserInfo) +
399                      ((sizeof(NVRAMConfig) + 3) & ~0x00000003) + 6));
400     if (allowedChannel)
401     {
402         return TRUE;
403     }
404     return FALSE;
405 }
406 #endif
407 
408 /*---------------------------------------------------------------------------*
409   Name:         WM_GetLinkLevel
410 
411   Description:  Gets link level during communication. Synchronous function.
412 
413   Arguments:    None.
414 
415   Returns:      WMLinkLevel: Link level rated in four levels.
416  *---------------------------------------------------------------------------*/
WM_GetLinkLevel(void)417 WMLinkLevel WM_GetLinkLevel(void)
418 {
419     WMErrCode result;
420     WMArm9Buf *p = WMi_GetSystemWork();
421 
422     // Check if initialized
423     result = WMi_CheckInitialized();
424     if (result != WM_ERRCODE_SUCCESS)
425     {
426         return WM_LINK_LEVEL_0;        // Lowest radio strength
427     }
428 
429     DC_InvalidateRange(&(p->status->state), 2);
430     switch (p->status->state)
431     {
432     case WM_STATE_MP_PARENT:
433         // For parent
434         DC_InvalidateRange(&(p->status->child_bitmap), 2);
435         if (p->status->child_bitmap == 0)
436         {
437             // When there is no child
438             return WM_LINK_LEVEL_0;    // Lowest radio strength
439         }
440     case WM_STATE_MP_CHILD:
441     case WM_STATE_DCF_CHILD:
442         // For child
443         DC_InvalidateRange(&(p->status->linkLevel), 2);
444         return (WMLinkLevel)(p->status->linkLevel);
445     }
446 
447     // When unconnected
448     return WM_LINK_LEVEL_0;            // Lowest radio strength
449 }
450 
451 /*---------------------------------------------------------------------------*
452   Name:         WM_GetDispersionBeaconPeriod
453 
454   Description:  Gets the beacon interval value that should be set when operating as a parent.
455 
456   Arguments:    None.
457 
458   Returns:      u16: Beacon interval value that should be set (ms).
459  *---------------------------------------------------------------------------*/
WM_GetDispersionBeaconPeriod(void)460 u16 WM_GetDispersionBeaconPeriod(void)
461 {
462     u8      mac[6];
463     u16     ret;
464     s32     i;
465 
466     OS_GetMacAddress(mac);
467     for (i = 0, ret = 0; i < 6; i++)
468     {
469         ret += mac[i];
470     }
471     ret += OS_GetVBlankCount();
472     ret *= 7;
473     return (u16)(WM_DEFAULT_BEACON_PERIOD + (ret % 20));
474 }
475 
476 /*---------------------------------------------------------------------------*
477   Name:         WM_GetDispersionScanPeriod
478 
479   Description:  Gets the search limit time that should be set for a child to search for a parent.
480 
481   Arguments:    None.
482 
483   Returns:      u16: Search limit time that should be set (ms).
484  *---------------------------------------------------------------------------*/
WM_GetDispersionScanPeriod(void)485 u16 WM_GetDispersionScanPeriod(void)
486 {
487     u8      mac[6];
488     u16     ret;
489     s32     i;
490 
491     OS_GetMacAddress(mac);
492     for (i = 0, ret = 0; i < 6; i++)
493     {
494         ret += mac[i];
495     }
496     ret += OS_GetVBlankCount();
497     ret *= 13;
498     return (u16)(WM_DEFAULT_SCAN_PERIOD + (ret % 10));
499 }
500 
501 /*---------------------------------------------------------------------------*
502   Name:         WM_GetOtherElements
503 
504   Description:  Gets the extended elements in the beacon.
505                 Synchronous function.
506 
507   Arguments:    bssDesc: Parent information structure.
508                           Specifies the structure obtained with WM_StartScan(Ex).
509 
510   Returns:      WMOtherElements: Extended element structure.
511  *---------------------------------------------------------------------------*/
WM_GetOtherElements(WMBssDesc * bssDesc)512 WMOtherElements WM_GetOtherElements(WMBssDesc *bssDesc)
513 {
514     WMOtherElements elems;
515     u8     *p_elem;
516     int     i;
517     u16      curr_elem_len;
518     u16      elems_len;                 // Length of all elements
519     u16      elems_len_counter;         // Counter for checking the length of elements
520 
521     // Ends when gameInfo is included
522     if (bssDesc->gameInfoLength != 0)
523     {
524         elems.count = 0;
525         return elems;
526     }
527 
528     // Get otherElement count and terminate if 0
529     elems.count = (u8)(bssDesc->otherElementCount);
530     if (elems.count == 0)
531         return elems;
532 
533     // The maximum allowed number of elems is limited to WM_SCAN_OTHER_ELEMENT_MAX
534     if (elems.count > WM_SCAN_OTHER_ELEMENT_MAX)
535         elems.count = WM_SCAN_OTHER_ELEMENT_MAX;
536 
537     // First set the start of elements into gameInfo
538     p_elem = (u8 *)&(bssDesc->gameInfo);
539 
540     // Get length of all elements and initialize counter used for checking
541     elems_len = (u16)((bssDesc->length * sizeof(u16)) - 64);
542     elems_len_counter = 0;
543 
544     // Loop only 'elems' times
545     for (i = 0; i < elems.count; ++i)
546     {
547         elems.element[i].id = p_elem[0];
548         elems.element[i].length = p_elem[1];
549         elems.element[i].body = (u8 *)&(p_elem[2]);
550 
551         // Calculate current element length and add to the check counter
552         curr_elem_len = (u16)(elems.element[i].length + 2);
553         elems_len_counter += curr_elem_len;
554 
555         // OS_TPrintf("eles_len        =%d\n", elems_len);
556         // OS_TPrintf("eles_len_counter=%d\n", elems_len_counter);
557 
558         // An error results if the length of all elements is exceeded, and notify that there were no element
559         //
560         if (elems_len_counter > elems_len)
561         {
562             WM_WARNING("Elements length error.\n");
563             elems.count = 0;
564             return elems;
565         }
566 
567         // Calculate the lead address of the next element
568         p_elem = (u8 *)(p_elem + curr_elem_len);
569     }
570 
571     return elems;
572 }
573 
574 /*---------------------------------------------------------------------------*
575   Name:         WM_GetNextTgid
576 
577   Description:  Gets the automatically generated, unique TGID value.
578                 Synchronous function.
579 
580   Arguments:    None.
581 
582   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.
583 
584  *---------------------------------------------------------------------------*/
WM_GetNextTgid(void)585 u16 WM_GetNextTgid(void)
586 {
587     enum
588     { TGID_DEFAULT = (1 << 16) };
589     static u32 tgid_bak = (u32)TGID_DEFAULT;
590     /* Use the RTC time value the first time so as to preserve the integrity of the unit's own time */
591     if (tgid_bak == (u32)TGID_DEFAULT)
592     {
593         RTCTime rt[1];
594         RTC_Init();
595         if (RTC_GetTime(rt) == RTC_RESULT_SUCCESS)
596         {
597             tgid_bak = (u16)(rt->second + (rt->minute << 8));
598         }
599         else
600         {
601             OS_TWarning("failed to get RTC-data to create unique TGID!\n");
602         }
603     }
604     /* Use the unique value and increment each time */
605     tgid_bak = (u16)(tgid_bak + 1);
606     return (u16)tgid_bak;
607 }
608 
609 
610 /*---------------------------------------------------------------------------*
611     End of file
612  *---------------------------------------------------------------------------*/
613