1 /*---------------------------------------------------------------------------*
2   Project:  MPDS library
3   File:     mpdssystem.c
4 
5   Copyright 2007 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   $Log: mpdssystem.c,v $
14   Revision 1.11  2007/11/29 03:17:55  seiki_masashi
15   Added the const modifier.
16 
17   Revision 1.10  2007/10/24 13:45:24  seiki_masashi
18   Changed so that OSThreadQueue is used during synchronization.
19 
20   Revision 1.9  2007/10/24 08:47:14  seiki_masashi
21   Changed constant names.
22 
23   Revision 1.8  2007/10/22 10:27:04  seiki_masashi
24   Renamed doubleMode to isDoubleMode
25 
26   Revision 1.7  2007/10/22 09:41:04  seiki_masashi
27   Made the MPDSStep function into a synchronous function, and added the new function MPDSTryStep
28 
29   Revision 1.6  2007/10/18 01:36:13  seiki_masashi
30   Fixed debug output
31 
32   Revision 1.5  2007/10/18 00:31:14  seiki_masashi
33   Small fix
34 
35   Revision 1.4  2007/10/17 12:47:48  seiki_masashi
36   Changed the constants for debug output
37 
38   Revision 1.3  2007/10/17 09:43:22  seiki_masashi
39   Added debug output
40 
41   Revision 1.2  2007/10/11 00:16:13  seiki_masashi
42   Small fix
43 
44   Revision 1.1  2007/10/10 08:37:07  seiki_masashi
45   Added the MPDS library
46 
47   $NoKeywords: $
48  *---------------------------------------------------------------------------*/
49 
50 #include <revolution/revodefs.h>
51 REVOLUTION_LIB_VERSION( MPDS );
52 
53 #include <revolution.h>
54 #include <revolution/net.h>
55 #include <revolution/mpds.h>
56 
57 #include "mpdsprivate.h"
58 
59 
60 /*---------------------------------------------------------------------------*
61     Constant Definitions
62  *---------------------------------------------------------------------------*/
63 
64 /*---------------------------------------------------------------------------*
65     Internal Variable Definitions
66  *---------------------------------------------------------------------------*/
67 
68 static BOOL  MPDSi_registered     = FALSE;
69 
70 u32 MPDSi_debugLevel = MPDS_DEBUG_LEVEL_DEFAULT;
71 
72 
73 /*---------------------------------------------------------------------------*
74     Internal Function Prototype Definitions
75  *---------------------------------------------------------------------------*/
76 
77 static u8 CountPopulation(u32 x);
78 static void PortCallback( s32 type, MPPortCallbackInfo* info );
GetNextIndex(u32 index)79 static inline u16 GetNextIndex(u32 index)
80 {
81     return (u16)((index + 1) % MPDS_DATASET_NUM);
82 }
83 
GetPrevIndex(u32 index)84 static inline u16 GetPrevIndex(u32 index)
85 {
86     return (u16)((index + MPDS_DATASET_NUM - 1) % MPDS_DATASET_NUM);
87 }
88 
89 static void Start( MPDSContext* context );
90 static void Stop( MPDSContext* context );
91 static void SignalDataSet( MPDSContext* context );
92 static s32 Step( MPDSContext* context, const void* sendData, MPDSDataSet* recvDataSet, BOOL isSync );
93 static void ReceiveData(MPDSContext *context, u32 aid, u8 *data);
94 static void SendDataSet(MPDSContext *context, BOOL delayed);
95 static u8* GetSharedDataAddress( const MPDSContext *context, u32 aidBits, u16 *receiveBuf, u32 aid);
96 static void SetDataCallback(s32 result, MPCallbackInfo *info);
97 static void ReceiveCallback_Parent(s32 type, MPPortCallbackInfo *info);
98 
99 #if 0
100 #define MPDSiLOG_AIDBITS_BEGIN( context, index )  { u16 __prev_aidbits = (context)->ds[(index)].aidBits
101 #define MPDSiLOG_AIDBITS_END( context, index )  MPDSiLog( DETAIL_AIDBITS, "ds[%d].aidBits = %04x -> %04x", (index), __prev_aidbits, (context)->ds[(index)].aidBits ); }
102 #else
103 #define MPDSiLOG_AIDBITS_BEGIN( context, index )  ((void)0)
104 #define MPDSiLOG_AIDBITS_END( context, index )  ((void)0)
105 #endif
106 
107 
108 
109 /*---------------------------------------------------------------------------*
110   Name        : MPDSInit
111   Description : Configure the initial settings for data sharing
112   Arguments   : context - The data sharing context structure
113                 config  - Data sharing settings
114   Returns     : s32     - Returns the result of the process. Returns a negative value if processing failed.
115  *---------------------------------------------------------------------------*/
116 s32
MPDSInit(MPDSContext * context,const MPDSConfig * config)117 MPDSInit( MPDSContext* context, const MPDSConfig* config )
118 {
119     u32 aidBits;
120 
121     if ( MPDSi_registered == FALSE )
122     {
123         MPDSi_registered = TRUE;
124         OSRegisterVersion( __MPDSVersion );
125     }
126 
127     if ( context == NULL || config == NULL )
128     {
129         MPDSiError("Invalid argument");
130         return MP_RESULT_ILLEGAL_PARAMETER;
131     }
132 
133     (void)NETMemSet( context, 0, sizeof(MPDSContext) );
134     (void)NETMemCpy( &context->config, config, sizeof(MPDSConfig) );
135 
136     aidBits = config->aidBits | 0x0001; // Parents are always included
137     context->config.aidBits = aidBits;
138 
139     if ( config->port < MP_RAW_PORT_MAX
140          || (config->aidBits & MP_AID_BITS_MASK) == 0
141          || (config->aidBits & ~MP_AID_BITS_MASK) != 0 )
142     {
143         MPDSiError("Invalid config");
144         return MP_RESULT_ILLEGAL_PARAMETER;
145     }
146 
147     if ( !config->isParent )
148     {
149         MPDSiError("config.isParent have to be TRUE");
150         return MP_RESULT_ILLEGAL_PARAMETER;
151     }
152 
153     if ( !config->isAutoStart )
154     {
155         MPDSiError("config.isAutoStart have to be TRUE");
156         return MP_RESULT_ILLEGAL_PARAMETER;
157     }
158 
159     OSInitThreadQueue(&context->readThreadQueue);
160 
161     {
162         u16 count = CountPopulation(aidBits);
163         context->stationNumber = count;
164         context->dataSetLength = (u16)(context->config.dataLength * count);
165 
166         if (context->dataSetLength > MPDS_DATA_SIZE)
167         {
168             // Total data amount exceeds limit
169             context->config.aidBits = 0;
170             MPDSiError("Total size of sharing data must be less than or equal to %d bytes.", MPDS_DATA_SIZE);
171             return MP_RESULT_ILLEGAL_PARAMETER;
172         }
173         context->dataSetLength += 4;    // aidBits, receivedBits
174     }
175 
176     context->state = MPDS_STATE_READY;
177 
178     return MP_RESULT_OK;
179 }
180 
Start(MPDSContext * context)181 void Start( MPDSContext* context )
182 {
183     OSWakeupThread(&context->readThreadQueue); // Just in case
184 
185     if ( context->config.isParent )
186     {
187         int     i;
188 
189         for (i = 0; i < MPDS_DATASET_NUM; i++)
190         {
191             MPDSiLOG_AIDBITS_BEGIN( context, i );
192             context->ds[i].aidBits = MPHToMP16(0x0001);
193             MPDSiLOG_AIDBITS_END( context, i );
194         }
195 
196         // Set empty data for startup
197         for (i = 0; i < ((context->config.isDoubleMode == TRUE) ? 2 : 1); i++)
198         {
199             context->writeIndex = GetNextIndex(context->writeIndex);
200             context->seqNum[i] = 0xffff;
201             context->sendIndex = GetNextIndex(context->sendIndex);
202             SignalDataSet(context);
203         }
204     }
205 
206     context->state = MPDS_STATE_START;
207 }
208 
Stop(MPDSContext * context)209 void Stop( MPDSContext* context )
210 {
211     context->state = MPDS_STATE_READY;
212 
213     OSWakeupThread(&context->readThreadQueue);
214 }
215 
SignalDataSet(MPDSContext * context)216 void SignalDataSet( MPDSContext* context )
217 {
218     OSWakeupThread(&context->readThreadQueue);
219     {
220         MPPortCallback cb = context->config.mpdsCallback;
221         if ( cb != NULL )
222         {
223             MPPortCallbackInfo* info = &context->tmpCallbackInfo;
224             (void)NETMemSet( info, 0, sizeof(MPPortCallbackInfo) );
225             info->type = MPDS_PORT_CB_TYPE_DATASET_RECEIVED;
226             info->result = MP_RESULT_OK;
227             info->port = context->config.port;
228             info->userData = context;
229             cb(info->type, info);
230         }
231     }
232 }
233 
234 /*---------------------------------------------------------------------------*
235   Name        : MPDSSetupPortConfig
236   Description : Configure MP communications for data sharing
237   Arguments   : context - The data sharing context structure
238                 mpconfig - MP communication settings
239   Returns     : s32     - Returns the result of the processing. Returns a negative value if processing failed.
240  *---------------------------------------------------------------------------*/
241 s32
MPDSSetupPortConfig(const MPDSContext * context,MPConfig * mpconfig)242 MPDSSetupPortConfig( const MPDSContext* context, MPConfig* mpconfig )
243 {
244     // Check the parameter
245     if (context == NULL || mpconfig == NULL)
246     {
247         MPDSiError("Invalid parameter");
248         return MP_RESULT_ILLEGAL_PARAMETER;
249     }
250 
251     if ( context->config.isParent )
252     {
253         MPSetPortConfigEx( mpconfig, context->config.port, ReceiveCallback_Parent, context->config.priority, (void*)context );
254     }
255 #ifdef MPDS_ENABLE_CHILD
256     else
257     {
258         MPSetPortConfigEx( mpconfig, context->config.port, ReceiveCallback_Child, context->config.priority, (void*)context );
259     }
260 #endif
261 
262     return MP_RESULT_OK;
263 }
264 
265 #if 0
266 /*---------------------------------------------------------------------------*
267   Name        : MPDSStart
268   Description : Start MP communications for data sharing
269   Arguments   : context - The data sharing context structure
270   Returns     : s32     - Returns the result of the processing. Returns a negative value if processing failed.
271  *---------------------------------------------------------------------------*/
272 s32
273 MPDSStart( MPDSContext* context )
274 {
275     // Check the parameter
276     if (context == NULL)
277     {
278         MPDSiError("Invalid parameter");
279         return MP_RESULT_ILLEGAL_PARAMETER;
280     }
281 
282     if ( context->config.isParent )
283     {
284         // Parent's start processing
285         int  i;
286         u32  mpReadyBits = MPGetConnectedAIDs();
287 
288         for (i = 0; i < MPDS_DATASET_NUM; i++)
289         {
290             context->ds[i].aidBits = MPHToMP16((u16)(context->config.aidBits & (mpReadyBits | 0x0001)));
291         }
292 
293         // Sends empty data for start-up
294         for (i = 0; i < ((context->config.isDoubleMode == TRUE) ? 2 : 1); i++)
295         {
296             int     res;
297 
298             MPDSiTrace( "send ds[%d] to aids %08x", i, (context->config.aidBits & mpReadyBits) );
299             context->writeIndex = GetNextIndex(context->writeIndex);
300             res =
301                 MPSendAsync( &context->ds[i], context->dataSetLength,
302                              (u16)(context->config.aidBits & mpReadyBits), context->config.port,
303                              NULL, SetDataCallback, (void*)context );
304             if ( res != MP_RESULT_OK )
305             {
306                 MPDSiWarning("MPSendAsync failed during data-sharing. result=%x", res);
307                 context->state = MPDS_STATE_ERROR;
308                 return res;
309             }
310         }
311     }
312 #ifdef MPDS_ENABLE_CHILD
313     else
314     {
315         // Child's start processing
316         context->sendIndex = (u16)(MPDS_DATASET_NUM - 1);
317     }
318 #endif
319 
320     return MP_RESULT_OK;         // Successful completion
321 }
322 
323 /*---------------------------------------------------------------------------*
324   Name        : MPDSStop
325   Description : Stop data sharing
326   Arguments   : context - The data sharing context structure
327   Returns     : s32     - Returns the result of the processing. Returns a negative value if processing failed.
328  *---------------------------------------------------------------------------*/
329 s32
330 MPDSStop( MPDSContext* context )
331 {
332 }
333 #endif
334 
335 /*---------------------------------------------------------------------------*
336   Name        : MPDSStep
337   Description : Perform data sharing
338   Arguments   : context - The data sharing context structure
339                 sendData - The data that the local host wants to share next
340                 recvDataSet - The data that was shared
341   Returns     : s32     - Returns the result of the processing. Returns a negative value if processing failed.
342  *---------------------------------------------------------------------------*/
343 s32
MPDSStep(MPDSContext * context,const void * sendData,MPDSDataSet * recvDataSet)344 MPDSStep( MPDSContext* context, const void* sendData, MPDSDataSet* recvDataSet )
345 {
346     return Step( context, sendData, recvDataSet, TRUE );
347 }
348 
349 /*---------------------------------------------------------------------------*
350   Name        : MPDSTryStep
351   Description : Perform data sharing
352   Arguments   : context - The data sharing context structure
353                 sendData - The data that the local host wants to share next
354                 recvDataSet - The data that was shared
355   Returns     : s32     - Returns the result of the processing. Returns a negative value if processing failed.
356  *---------------------------------------------------------------------------*/
357 s32
MPDSTryStep(MPDSContext * context,const void * sendData,MPDSDataSet * recvDataSet)358 MPDSTryStep( MPDSContext* context, const void* sendData, MPDSDataSet* recvDataSet )
359 {
360     return Step( context, sendData, recvDataSet, FALSE );
361 }
362 
363 s32
Step(MPDSContext * context,const void * sendData,MPDSDataSet * recvDataSet,BOOL isSync)364 Step( MPDSContext* context, const void* sendData, MPDSDataSet* recvDataSet, BOOL isSync )
365 {
366     s32     result;
367     u32     mpReadyBits;
368     u32     state;
369 
370     // Check the parameter
371     if ( context == NULL || sendData == NULL || recvDataSet == NULL )
372     {
373         MPDSiWarning("Invalid parameter");
374         return MP_RESULT_ILLEGAL_PARAMETER;
375     }
376 
377     // Checks the data sharing state
378     state = context->state;
379     if (state == MPDS_STATE_ERROR)
380     {
381         MPDSiWarning("An error occurred during data-sharing.");
382         return MP_RESULT_ILLEGAL_STATE;
383     }
384     if (state != MPDS_STATE_START && state != MPDS_STATE_RETRY_SEND)
385     {
386         MPDSiWarning("It is not data-sharing mode now.");
387         return MP_RESULT_ILLEGAL_STATE;
388     }
389 
390     result = MP_RESULT_NO_DATA;
391 
392     if ( context->config.isParent )
393     {
394         // If a parent
395         BOOL    sendFlag = FALSE;
396         BOOL    delayed = FALSE;
397 
398         mpReadyBits = MPGetConnectedAIDs();
399 
400         if (state == MPDS_STATE_RETRY_SEND)
401         {
402             // Resends because the previous time was SEND_QUEUE_FULL
403             int     res;
404             int     oldWI;
405             context->state = MPDS_STATE_START;
406 
407             MPDSiReport("send queue was full. do retry.");
408 
409             oldWI = GetPrevIndex(context->writeIndex);
410             MPDSiTrace( "resend ds[%d] to aids %08x", oldWI, (context->config.aidBits & mpReadyBits) );
411             res =
412                 MPSendAsync( &context->ds[oldWI], context->dataSetLength,
413                              (u16)(context->config.aidBits & mpReadyBits), context->config.port,
414                              NULL, SetDataCallback, (void*)context );
415             if (res != MP_RESULT_OK)
416             {
417                 MPDSiWarning("MPSendAsync failed during data-sharing. result=%x", res);
418                 context->state = MPDS_STATE_ERROR;
419                 return res;
420             }
421         }
422 
423         while ( context->state == MPDS_STATE_START )
424         {
425             // After the parent device has finished sending DataSet, it will be available for use, so decide the limit up to which sendIndex can read.
426             if (context->readIndex != context->sendIndex)
427             {
428                 // Read processing
429                 // Because readIndex is only manipulated here, there is no need to disable interrupts
430                 MPDSiTrace("read ds   : write: %d, read: %d, send: %d, seq#: %d",
431                            context->writeIndex, context->readIndex, context->sendIndex,
432                            context->seqNum[context->readIndex]);
433 
434                 MPDSiLOG_AIDBITS_BEGIN( context, context->readIndex );
435                 context->ds[context->readIndex].aidBits |= MPHToMP16(0x0001);  // The lowest bit in the aidBits in the transmission data is a delay flag.
436                 MPDSiLOG_AIDBITS_END( context, context->readIndex );
437                 (void)NETMemCpy(recvDataSet, &context->ds[context->readIndex], sizeof(MPDSDataSet));
438                 context->currentSeqNum = context->seqNum[context->readIndex];
439                 context->readIndex = GetNextIndex(context->readIndex);
440 
441                 sendFlag = TRUE;
442                 result = MP_RESULT_OK;
443                 if (context->config.isDoubleMode == FALSE && mpReadyBits != 0
444                     && context->ds[context->writeIndex].aidBits == MPHToMP16(0x0001))
445                 {
446                     // If the parent sets data, it can be sent immediately = only the parent has frame shifts.
447                     delayed = TRUE;
448                 }
449                 else
450                 {
451                     delayed = FALSE;
452                 }
453             }
454 
455             if ( isSync && result == MP_RESULT_NO_DATA )
456             {
457                 // If called in synchronous mode, and there was no received data, then sleep.
458                 OSSleepThread(&context->readThreadQueue);
459             }
460             else
461             {
462                 break;
463             }
464         }
465         if ( context->state != MPDS_STATE_START )
466         {
467             result = MP_RESULT_ILLEGAL_STATE;
468         }
469 
470         // Sends the DataSet when the data for all the devices is ready in the send buffer
471         SendDataSet(context, FALSE);
472 
473         if (sendFlag)
474         {
475             // The parent inserts into its own buffer instead of sending over wireless
476             MPDSiTrace("send data : write: %d, read: %d, send: %d", context->writeIndex,
477                                  context->readIndex, context->sendIndex);
478 
479             ReceiveData(context, 0, (u8 *)sendData);       // Remove const because chained rewrite past here is bothersome.
480 
481             if (context->config.isDoubleMode == FALSE)
482             {
483                 // When and only when there is not a Step in each frame, DataSet needs to be prepared at this time for sending with GF.
484                 //
485                 // Sends the DataSet when the data for all the devices is ready in the send buffer
486                 SendDataSet(context, delayed);
487             }
488         }
489     }
490 #ifdef MPDS_ENABLE_CHILD
491     else
492     {
493         // If a child
494         BOOL    sendFlag = FALSE;
495 
496         if (state == MPDS_STATE_RETRY_SEND)
497         {
498             // Resends because the previous time was SEND_QUEUE_FULL
499             sendFlag = TRUE;
500             context->state = MPDS_STATE_START;
501             MPDSiReport("send queue was full. do retry.");
502         }
503         else
504         {
505             while ( context->state == MPDS_STATE_START )
506             {
507                 // After the child device has finished receiving DataSet, it will be available for use, so decide the limit up to which writeIndex can read.
508                 if (context->readIndex != context->writeIndex)
509                 {
510 
511                     // If the delay flag is down, it is forcibly delayed by one frame.
512                     // The lowest bit in the aidBits in the transmission data is a delay flag.
513                     if (!(context->ds[context->readIndex].aidBits & MPHToMP16(0x0001)))
514                     {
515                         context->ds[context->readIndex].aidBits |= MPHToMP16(0x0001);
516                     }
517                     else
518                     {
519                         // Read processing
520                         // Because readIndex is only manipulated here, there is no need to disable interrupts
521                         MPDSiTrace("read ds   : write: %d, read: %d, send: %d, seq#: %d",
522                                    context->writeIndex, context->readIndex, context->sendIndex,
523                                    context->seqNum[context->readIndex]);
524                         (void)NETMemCpy(recvDataSet, &context->ds[context->readIndex], sizeof(MPDSDataSet));
525                         context->currentSeqNum = context->seqNum[context->readIndex];
526                         context->readIndex = GetNextIndex(context->readIndex);
527 
528                         sendFlag = TRUE;
529                         result = MP_RESULT_OK;
530                     }
531                 }
532                 if ( isSync && result == MP_RESULT_NO_DATA )
533                 {
534                     // If called in synchronous mode, and there was no received data, then sleep.
535                     OSSleepThread(&context->readThreadQueue);
536                 }
537                 else
538                 {
539                     break;
540                 }
541             }
542             if ( context->state != MPDS_STATE_START )
543             {
544                 result = MP_RESULT_ILLEGAL_STATE;
545             }
546         }
547 
548         if (sendFlag)
549         {
550             // The child transmits it as-is
551             int     res;
552             // Take the liberty of using part of context->ds as a send buffer
553             u16    *buf = (u16 *)(((u8 *)&context->ds[context->sendIndex]) + 32); // 32-byte alignment is required
554 
555             MPDSiTrace("send data : write: %d, read: %d, send: %d", context->writeIndex,
556                                  context->readIndex, context->sendIndex);
557 
558             (void)NETMemCpy(buf, sendData, context->config.dataLength);
559             res =
560                 MPSendAsync( buf, context->dataSetLength,
561                              context->config.aidBits, context->config.port,
562                              NULL, SetDataCallback, (void*)context );
563             context->sendIndex = GetNextIndex(context->sendIndex);
564             SignalDataSet(context);
565             if (res != MP_RESULT_OK)
566             {
567                 MPDSiWarning("MPSendAsync failed during data-sharing. result=%x", res);
568                 context->state = MPDS_STATE_ERROR;
569                 result = res;
570             }
571         }
572     }
573 #endif
574 
575     return result;
576 }
577 
578 /*---------------------------------------------------------------------------*
579   Name        : MPDSGetData
580   Description : Gets the data that was shared
581   Arguments   : context - The data sharing context structure
582                 dataSet - a shared data structure
583                 aid     - the aid of the data to be obtained
584   Returns     : u8*     - a pointer to the shared data
585  *---------------------------------------------------------------------------*/
MPDSGetData(const MPDSContext * context,const MPDSDataSet * dataSet,u32 aid)586 const u8* MPDSGetData( const MPDSContext* context, const MPDSDataSet* dataSet, u32 aid )
587 {
588     u16     aidBits;
589     u16     receivedBits;
590     u16     aidBit = (u16)(1U << aid);
591 
592     // Check parameters
593     if (context == NULL || dataSet == NULL)
594     {
595         MPDSiWarning("Invalid parameter");
596         return NULL;
597     }
598 
599     aidBits = MPHToMP16(dataSet->aidBits);
600     receivedBits = MPHToMP16(dataSet->receivedBits);
601 
602     if (!(aidBits & aidBit))
603     {
604         return NULL;
605     }
606 
607     if (!(receivedBits & aidBit))
608     {
609         // Has not received data
610         return NULL;
611     }
612 
613     return GetSharedDataAddress(context, aidBits, (u16*)dataSet->data, aid);
614 }
615 
616 /*---------------------------------------------------------------------------*
617   Name:         SetDataCallback
618 
619   Description:  Send completion callback.
620 
621   Arguments:    callback:   A pointer to the callback structure.
622 
623   Returns:      None.
624  *---------------------------------------------------------------------------*/
SetDataCallback(s32 result,MPCallbackInfo * info)625 static void SetDataCallback(s32 result, MPCallbackInfo *info)
626 {
627 #pragma unused(result)
628     MPDSContext *context = (MPDSContext *)info->userData;
629 
630     if ( context == NULL )
631     {
632         MPDSiWarning("data-sharing has already terminated.");
633         return;
634     }
635 
636     if ( info->result == MP_RESULT_OK )
637     {
638         // Send completed
639         if ( context->config.isParent )
640         {
641             // Parent-side processing
642             MPDSiTrace("sent ds   : write: %d, read: %d, send: %d", context->writeIndex,
643                                  context->readIndex, context->sendIndex);
644 
645             context->seqNum[context->sendIndex] = (u16)(info->dataSent.seqNo >> 1);
646             context->sendIndex = GetNextIndex(context->sendIndex);
647             SignalDataSet(context);
648         }
649 #ifdef MPDS_ENABLE_CHILD
650         else
651         {
652             // Child-side processing
653             MPDSiTrace("sent data : write: %d, read: %d, send: %d", context->writeIndex,
654                                  context->readIndex, context->sendIndex);
655         }
656 #endif
657     }
658     else
659     {
660         MPDSiWarning("MPSendAsync failed during data-sharing. result=%x",
661                      info->result);
662         context->state = MPDS_STATE_ERROR;
663     }
664 }
665 
666 /*---------------------------------------------------------------------------*
667   Name:         ReceiveCallback_Parent
668 
669   Description:  A parent port receive callback
670 
671   Arguments:    callback:   A pointer to the callback structure.
672 
673   Returns:      None.
674  *---------------------------------------------------------------------------*/
ReceiveCallback_Parent(s32 type,MPPortCallbackInfo * info)675 static void ReceiveCallback_Parent(s32 type, MPPortCallbackInfo *info)
676 {
677 #pragma unused(type)
678     MPDSContext *context = (MPDSContext *)info->userData;
679 
680     if (context == NULL)
681     {
682         MPDSiWarning("data-sharing has already terminated.");
683         return;
684     }
685 
686     if ( info->result == MP_RESULT_OK )
687     {
688         switch (info->type)
689         {
690         case MP_PORT_CB_TYPE_DATA_RECEIVED:
691             MPDSiTrace("data received to MPDS: aid=%d, len=%d, seqNo=%d", info->dataReceived.fromAid, info->dataReceived.length, info->dataReceived.seqNo);
692             // Store the received child data in a buffer
693             ReceiveData(context, info->dataReceived.fromAid, info->dataReceived.data);
694             SendDataSet(context, FALSE);
695             break;
696 
697         case MP_PORT_CB_TYPE_CONNECTED:
698             MPDSiTrace("connected notification to MPDS: aid=%d", info->connected.fromAid);
699             SendDataSet(context, FALSE);    // Should not be required
700             {
701                 MPPortCallback cb = context->config.mpdsCallback;
702                 if ( cb != NULL )
703                 {
704                     cb(type, info);
705                 }
706             }
707             break;
708 
709         case MP_PORT_CB_TYPE_DISCONNECTED:
710             MPDSiTrace("disconnected notification to MPDS: aid=%d", info->disconnected.fromAid);
711             {
712                 u32     aidBit;
713                 u32     writeIndex;
714                 BOOL    enabled;
715                 aidBit = 1U << info->dataReceived.fromAid;
716                 enabled = OSDisableInterrupts();
717                 writeIndex = context->writeIndex;
718                 MPDSiLOG_AIDBITS_BEGIN( context, writeIndex );
719                 context->ds[writeIndex].aidBits &= MPHToMP16((u16)~aidBit);
720                 MPDSiLOG_AIDBITS_END( context, writeIndex );
721                 if (context->config.isDoubleMode == TRUE)
722                 {
723                     MPDSiLOG_AIDBITS_BEGIN( context, GetNextIndex(writeIndex) );
724                     context->ds[GetNextIndex(writeIndex)].aidBits &= MPHToMP16((u16)~aidBit);
725                     MPDSiLOG_AIDBITS_END( context, GetNextIndex(writeIndex) );
726                 }
727                 (void)OSRestoreInterrupts(enabled);
728                 SendDataSet(context, FALSE);
729                 if (context->config.isDoubleMode == TRUE)
730                 {
731                     SendDataSet(context, FALSE);
732                 }
733             }
734             {
735                 MPPortCallback cb = context->config.mpdsCallback;
736                 if ( cb != NULL )
737                 {
738                     cb(type, info);
739                 }
740             }
741             break;
742 
743         case MP_PORT_CB_TYPE_STARTUP:
744             MPDSiTrace("startup notification to MPDS.");
745             // Note that notifications that can be received are done within Start
746             {
747                 MPPortCallback cb = context->config.mpdsCallback;
748                 if ( cb != NULL )
749                 {
750                     cb(type, info);
751                 }
752             }
753             if (context->config.isAutoStart)
754             {
755                 Start(context);
756             }
757             break;
758 
759         case MP_PORT_CB_TYPE_CLEANUP:
760             MPDSiTrace("cleanup notification to MPDS.");
761             if (context->config.isAutoStart)
762             {
763                 Stop(context);
764             }
765             {
766                 MPPortCallback cb = context->config.mpdsCallback;
767                 if ( cb != NULL )
768                 {
769                     cb(type, info);
770                 }
771             }
772             break;
773         }
774     }
775     else
776     {
777         MPDSiWarning("An unknown receiving error occured during data-sharing. result=%x",
778                      info->result);
779         context->state = MPDS_STATE_ERROR;
780     }
781 }
782 
783 /*---------------------------------------------------------------------------*
784   Name:         ReceiveData
785 
786   Description:  Stores the data, because the parent received data from several devices.
787 
788   Arguments:    context - MPDSContext structure.
789                 aid:      AID of the terminal that received data.
790                 data:     A pointer to the received data.
791 
792   Returns:      None.
793  *---------------------------------------------------------------------------*/
ReceiveData(MPDSContext * context,u32 aid,u8 * data)794 static void ReceiveData(MPDSContext* context, u32 aid, u8* data)
795 {
796     u16     aidBit = (u16)(1 << aid);
797 
798     MPDSiTrace("recv data%d: write: %d, read: %d, send: %d", aid, context->writeIndex,
799                          context->readIndex, context->sendIndex);
800 
801     // Confirms whether it is a processing target
802     if (context->config.aidBits & aidBit)
803     {
804         u8*     buf;
805         u16     writeIndex;
806         BOOL    enabled;
807 
808         if (!(context->ds[context->writeIndex].aidBits & MPHToMP16(aidBit)))
809         {
810             if (context->config.isDoubleMode == TRUE)
811             {
812                 MPDSiReport("[DS] received two DS packets from aid %d", aid);
813 
814                 writeIndex = GetNextIndex(context->writeIndex);
815                 if (!(context->ds[writeIndex].aidBits & MPHToMP16(aidBit)))
816                 {
817                     // Up to two are stored in the buffer. Anything beyond that is discarded.
818                     MPDSiWarning("received too many DataSharing packets from aid %d. discarded.",
819                                aid);
820                     return;
821                 }
822             }
823             else
824             {
825                 // If not in doubleMode, the buffer can hold only up to one
826                 MPDSiWarning("received too many DataSharing packets from aid %d. discarded.", aid);
827                 return;
828             }
829         }
830         else
831         {
832             writeIndex = context->writeIndex;
833         }
834 
835         buf = GetSharedDataAddress(context, context->config.aidBits, context->ds[writeIndex].data, aid);
836         if (data != NULL)
837         {
838             (void)NETMemCpy(buf, data, context->config.dataLength);
839         }
840         else
841         {
842             MPDSiWarning( "received data is null." );
843             (void)NETMemSet(buf, 0, context->config.dataLength);
844         }
845 
846         enabled = OSDisableInterrupts();
847         // Disables the not-yet-received flag
848         MPDSiLOG_AIDBITS_BEGIN( context, writeIndex );
849         context->ds[writeIndex].aidBits &= MPHToMP16((u16)~aidBit);
850         MPDSiLOG_AIDBITS_END( context, writeIndex );
851         // Enables the received flag
852         context->ds[writeIndex].receivedBits |= MPHToMP16(aidBit);
853         (void)OSRestoreInterrupts(enabled);
854     }
855 }
856 
857 /*---------------------------------------------------------------------------*
858   Name:         SendDataSet
859 
860   Description:  After the parent confirms reception of each device's data, the data set is sent.
861 
862   Arguments:    context - MPDSContext structure.
863                 delayed:   TRUE if in frame delay state
864 
865   Returns:      None.
866  *---------------------------------------------------------------------------*/
SendDataSet(MPDSContext * context,BOOL delayed)867 void SendDataSet(MPDSContext *context, BOOL delayed)
868 {
869     BOOL enabled;
870 
871     enabled = OSDisableInterrupts();
872     // If and when reception has completed for all devices
873     // (The ds[].aidBits acts as unreceived flag during the receiving buffer)
874     if (context->ds[context->writeIndex].aidBits == MPHToMP16(0))
875     {
876         u16     newWI, oldWI, resetWI;
877         s32     res;
878         u32     mpReadyBits;
879 
880         MPDSiTrace("send ds   : write: %d, read: %d, send: %d", context->writeIndex,
881                              context->readIndex, context->sendIndex);
882 
883         mpReadyBits = MPGetConnectedAIDs();
884         oldWI = context->writeIndex;
885         newWI = GetNextIndex(oldWI);
886         if (context->config.isDoubleMode == TRUE)
887         {
888             resetWI = GetNextIndex(newWI);
889         }
890         else
891         {
892             resetWI = newWI;
893         }
894         ASSERT(newWI != context->readIndex && resetWI != context->readIndex);
895 //        ASSERT( context->sendIndex == context->writeIndex);
896         (void)NETMemSet(&context->ds[resetWI], 0, sizeof(MPDSDataSet));
897         MPDSiLOG_AIDBITS_BEGIN( context, resetWI );
898         context->ds[resetWI].aidBits = MPHToMP16((u16)(context->config.aidBits & (mpReadyBits | 0x0001)));
899         MPDSiLOG_AIDBITS_END( context, resetWI );
900         context->writeIndex = newWI;
901         MPDSiLOG_AIDBITS_BEGIN( context, oldWI );
902         context->ds[oldWI].aidBits = MPHToMP16((u16)context->config.aidBits);        // Enter the original value in aidBits before sending
903         if (delayed == TRUE)
904         {
905             // The lowest bit in the aidBits is a delay flag
906             context->ds[oldWI].aidBits &= MPHToMP16((u16)~0x0001);
907         }
908         MPDSiLOG_AIDBITS_END( context, oldWI );
909         (void)OSRestoreInterrupts(enabled);
910         res =
911             MPSendAsync( &context->ds[oldWI], context->dataSetLength,
912                          (u16)(context->config.aidBits & mpReadyBits), context->config.port,
913                          NULL, SetDataCallback, (void*)context );
914         if (res != MP_RESULT_OK)
915         {
916             MPDSiWarning("MPSendAsync failed during data-sharing. result=%x", res);
917             context->state = MPDS_STATE_ERROR;
918         }
919     }
920     else
921     {
922         (void)OSRestoreInterrupts(enabled);
923     }
924 }
925 
926 /*---------------------------------------------------------------------------*
927   Name:         GetSharedDataAddress
928 
929   Description:  Gets a specific AID address within the receive buffer.
930 
931   Arguments:    context     -   MPDSContext structure
932                 aidBits   -   Other communication peer(s) included in the data
933                 receiveBuf:   Receive buffer
934                 aid:           AID.
935                                 Confirm aidBits & (1<<aid) before calling this.
936 
937   Returns:      u16* :     The address of the received data.
938  *---------------------------------------------------------------------------*/
939 u8*
GetSharedDataAddress(const MPDSContext * context,u32 aidBits,u16 * receiveBuf,u32 aid)940 GetSharedDataAddress( const MPDSContext *context, u32 aidBits, u16 *receiveBuf, u32 aid)
941 {
942     u32     mask;
943     u32     count;
944     u32     offset;
945 
946     // Count the 1's among the aid bits in the aidBits, from the bottom
947     mask = (0x0001U << aid) - 1U;
948     aidBits &= mask;
949     count = CountPopulation(aidBits);
950     offset = context->config.dataLength * count;
951 
952     return ((u8 *)receiveBuf) + offset;
953 }
954 
955 #ifndef NDEBUG
956 /*---------------------------------------------------------------------------*
957   Name        : MPDSSetDebugLevel
958   Description : Change the level of debug output.
959   Arguments   : level - Debug output type bit to be output
960   Returns     : None.
961  *---------------------------------------------------------------------------*/
962 void
MPDSSetDebugLevel(u32 level)963 MPDSSetDebugLevel( u32 level )
964 {
965     MPDSi_debugLevel = level;
966 }
967 
968 /*---------------------------------------------------------------------------*
969   Name        : MPDSiVLogCore
970   Description : Outputs a log.
971   Arguments   : level   - Output level of the log.
972                 levelString - String notation for the output level.
973                 file  - Filename.
974                 func    - Function name.
975                 line    - Line number in file.
976                 fmt     - Text string to be output.
977                 vlist   - Variable-length arguments.
978   Returns     : None.
979  *---------------------------------------------------------------------------*/
980 void
MPDSiVLogCore(u32 level,const char * levelString,const char * file,const char * func,int line,const char * fmt,va_list vlist)981 MPDSiVLogCore( u32 level, const char* levelString,
982                const char* file, const char* func, int line, const char* fmt, va_list vlist )
983 {
984 #pragma unused( func )
985 
986     if( ! MPDSi_IS_DEBUG_LEVEL(level) )
987     {
988         return;
989     }
990 
991     {
992         OSReport( "%c[%04x|MPDS %s] ",
993                   (level & MPDSi_DEBUG_LEVEL_IMPORTANTS) ? '!' : ' ',
994                   (u32)(OSTicksToMilliseconds(OSGetTick())&0xffff),
995                   levelString );
996         if( fmt != NULL )
997         {
998             OSVReport( fmt, vlist );
999         }
1000         OSReport( " (%s:%d)\n", file, line );
1001     }
1002 }
1003 
1004 /*---------------------------------------------------------------------------*
1005   Name        : MPDSiLogCore
1006   Description : Outputs a log.
1007   Arguments   : level   - Output level of the log.
1008                 levelString - String notation for the output level.
1009                 file  - Filename.
1010                 func    - Function name.
1011                 line    - Line number in file.
1012                 fmt     - Text string to be output.
1013   Returns     : None.
1014  *---------------------------------------------------------------------------*/
1015 void
MPDSiLogCore(u32 level,const char * levelString,const char * file,const char * func,int line,const char * fmt,...)1016 MPDSiLogCore( u32 level, const char* levelString,
1017               const char* file, const char* func, int line, const char* fmt, ... )
1018 {
1019     va_list     vlist;
1020 
1021     va_start( vlist, fmt );
1022     MPDSiVLogCore( level, levelString, file, func, line, fmt, vlist );
1023     va_end( vlist );
1024 }
1025 #endif // !NDEBUG
1026 
1027 
CountPopulation(u32 x)1028 u8 CountPopulation( u32 x )
1029 {
1030     // Rather than counting 32 bits directly, first store the number of 1's for every 2 bits in the same location as those 2 bits.
1031     //
1032     // In other words, every 2 bits are converted such that 00 -> 00, 01 -> 01, 10 -> 01, and 11 -> 10.
1033     // When x -> x', for a 2-bit value we have x' = x - (x >> 1).
1034     x -= ((x >> 1) & 0x55555555);
1035 
1036     // When counting in 4-bit units, add the number of 1's stored in the upper and lower 2 bits, and then store this as the number of 1's in that original 4-bit location.
1037     //
1038     x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
1039 
1040     // Do the same for 8-bit units.
1041     // However, the maximum result for each digit is 8, and this fits in 4 bits, it is not necessary to mask ahead of time.
1042     //
1043     x += (x >> 4);
1044 
1045     // Mask unnecessary parts in preparation for the next operations.
1046     x &= 0x0f0f0f0f;
1047 
1048     // Get the sum of the upper 8 bits and lower 8 bits in 16-bit units.
1049     x += (x >> 8);
1050 
1051     // Do the same for 32-bit units.
1052     x += (x >> 16);
1053 
1054     // The lower 8-bit value is the result.
1055     return (u8)( x & 0xff );
1056 }
1057 
1058 /*---------------------------------------------------------------------------*
1059   End of file
1060  *---------------------------------------------------------------------------*/
1061