1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WM - libraries
3   File:     wm_ds.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-09-17#$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 #include    <nitro/wm.h>
19 #include    "wm_arm9_private.h"
20 
21 
22 /*---------------------------------------------------------------------------*
23     Internal Function Definitions
24  *---------------------------------------------------------------------------*/
25 static void WmDataSharingSetDataCallback(void *callback);
26 static void WmDataSharingReceiveCallback_Parent(void *callback);
27 static void WmDataSharingReceiveCallback_Child(void *callback);
28 static void WmDataSharingReceiveData(WMDataSharingInfo *dsInfo, u16 aid, u16 *data);
29 static void WmDataSharingSendDataSet(WMDataSharingInfo *dsInfo, BOOL delayed);
30 static u16 *WmGetSharedDataAddress(WMDataSharingInfo *dsInfo, u32 aidBitmap, u16 *receiveBuf,
31                                    u32 aid);
32 
33 //// List of port numbers currently being used in data-sharing
34 //static u16 WmDataSharingPortBitmap = 0;
35 
WmDataSharingGetNextIndex(u32 index)36 static inline u16 WmDataSharingGetNextIndex(u32 index)
37 {
38     return (u16)((index + 1) % WM_DS_DATASET_NUM);
39 }
40 
WmDataSharingGetPrevIndex(u32 index)41 static inline u16 WmDataSharingGetPrevIndex(u32 index)
42 {
43     return (u16)((index + WM_DS_DATASET_NUM - 1) % WM_DS_DATASET_NUM);
44 }
45 
46 
47 /*---------------------------------------------------------------------------*
48   Name:         WM_StartDataSharing
49 
50   Description:  Enables the data sharing feature.
51 
52   Arguments:    dsInfo:   WMDataSharingInfo structure.
53                 port:        Number of port to use.
54                 aidBitmap:       AID bitmap of the other party for performing data sharing.
55                 dataLength:      Data length of shared memory (specify an even number of bytes)
56                 doubleMode:     Specify TRUE if using WM_StepDataSharing in every frame.
57 
58   Returns:      WMErrCode   -   Returns the processing result.
59  *---------------------------------------------------------------------------*/
60 WMErrCode
WM_StartDataSharing(WMDataSharingInfo * dsInfo,u16 port,u16 aidBitmap,u16 dataLength,BOOL doubleMode)61 WM_StartDataSharing(WMDataSharingInfo *dsInfo, u16 port, u16 aidBitmap, u16 dataLength,
62                     BOOL doubleMode)
63 {
64     WMErrCode result;
65     int     aid;
66     u16     connectedAIDs = 0x0001;
67 
68     // Check the state
69     result = WMi_CheckStateEx(2, WM_STATE_MP_PARENT, WM_STATE_MP_CHILD);
70     WM_CHECK_RESULT(result);
71 
72     // Check parameters
73     if (dsInfo == NULL)
74     {
75         WM_WARNING("Parameter \"dsInfo\" must not be NULL.\n");
76         return WM_ERRCODE_INVALID_PARAM;
77     }
78     if (port >= WM_NUM_OF_PORT)
79     {
80         WM_WARNING("Parameter \"port\" must be less than %d.\n", WM_NUM_OF_PORT);
81         return WM_ERRCODE_INVALID_PARAM;
82     }
83     if ((u32)dsInfo & 0x01f)
84     {
85         // Alignment check is a warning only, not an error
86         WM_WARNING("Parameter \"dsInfo\" is not 32-byte aligned.\n");
87     }
88     if (aidBitmap == 0)
89     {
90         WM_WARNING("Parameter \"aidBitmap\" must not be 0.\n");
91         return WM_ERRCODE_INVALID_PARAM;
92     }
93 
94     // Get necessary information
95     aid = WM_GetAID();
96     if (aid == 0)
97     {
98         connectedAIDs = WM_GetConnectedAIDs();
99     }
100 
101     // Initialize data sharing control variables
102     MI_CpuClearFast(dsInfo, sizeof(WMDataSharingInfo));
103     dsInfo->writeIndex = 0;
104     dsInfo->sendIndex = 0;
105     dsInfo->readIndex = 0;
106     dsInfo->dataLength = dataLength;
107     dsInfo->port = port;
108     dsInfo->aidBitmap = 0;
109     dsInfo->doubleMode = (u16)((doubleMode) ? TRUE : FALSE);
110 
111     aidBitmap |= (1 << aid);           // Add the self's own portion
112     dsInfo->aidBitmap = aidBitmap;
113 
114     {
115         u16     count = MATH_CountPopulation(aidBitmap);
116         dsInfo->stationNumber = count;
117         dsInfo->dataSetLength = (u16)(dataLength * count);
118 
119         if (dsInfo->dataSetLength > WM_DS_DATA_SIZE)
120         {
121             // Total data amount exceeds limit
122             dsInfo->aidBitmap = 0;
123             WM_WARNING("Total size of sharing data must be less than or equal to %d bytes.\n",
124                        WM_DS_DATA_SIZE);
125             return WM_ERRCODE_INVALID_PARAM;
126         }
127         dsInfo->dataSetLength += 4;    // aidBitmap, receivedBitmap
128     }
129 
130     dsInfo->state = WM_DS_STATE_START;
131 
132     if (aid == 0)
133     {
134         // Parent's start processing
135         int     i;
136 
137         for (i = 0; i < WM_DS_DATASET_NUM; i++)
138         {
139             dsInfo->ds[i].aidBitmap = (u16)(dsInfo->aidBitmap & (connectedAIDs | 0x0001));
140         }
141 
142         (void)WM_SetPortCallback(port, WmDataSharingReceiveCallback_Parent, (void *)dsInfo);
143 
144         // Sends empty data for start-up
145         for (i = 0; i < ((dsInfo->doubleMode == TRUE) ? 2 : 1); i++)
146         {
147             int     res;
148 
149             dsInfo->writeIndex = WmDataSharingGetNextIndex(dsInfo->writeIndex);
150             res =
151                 WM_SetMPDataToPortEx(WmDataSharingSetDataCallback, dsInfo, (u16 *)&dsInfo->ds[i],
152                                      dsInfo->dataSetLength,
153                                      (u16)(dsInfo->aidBitmap & connectedAIDs), dsInfo->port,
154                                      WM_PRIORITY_HIGH);
155             if (res == WM_ERRCODE_NO_CHILD)
156             {
157                 dsInfo->seqNum[i] = 0xffff;
158                 dsInfo->sendIndex = WmDataSharingGetNextIndex(dsInfo->sendIndex);
159             }
160             else
161             {
162                 if (res != WM_ERRCODE_SUCCESS && res != WM_ERRCODE_OPERATING)
163                 {
164                     WM_WARNING("WM_SetMPDataToPort failed during data-sharing. errcode=%x\n", res);
165                     dsInfo->state = WM_DS_STATE_ERROR;
166                     return WM_ERRCODE_FAILED;
167                 }
168             }
169         }
170     }
171     else
172     {
173         // Child's start processing
174         dsInfo->sendIndex = (u16)(WM_DS_DATASET_NUM - 1);
175         (void)WM_SetPortCallback(port, WmDataSharingReceiveCallback_Child, (void *)dsInfo);
176     }
177 
178     return WM_ERRCODE_SUCCESS;         // Successful completion
179 }
180 
181 /*---------------------------------------------------------------------------*
182   Name:         WM_EndDataSharing
183 
184   Description:  Disables the data sharing feature.
185 
186   Arguments:    dsInfo:   WMDataSharingInfo structure.
187 
188   Returns:      WMErrCode   -   Returns the processing result.
189  *---------------------------------------------------------------------------*/
WM_EndDataSharing(WMDataSharingInfo * dsInfo)190 WMErrCode WM_EndDataSharing(WMDataSharingInfo *dsInfo)
191 {
192     // Check parameters
193     if (dsInfo == NULL)
194     {
195         WM_WARNING("Parameter \"dsInfo\" must not be NULL.\n");
196         return WM_ERRCODE_INVALID_PARAM;
197     }
198 
199     // Checks the data sharing state
200     if (dsInfo->aidBitmap == 0)
201     {
202         WM_WARNING("It is not data-sharing mode now.\n");
203         return WM_ERRCODE_ILLEGAL_STATE;
204     }
205 
206     (void)WM_SetPortCallback(dsInfo->port, NULL, NULL);
207     dsInfo->aidBitmap = 0;
208     dsInfo->state = WM_DS_STATE_READY;
209 
210     return WM_ERRCODE_SUCCESS;         // Successful completion
211 }
212 
213 /*---------------------------------------------------------------------------*
214   Name:         WM_StepDataSharing
215 
216   Description:  Advances synchronicity of data sharing by one.
217 
218   Arguments:    dsInfo:   WMDataSharingInfo structure.
219                 sendData:        Send data that you want to share.
220                 receiveData:     Received shared data.
221 
222   Returns:      WMErrCode   -   Returns the processing result.
223                     *_SUCCESS: Shared data send/receive successful.
224                     *_NO_DATASET: Next shared data has not come yet.
225  *---------------------------------------------------------------------------*/
WM_StepDataSharing(WMDataSharingInfo * dsInfo,const u16 * sendData,WMDataSet * receiveData)226 WMErrCode WM_StepDataSharing(WMDataSharingInfo *dsInfo, const u16 *sendData, WMDataSet *receiveData)
227 {
228     WMErrCode result;
229     u16     aid;
230     u16     connectedAIDs;
231     u16     state;
232 
233     // Check the state
234     result = WMi_CheckStateEx(2, WM_STATE_MP_PARENT, WM_STATE_MP_CHILD);
235     WM_CHECK_RESULT(result);
236 
237     // Check parameters
238     if (dsInfo == NULL)
239     {
240         WM_WARNING("Parameter \"dsInfo\" must not be NULL.\n");
241         return WM_ERRCODE_INVALID_PARAM;
242     }
243     if (sendData == NULL)
244     {
245         WM_WARNING("Parameter \"sendData\" must not be NULL.\n");
246         return WM_ERRCODE_INVALID_PARAM;
247     }
248     if (receiveData == NULL)
249     {
250         WM_WARNING("Parameter \"receiveData\" must not be NULL.\n");
251         return WM_ERRCODE_INVALID_PARAM;
252     }
253 
254     // Get necessary information
255     aid = WM_GetAID();
256     if (aid == 0)
257     {
258         connectedAIDs = WM_GetConnectedAIDs();
259     }
260 
261     // Checks the data sharing state
262     state = dsInfo->state;
263     if (state == WM_DS_STATE_ERROR)
264     {
265         WM_WARNING("An error occurred during data-sharing.\n");
266         return WM_ERRCODE_FAILED;
267     }
268     if (state != WM_DS_STATE_START && state != WM_DS_STATE_RETRY_SEND)
269     {
270         WM_WARNING("It is not data-sharing mode now.\n");
271         return WM_ERRCODE_ILLEGAL_STATE;
272     }
273 
274     result = WM_ERRCODE_NO_DATASET;
275 
276     if (aid == 0)
277     {
278         // If a parent
279         BOOL    sendFlag = FALSE;
280         BOOL    delayed = FALSE;
281 
282         if (state == WM_DS_STATE_RETRY_SEND)
283         {
284             // Resends because the previous time was SEND_QUEUE_FULL
285             int     res;
286             int     oldWI;
287             dsInfo->state = WM_DS_STATE_START;
288 
289             WM_DLOG_DATASHARING("send queue was full. do retry.");
290 
291             oldWI = WmDataSharingGetPrevIndex(dsInfo->writeIndex);
292             res =
293                 WM_SetMPDataToPortEx(WmDataSharingSetDataCallback, dsInfo,
294                                      (u16 *)&dsInfo->ds[oldWI], dsInfo->dataSetLength,
295                                      (u16)(dsInfo->aidBitmap & connectedAIDs), dsInfo->port,
296                                      WM_PRIORITY_HIGH);
297             if (res == WM_ERRCODE_NO_CHILD)
298             {
299                 WM_DLOGF_DATASHARING("sent ds   : write: %d, read: %d, send: %d\n",
300                                      dsInfo->writeIndex, dsInfo->readIndex, dsInfo->sendIndex);
301                 dsInfo->seqNum[oldWI] = 0xffff;
302                 dsInfo->sendIndex = WmDataSharingGetNextIndex(dsInfo->sendIndex);
303             }
304             else
305             {
306                 if (res != WM_ERRCODE_SUCCESS && res != WM_ERRCODE_OPERATING)
307                 {
308                     WM_WARNING("WM_SetMPDataToPort failed during data-sharing. errcode=%x\n", res);
309                     dsInfo->state = WM_DS_STATE_ERROR;
310                     return WM_ERRCODE_FAILED;
311                 }
312             }
313         }
314 
315         // After the parent device has finished sending DataSet, it will be available for use, so decide the limit up to which sendIndex can read.
316         if (dsInfo->readIndex != dsInfo->sendIndex)
317         {
318             // Read processing
319             WM_DLOGF_DATASHARING("read ds   : write: %d, read: %d, send: %d, seq#: %d",
320                                  dsInfo->writeIndex, dsInfo->readIndex, dsInfo->sendIndex,
321                                  dsInfo->seqNum[dsInfo->readIndex]);
322 
323             dsInfo->ds[dsInfo->readIndex].aidBitmap |= 0x0001;  // The lowest bit in the aidBitmap in the transmission data is a delay flag.
324             MI_CpuCopy16(&dsInfo->ds[dsInfo->readIndex], receiveData, sizeof(WMDataSet));
325             dsInfo->currentSeqNum = dsInfo->seqNum[dsInfo->readIndex];
326             dsInfo->readIndex = WmDataSharingGetNextIndex(dsInfo->readIndex);
327 
328             sendFlag = TRUE;
329             result = WM_ERRCODE_SUCCESS;
330             if (dsInfo->doubleMode == FALSE && connectedAIDs != 0
331                 && dsInfo->ds[dsInfo->writeIndex].aidBitmap == 0x0001)
332             {
333                 // If the parent sets data, it can be sent immediately = only the parent has frame shifts.
334                 delayed = TRUE;
335             }
336             else
337             {
338                 delayed = FALSE;
339             }
340         }
341 
342         // Sends the DataSet when the data for all the devices is ready in the send buffer
343         WmDataSharingSendDataSet(dsInfo, FALSE);
344 
345         if (sendFlag)
346         {
347             // The parent inserts into its own buffer instead of sending over wireless
348             WM_DLOGF_DATASHARING("send data : write: %d, read: %d, send: %d", dsInfo->writeIndex,
349                                  dsInfo->readIndex, dsInfo->sendIndex);
350 
351             WmDataSharingReceiveData(dsInfo, 0, (u16 *)sendData);       // Remove const because chained rewrite past here is bothersome.
352 
353             if (dsInfo->doubleMode == FALSE)
354             {
355                 // When and only when there is not a Step in each frame, DataSet needs to be prepared at this time for sending with GF.
356                 //
357                 // Sends the DataSet when the data for all the devices is ready in the send buffer
358                 WmDataSharingSendDataSet(dsInfo, delayed);
359             }
360         }
361     }
362     else
363     {
364         // If a child
365         BOOL    sendFlag = FALSE;
366 
367         if (state == WM_DS_STATE_RETRY_SEND)
368         {
369             // Resends because the previous time was SEND_QUEUE_FULL
370             sendFlag = TRUE;
371             dsInfo->state = WM_DS_STATE_START;
372             WM_DLOG_DATASHARING("send queue was full. do retry.");
373         }
374         else
375         {
376             // After the child device has finished receiving DataSet, it will be available for use, so decide the limit up to which writeIndex can read.
377             if (dsInfo->readIndex != dsInfo->writeIndex)
378             {
379                 // If the delay flag is down, it is forcibly delayed by one frame.
380                 // The lowest bit in the aidBitmap in the transmission data is a delay flag.
381                 if (!(dsInfo->ds[dsInfo->readIndex].aidBitmap & 0x0001))
382                 {
383                     dsInfo->ds[dsInfo->readIndex].aidBitmap |= 0x0001;
384                 }
385                 else
386                 {
387                     // Read processing
388                     WM_DLOGF_DATASHARING("read ds   : write: %d, read: %d, send: %d, seq#: %d",
389                                          dsInfo->writeIndex, dsInfo->readIndex, dsInfo->sendIndex,
390                                          dsInfo->seqNum[dsInfo->readIndex]);
391                     MI_CpuCopy16(&dsInfo->ds[dsInfo->readIndex], receiveData, sizeof(WMDataSet));
392                     dsInfo->currentSeqNum = dsInfo->seqNum[dsInfo->readIndex];
393                     dsInfo->readIndex = WmDataSharingGetNextIndex(dsInfo->readIndex);
394 
395                     sendFlag = TRUE;
396                     result = WM_ERRCODE_SUCCESS;
397                 }
398             }
399         }
400 
401         if (sendFlag)
402         {
403             // The child transmits it as-is
404             int     res;
405             // Use part of dsInfo->ds as a send buffer
406             u16    *buf = (u16 *)(((u8 *)&dsInfo->ds[dsInfo->sendIndex]) + 32); // 32-byte alignment is required
407 
408             WM_DLOGF_DATASHARING("send data : write: %d, read: %d, send: %d", dsInfo->writeIndex,
409                                  dsInfo->readIndex, dsInfo->sendIndex);
410 
411             MI_CpuCopy16(sendData, buf, dsInfo->dataLength);
412             res =
413                 WM_SetMPDataToPortEx(WmDataSharingSetDataCallback, dsInfo, buf, dsInfo->dataLength,
414                                      dsInfo->aidBitmap, dsInfo->port, WM_PRIORITY_HIGH);
415             dsInfo->sendIndex = WmDataSharingGetNextIndex(dsInfo->sendIndex);
416             if (res != WM_ERRCODE_OPERATING && res != WM_ERRCODE_SUCCESS)
417             {
418                 WM_WARNING("WM_SetMPDataToPort failed during data-sharing. errcode=%x\n", res);
419                 dsInfo->state = WM_DS_STATE_ERROR;
420                 result = WM_ERRCODE_FAILED;
421             }
422         }
423     }
424 
425     return result;
426 }
427 
428 /*---------------------------------------------------------------------------*
429   Name:         WmDataSharingSetDataCallback
430 
431   Description:  Send completion callback.
432 
433   Arguments:    callback:   A pointer to the callback structure.
434 
435   Returns:      None.
436  *---------------------------------------------------------------------------*/
WmDataSharingSetDataCallback(void * callback)437 static void WmDataSharingSetDataCallback(void *callback)
438 {
439     WMArm9Buf *p = WMi_GetSystemWork();
440     WMPortSendCallback *cb_Port = (WMPortSendCallback *)callback;
441     WMDataSharingInfo *dsInfo;
442     u16     aid;
443 
444     // Checks if WM_EndDataSharing() has been called while DSInfo has been called in a invalid state.
445     dsInfo = (WMDataSharingInfo *)(p->portCallbackArgument[cb_Port->port]);
446     if ((p->portCallbackTable[cb_Port->port] != WmDataSharingReceiveCallback_Parent
447          && p->portCallbackTable[cb_Port->port] != WmDataSharingReceiveCallback_Child)
448         || dsInfo == NULL || dsInfo != (WMDataSharingInfo *)(cb_Port->arg))
449     {
450         WM_WARNING("data-sharing has already terminated.");
451         return;
452     }
453 
454     aid = WM_GetAID();
455 
456     if (cb_Port->errcode == WM_ERRCODE_SUCCESS)
457     {
458         // Send completed
459         if (aid == 0)
460         {
461             // Parent-side processing
462             WM_DLOGF_DATASHARING("sent ds   : write: %d, read: %d, send: %d", dsInfo->writeIndex,
463                                  dsInfo->readIndex, dsInfo->sendIndex);
464 
465             dsInfo->seqNum[dsInfo->sendIndex] = (u16)(cb_Port->seqNo >> 1);
466             dsInfo->sendIndex = WmDataSharingGetNextIndex(dsInfo->sendIndex);
467         }
468         else
469         {
470             // Child-side processing
471             WM_DLOGF_DATASHARING("sent data : write: %d, read: %d, send: %d", dsInfo->writeIndex,
472                                  dsInfo->readIndex, dsInfo->sendIndex);
473         }
474     }
475     else
476     {
477         if (cb_Port->errcode == WM_ERRCODE_SEND_QUEUE_FULL)
478         {
479             // Resend because the transmission queue was full
480             if (aid != 0)
481             {
482                 // For the child, put the sendIndex back one
483                 dsInfo->sendIndex = WmDataSharingGetPrevIndex(dsInfo->sendIndex);
484             }
485             dsInfo->state = WM_DS_STATE_RETRY_SEND;
486             WM_DLOG_DATASHARING("send queue is full. will retry.");
487         }
488         else
489         {
490             WM_WARNING("WM_SetMPDataToPort failed during data-sharing. errcode=%x\n",
491                        cb_Port->errcode);
492             dsInfo->state = WM_DS_STATE_ERROR;
493         }
494     }
495 }
496 
497 /*---------------------------------------------------------------------------*
498   Name:         WmDataSharingReceiveCallback_Parent
499 
500   Description:  A parent port receive callback
501 
502   Arguments:    callback:   A pointer to the callback structure.
503 
504   Returns:      None.
505  *---------------------------------------------------------------------------*/
WmDataSharingReceiveCallback_Parent(void * callback)506 static void WmDataSharingReceiveCallback_Parent(void *callback)
507 {
508     WMPortRecvCallback *cb_Port = (WMPortRecvCallback *)callback;
509     WMDataSharingInfo *dsInfo = (WMDataSharingInfo *)cb_Port->arg;
510 
511     if (dsInfo == NULL)
512     {
513         WM_WARNING("data-sharing has already terminated.");
514         return;
515     }
516 
517     if (cb_Port->errcode == WM_ERRCODE_SUCCESS)
518     {
519         switch (cb_Port->state)
520         {
521         case WM_STATECODE_PORT_RECV:
522             // Store the received child data in a buffer
523             WmDataSharingReceiveData(dsInfo, cb_Port->aid, cb_Port->data);
524             WmDataSharingSendDataSet(dsInfo, FALSE);
525             break;
526 
527         case WM_STATECODE_CONNECTED:
528             WmDataSharingSendDataSet(dsInfo, FALSE);    // Should not be required
529             break;
530 
531         case WM_STATECODE_DISCONNECTED:
532         case WM_STATECODE_DISCONNECTED_FROM_MYSELF:
533             {
534                 u32     aidBit;
535                 u32     writeIndex;
536                 OSIntrMode enabled;
537                 aidBit = 1U << cb_Port->aid;
538                 enabled = OS_DisableInterrupts();
539                 writeIndex = dsInfo->writeIndex;
540                 dsInfo->ds[writeIndex].aidBitmap &= ~aidBit;
541                 if (dsInfo->doubleMode == TRUE)
542                 {
543                     dsInfo->ds[WmDataSharingGetNextIndex(writeIndex)].aidBitmap &= ~aidBit;
544                 }
545                 (void)OS_RestoreInterrupts(enabled);
546                 WmDataSharingSendDataSet(dsInfo, FALSE);
547                 if (dsInfo->doubleMode == TRUE)
548                 {
549                     WmDataSharingSendDataSet(dsInfo, FALSE);
550                 }
551             }
552             break;
553 
554         case WM_STATECODE_PORT_INIT:
555             break;
556         }
557     }
558     else
559     {
560         WM_WARNING("An unknown receiving error occured during data-sharing. errcode=%x\n",
561                    cb_Port->errcode);
562         dsInfo->state = WM_DS_STATE_ERROR;
563     }
564 }
565 
566 /*---------------------------------------------------------------------------*
567   Name:         WmDataSharingReceiveCallback_Child
568 
569   Description:  A child port receive callback.
570 
571   Arguments:    callback:   A pointer to the callback structure.
572 
573   Returns:      None.
574  *---------------------------------------------------------------------------*/
WmDataSharingReceiveCallback_Child(void * callback)575 static void WmDataSharingReceiveCallback_Child(void *callback)
576 {
577     WMPortRecvCallback *cb_Port = (WMPortRecvCallback *)callback;
578     WMDataSharingInfo *dsInfo = (WMDataSharingInfo *)cb_Port->arg;
579 
580     if (dsInfo == NULL)
581     {
582         WM_WARNING("data-sharing has already terminated.");
583         return;
584     }
585 
586     if (cb_Port->errcode == WM_ERRCODE_SUCCESS)
587     {
588         switch (cb_Port->state)
589         {
590         case WM_STATECODE_PORT_RECV:
591             {
592                 u32     length;
593                 u32     aid;
594                 u32     aidBitmap;
595                 WMDataSet *dataSet;
596 
597                 WM_DLOGF_DATASHARING("recv ds   : write: %d, read: %d, send: %d",
598                                      dsInfo->writeIndex, dsInfo->readIndex, dsInfo->sendIndex);
599 
600                 // Saves the DataSet
601                 dataSet = (WMDataSet *)(cb_Port->data);
602                 aidBitmap = dataSet->aidBitmap;
603                 length = cb_Port->length;
604                 aid = WM_GetAID();
605 
606                 if (length != dsInfo->dataSetLength)
607                 {
608                     WM_WARNING("received DataSharing data size(%d) != dsInfo->dataSetLength(%d)\n",
609                                length, dsInfo->dataSetLength);
610                     if (length > sizeof(WMDataSet))
611                     {
612                         // If incoming data is longer than the buffer, adjust it.
613                         WM_WARNING("received DataSharing data exceeds sizeof(WMDataSet)\n");
614                         length = sizeof(WMDataSet);
615                     }
616                 }
617 #ifdef SDK_DEBUG
618                 if (aidBitmap & ~(dsInfo->aidBitmap))
619                 {
620                     // Larger than the aidBitmap expected by the child
621                     WM_WARNING("received aidBitmap(%x) has too many members.\n", aidBitmap);
622                 }
623 #endif
624                 if (length >= 4 && (aidBitmap & (1 << aid)))
625                 {
626                     MI_CpuCopy16(dataSet, &dsInfo->ds[dsInfo->writeIndex], length);
627                     dsInfo->seqNum[dsInfo->writeIndex] = (u16)(cb_Port->seqNo >> 1);
628                     dsInfo->writeIndex = WmDataSharingGetNextIndex(dsInfo->writeIndex);
629                 }
630             }
631             break;
632         case WM_STATECODE_PORT_INIT:
633         case WM_STATECODE_CONNECTED:
634         case WM_STATECODE_DISCONNECTED:
635         case WM_STATECODE_DISCONNECTED_FROM_MYSELF:
636             break;
637         }
638     }
639     else
640     {
641         WM_WARNING("An unknown receiving error occured during data-sharing. errcode=%x\n",
642                    cb_Port->errcode);
643         dsInfo->state = WM_DS_STATE_ERROR;
644     }
645 }
646 
647 /*---------------------------------------------------------------------------*
648   Name:         WmDataSharingReceiveData
649 
650   Description:  Stores the data, because the parent received data from several devices.
651 
652   Arguments:    dsInfo      -   WMDataSharingInfo structure.
653                 aid:      AID of the terminal that received data.
654                 data:     A pointer to the received data.
655 
656   Returns:      None.
657  *---------------------------------------------------------------------------*/
WmDataSharingReceiveData(WMDataSharingInfo * dsInfo,u16 aid,u16 * data)658 static void WmDataSharingReceiveData(WMDataSharingInfo *dsInfo, u16 aid, u16 *data)
659 {
660     u16     aidBit = (u16)(1 << aid);
661 
662     WM_DLOGF_DATASHARING("recv data%d: write: %d, read: %d, send: %d", aid, dsInfo->writeIndex,
663                          dsInfo->readIndex, dsInfo->sendIndex);
664 
665     // Confirms whether it is a processing target
666     if (dsInfo->aidBitmap & aidBit)
667     {
668         u16    *buf;
669         u16     writeIndex;
670         OSIntrMode enabled;
671 
672         if (!(dsInfo->ds[dsInfo->writeIndex].aidBitmap & aidBit))
673         {
674             if (dsInfo->doubleMode == TRUE)
675             {
676                 WM_DLOGF_DATASHARING("[DS] received two DS packets from aid %d", aid);
677 
678                 writeIndex = WmDataSharingGetNextIndex(dsInfo->writeIndex);
679                 if (!(dsInfo->ds[writeIndex].aidBitmap & aidBit))
680                 {
681                     // Up to two are stored in the buffer. Anything beyond that is discarded.
682                     OS_Warning("received too many DataSharing packets from aid %d. discarded.\n",
683                                aid);
684                     return;
685                 }
686             }
687             else
688             {
689                 // If not in doubleMode, the buffer can hold only up to one
690                 OS_Warning("received too many DataSharing packets from aid %d. discarded.\n", aid);
691                 return;
692             }
693         }
694         else
695         {
696             writeIndex = dsInfo->writeIndex;
697         }
698 
699         buf = WmGetSharedDataAddress(dsInfo, dsInfo->aidBitmap, dsInfo->ds[writeIndex].data, aid);
700         if (data != NULL)
701         {
702             MI_CpuCopy16(data, buf, dsInfo->dataLength);
703         }
704         else
705         {
706             MI_CpuClear16(buf, dsInfo->dataLength);
707         }
708 
709         enabled = OS_DisableInterrupts();
710         // Disables the not-yet-received flag
711         dsInfo->ds[writeIndex].aidBitmap &= ~aidBit;
712         // Enables the received flag
713         dsInfo->ds[writeIndex].receivedBitmap |= aidBit;
714         (void)OS_RestoreInterrupts(enabled);
715     }
716 }
717 
718 /*---------------------------------------------------------------------------*
719   Name:         WmDataSharingSendDataSet
720 
721   Description:  After the parent confirms reception of each device's data, the data set is sent.
722 
723   Arguments:    dsInfo      -   WMDataSharingInfo structure.
724                 delayed:   TRUE if in frame delay state
725 
726   Returns:      None.
727  *---------------------------------------------------------------------------*/
WmDataSharingSendDataSet(WMDataSharingInfo * dsInfo,BOOL delayed)728 void WmDataSharingSendDataSet(WMDataSharingInfo *dsInfo, BOOL delayed)
729 {
730     OSIntrMode enabled;
731 
732     enabled = OS_DisableInterrupts();
733     // If receiving is finished for all the devices (The ds[].aidBitmap, from the receive buffer, carries out the role of a not-yet-received flag)
734     //
735     if (dsInfo->ds[dsInfo->writeIndex].aidBitmap == 0)
736     {
737         u16     newWI, oldWI, resetWI;
738         WMErrCode res;
739         u16     connectedAIDs;
740 
741         WM_DLOGF_DATASHARING("send ds   : write: %d, read: %d, send: %d", dsInfo->writeIndex,
742                              dsInfo->readIndex, dsInfo->sendIndex);
743 
744         connectedAIDs = WM_GetConnectedAIDs();
745         oldWI = dsInfo->writeIndex;
746         newWI = WmDataSharingGetNextIndex(oldWI);
747         if (dsInfo->doubleMode == TRUE)
748         {
749             resetWI = WmDataSharingGetNextIndex(newWI);
750         }
751         else
752         {
753             resetWI = newWI;
754         }
755         SDK_ASSERT(newWI != dsInfo->readIndex && resetWI != dsInfo->readIndex);
756 //        SDK_ASSERT( dsInfo->sendIndex == dsInfo->writeIndex);
757         MI_CpuClear16(&dsInfo->ds[resetWI], sizeof(WMDataSet));
758         dsInfo->ds[resetWI].aidBitmap = (u16)(dsInfo->aidBitmap & (connectedAIDs | 0x0001));
759         dsInfo->writeIndex = newWI;
760         dsInfo->ds[oldWI].aidBitmap = dsInfo->aidBitmap;        // Enter the original value in aidBitmap before sending
761         if (delayed == TRUE)
762         {
763             // The lowest bit in the aidBitmap is a delay flag
764             dsInfo->ds[oldWI].aidBitmap &= ~0x0001;
765         }
766         (void)OS_RestoreInterrupts(enabled);
767         res =
768             WM_SetMPDataToPortEx(WmDataSharingSetDataCallback, dsInfo, (u16 *)&dsInfo->ds[oldWI],
769                                  dsInfo->dataSetLength, (u16)(dsInfo->aidBitmap & connectedAIDs),
770                                  dsInfo->port, WM_PRIORITY_HIGH);
771         if (res == WM_ERRCODE_NO_CHILD)
772         {
773             WM_DLOGF_DATASHARING("sent ds   : write: %d, read: %d, send: %d", dsInfo->writeIndex,
774                                  dsInfo->readIndex, dsInfo->sendIndex);
775 
776             dsInfo->seqNum[oldWI] = 0xffff;
777             dsInfo->sendIndex = WmDataSharingGetNextIndex(dsInfo->sendIndex);
778         }
779         else
780         {
781             if (res != WM_ERRCODE_SUCCESS && res != WM_ERRCODE_OPERATING)
782             {
783                 WM_WARNING("WM_SetMPDataToPort failed during data-sharing. errcode=%x\n", res);
784                 dsInfo->state = WM_DS_STATE_ERROR;
785             }
786         }
787     }
788     else
789     {
790         (void)OS_RestoreInterrupts(enabled);
791     }
792 }
793 
794 /*---------------------------------------------------------------------------*
795   Name:         WM_GetSharedDataAddress
796 
797   Description:  Gets a specific AID address during a session of receiving data in data sharing.
798 
799   Arguments:    dsInfo:   WMDataSharingInfo structure.
800                 receiveData:     Received shared data.
801                 aid:           AID.
802 
803   Returns:      u16* :     The address of the received data. If it does not exist, returns NULL.
804  *---------------------------------------------------------------------------*/
WM_GetSharedDataAddress(WMDataSharingInfo * dsInfo,WMDataSet * receiveData,u16 aid)805 u16    *WM_GetSharedDataAddress(WMDataSharingInfo *dsInfo, WMDataSet *receiveData, u16 aid)
806 {
807     u32     aidBitmap = receiveData->aidBitmap;
808     u32     receivedBitmap = receiveData->receivedBitmap;
809     u32     aidBit = (1U << aid);
810 
811     // Check parameters
812     if (dsInfo == NULL)
813     {
814         WM_WARNING("Parameter \"dsInfo\" must not be NULL.\n");
815         return NULL;
816     }
817 
818     if (receiveData == NULL)
819     {
820         WM_WARNING("Parameter \"receiveData\" must not be NULL.\n");
821         return NULL;
822     }
823 
824     if (!(aidBitmap & aidBit))
825     {
826 //        WM_WARNING("Parameter \"aid\" must be a member of \"receiveData->aidBitmap\".\n");
827         return NULL;
828     }
829 
830     if (!(receivedBitmap & aidBit))
831     {
832         // Has not received data
833         return NULL;
834     }
835 
836     return WmGetSharedDataAddress(dsInfo, aidBitmap, receiveData->data, aid);
837 }
838 
839 /*---------------------------------------------------------------------------*
840   Name:         WmGetSharedDataAddress
841 
842   Description:  Gets a specific AID address within the receive buffer.
843 
844   Arguments:    dsInfo:   WMDataSharingInfo structure.
845                 aidBitmap:   Other communication peer(s) included in the data.
846                 receiveBuf:   Receive buffer
847                 aid:           AID.
848                                 Confirm aidBitmap & (1<<aid) before calling this.
849 
850   Returns:      u16* :     The address of the received data.
851  *---------------------------------------------------------------------------*/
WmGetSharedDataAddress(WMDataSharingInfo * dsInfo,u32 aidBitmap,u16 * receiveBuf,u32 aid)852 u16    *WmGetSharedDataAddress(WMDataSharingInfo *dsInfo, u32 aidBitmap, u16 *receiveBuf, u32 aid)
853 {
854     u32     mask;
855     u32     count;
856     u32     offset;
857 
858     // Count the '1's among the aid bits in the aidBitmap, from the bottom
859     mask = (0x0001U << aid) - 1U;
860     aidBitmap &= mask;
861     count = MATH_CountPopulation(aidBitmap);
862     offset = dsInfo->dataLength * count;
863 
864     return (u16 *)(((u8 *)receiveBuf) + offset);
865 }
866 
867 /*---------------------------------------------------------------------------*
868     End of file
869  *---------------------------------------------------------------------------*/
870