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