1 /*---------------------------------------------------------------------------*
2   Project:  Revolution MP simple async demo
3   File:     mpsimple.c
4 
5   Copyright 2006 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: mpsimpleAsync.c,v $
14   Revision 1.16  2007/10/26 07:29:51  seiki_masashi
15   Cleaned up the code.
16 
17   Revision 1.15  2007/10/26 07:05:24  seiki_masashi
18   Revised the link level display.
19 
20   Revision 1.13  2007/10/26 05:48:03  seiki_masashi
21   Changed the prefix character for variables from 'g' to 's'.
22 
23   Revision 1.8  2007/10/04 09:41:19  seiki_masashi
24   Support for MP_BEACON_PERIOD_AUTO.
25 
26   Revision 1.7  2007/10/03 04:58:41  seiki_masashi
27   Corrections following specification changes to the MPSendAsync function.
28 
29   Revision 1.6  2007/08/24 04:44:59  seiki_masashi
30   Changed the working memory size for the MP library from 32k to 64k.
31 
32   Revision 1.5  2007/08/01 09:36:29  kitase_hirotake
33   Changed TAB to SPACE.
34 
35   Revision 1.4  2006/11/26 14:22:12  seiki_masashi
36   Reduced the MP heap size to the current minimum value, 32kB.
37   Removed the debug output at data receive/transfer.
38 
39   Revision 1.3  2006/11/13 06:54:10  kitase_hirotake
40   Made changes so that buffer passed to MP is taken from MEM2.
41   Made changes so that REXDEMO will be used.
42 
43   Revision 1.2  2006/09/08 11:54:02  yosizaki
44   Revised the include file.
45 
46   Revision 1.1  2006/08/23 04:33:20  kitase_hirotake
47   Added mpsimpleAsync.
48 
49   Revision 1.1  2006/08/22 01:44:42  kitase_hirotake
50   Initial upload
51 
52   $NoKeywords: $
53  *---------------------------------------------------------------------------*/
54 
55 //
56 // This sample performs MP communications with the demos/wm/simple-1 demo in the NITRO-SDK.
57 // The MPSendAsync asynchronous transmission function is used.
58 //
59 // This demo only performs a minimal amount of processing to determine if communications are being performed.
60 // Refer to the mpdsmodel demo, an MPDS library demo, when creating an actual application.
61 //
62 //
63 
64 #include <string.h>
65 #include <revolution.h>
66 #include <revolution/mp.h>
67 #include <revolution/mem.h>
68 
69 #include "rexdemo/demokpad.h"
70 #include "rexdemo/graphic.h"
71 
72 #define     USERHEAP_SIZE ( 65536 )
73 
74 /*===========================================================================*/
75 
76 static MEMHeapHandle    sUserHeap;
77 
78 static u32 sRecvBuf[MP_AID_MAX];
79 static BOOL sRecvFlag[MP_AID_MAX];
80 
81 static OSMessageQueue sMessageQueue;
82 static OSMessage      sMessageArray[16]; // This demo only uses one level.
83 
84 /*===========================================================================*/
85 
86 static const GXColor white = { 0xFF, 0xFF, 0xFF, };
87 static const GXColor yellow = { 0xFF, 0xFF, 0x00, };
88 static const GXColor gray = { 0x80, 0x80, 0x80, };
89 static const GXColor black = { 0x00, 0x00, 0x00, };
90 static const GXColor red = { 0xFF, 0x00, 0x18 };
91 static const GXColor green = { 0x00, 0xFF, 0x00 };
92 
93 /*===========================================================================*/
94 
95 void* myAlloc( u32 size );
96 void myFree( void* ptr );
97 
98 static void PortCallbackFunction( s32 type, MPPortCallbackInfo* info );
99 static void SendAsyncCallbackFunction( s32 result, struct MPCallbackInfo *info );
100 
101 /*===========================================================================*/
102 
103 // The GGID is a unique ID for MP communications assigned to each application.
104 //   You must receive a GGID assignment from Nintendo for an actual application.
105 //   Here, a GGID is used that is identical to that of the demos/wm/simple-1 demo.
106 #define MY_GGID     0x003fff10
107 
108 // the port number used by MP communications to send and receive data
109 #define MY_PORT     4
110 
111 // MP communication settings
112 static MPConfig config =
113 {
114     myAlloc,
115     myFree,
116 
117     8,                  // threadPriority; set to a priority that is higher than the main thread by 4 or more
118 
119     MP_MODE_PARENT,     // mode
120 
121     MY_GGID,            // ggid
122     MP_TGID_AUTO,       // tgid
123 
124     1,                  // channel
125                         // Because the simple-1 demo of NITRO-SDK is fixed to ch1, parent device is also fixed to ch1
126                         //
127                         // Normally applications should use automatic settings by specifying MP_CHANNEL_AUTO.
128 
129     MP_LIFETIME_DEFAULT,// lifeTime; usually equal to MP_LIFETIME_DEFAULT
130 
131     MP_BEACON_PERIOD_AUTO,  // beaconPeriod; normally MP_BEACON_PERIOD_AUTO
132     15,                 // maxNodes
133     4,                  // parentMaxSize
134     4,                  // childMaxSize
135     TRUE,               // entryFlag
136     FALSE,              // multiBootFlag; usually FALSE
137 
138     1,                  // frequency
139 
140     0,                  // userGameInfoLength
141     { 0, },             // userGameInfo
142 
143     NULL,               // indicationCallbackFunction
144 
145     /// ...             // port configuration (can be set up using MPSetPortConfig)
146 };
147 
main(void)148 void main(void)
149 {
150     s32 result;
151 
152     /* initialize OS and memory heap */
153     OSReport("test program started.\n");
154     REXDEMOKPadInit();
155     REXDEMOInitScreen( FALSE );
156     REXDEMOSetGroundColor( black );
157     REXDEMOSetFontSize( 10, 20 );
158     REXDEMOBeginRender();
159     REXDEMOWaitRetrace();
160 
161     /* initialize heap for MP library */
162     {
163         void*   heapAddress;
164 
165         heapAddress = OSGetMEM2ArenaLo();
166         OSSetMEM2ArenaLo( (void*)OSRoundUp32B( (u32)heapAddress + USERHEAP_SIZE ) );
167         sUserHeap   = MEMCreateExpHeapEx( heapAddress, USERHEAP_SIZE, MEM_HEAP_OPT_THREAD_SAFE );
168         if( sUserHeap == NULL )
169         {
170             OSHalt( "Could not create heap.\n" );
171         }
172     }
173 
174     //
175     // initializes the message queue
176     //
177     OSInitMessageQueue(
178         &sMessageQueue,
179         sMessageArray,
180         sizeof sMessageArray / sizeof sMessageArray[0]);
181 
182     while(TRUE)
183     {
184         MPSetPortConfig( &config, MY_PORT, PortCallbackFunction, MP_PRIORITY_NORMAL );
185         OSReport("MPStartup()\n");
186         result = MPStartup( &config );
187         if( result != MP_RESULT_OK )
188         {
189             OSReport( "MPStartup returns %08x\n", result );
190             OSHalt( "** panic **\n" );
191         }
192 
193         {
194             static u32 frameData[512/sizeof(u32)] ATTRIBUTE_ALIGN(32);
195             u32 count = 0;
196 
197             u32 restBits = 0;
198             frameData[0] = MPHToMP32(count);
199 
200             for( count = 0; TRUE; count++ )
201             {
202                 OSMessage msg;
203 
204                 REXDEMOKPadRead();
205 
206                 if( REXDEMOGetAnyMixedPadTrigger() & (KPAD_BUTTON_A | (PAD_BUTTON_A << 16)) )
207                 {
208                     break;
209                 }
210 
211                 frameData[0] = MPHToMP32(count);
212 
213                 result = MPSendAsync ( frameData, sizeof(u32), 0xfffe, MY_PORT, &restBits, SendAsyncCallbackFunction, NULL );
214 
215                 if( result == MP_RESULT_OK )
216                 {
217                     // Succeeded in sending an asynchronous transmission request.
218                     // The success or failure of communications can be determined by referencing restBits after a notification has come in SendAsyncCallbackFunction.
219                     //
220 
221                     // Using MessageQueue, wait for a notification to come to the callback.
222                     (void)OSReceiveMessage(&sMessageQueue, &msg, OS_MESSAGE_BLOCK);
223 
224                     // There is now a valid result stored in restBits.
225                     if( restBits == 0 )
226                     {
227                         // transmissions to all destinations succeeded
228                     }
229                     else
230                     {
231                         // transmissions to some child devices failed
232                         // A list of the child devices for whom transmission failed is stored in restBits.
233                     }
234                 }
235                 else
236                 {
237                     // failed to send an asynchronous transmission request
238                     // when the number of simultaneous MP function callers exceeded the upper limit of 32
239                     OSReport("MPSendAsync failed: %08x\n", result);
240                 }
241 
242                 REXDEMOBeginRender();
243 
244                 REXDEMOSetTextColor(green);
245                 REXDEMOPrintf(40, 8, 0, "Parent mode");
246                 REXDEMOSetTextColor(white);
247                 REXDEMOPrintf(4, 400, 0, "push <A> button to restart.");
248 
249                 REXDEMOSetTextColor(green);
250                 {
251                     s32 linkLevel = MPGetLinkLevel();
252                     REXDEMOPrintf(480, 400, 0, "Link Level: %d", (linkLevel >= 0) ? linkLevel : 0);
253                 }
254 
255                 REXDEMOSetTextColor(yellow);
256                 REXDEMOPrintf(4, 30, 0, "Send:      %08x", count);
257                 REXDEMOPrintf(4, 52, 0, "Receive:");
258 
259                 {
260                     int     i;
261 
262                     for (i = 1; i < MP_AID_MAX; i++)
263                     {
264                         if (sRecvFlag[i])
265                         {
266                             REXDEMOSetTextColor(yellow);
267                             REXDEMOPrintf(40, (s16)(60 + i * 20), 0, "Child%02d: %08x", i, sRecvBuf[i]);
268                         }
269                         else
270                         {
271                             REXDEMOSetTextColor(red);
272                             REXDEMOPrintf(40, (s16)(60 + i * 20), 0, "No child");
273                         }
274                     }
275                 }
276 
277                 REXDEMOSetTextColor(white);
278                 REXDEMOWaitRetrace();
279             }
280         }
281 
282         OSReport("MPCleanup()\n");
283         (void)MPCleanup();
284     }
285 }
286 
287 /*===========================================================================*/
288 
SendAsyncCallbackFunction(s32 result,struct MPCallbackInfo * info)289 void SendAsyncCallbackFunction( s32 result, struct MPCallbackInfo *info )
290 {
291 #pragma unused(result)
292 #pragma unused(info)
293 
294     // This function is called from a thread for MP library callbacks.
295     // This is not an interrupt callback, so functions for synchronizing threads can be called. However, these functions will affect MP communications if they block for too long.
296     //
297     // Keep blocking used for exclusive access to a minimum.
298     // Depending on the situation, consider methods of transferring data that do not block, such as those that use OSMessageQueue.
299     //
300 
301     // Notify the main thread that an asynchronous transmission request has completed.
302     //   In this demo, MPSendAsync is not invoked multiple times simultaneously. Consequently, blocking due to a full MessageQueue will not occur.
303     //
304     (void)OSSendMessage(&sMessageQueue, "Hello!", OS_MESSAGE_BLOCK);
305 }
306 
PortCallbackFunction(s32 type,MPPortCallbackInfo * info)307 void PortCallbackFunction( s32 type, MPPortCallbackInfo* info )
308 {
309 
310     // This function is called from a thread for MP library callbacks.
311     // This is not an interrupt callback, so functions for synchronizing threads can be called. However, these functions will affect MP communications if they block for too long.
312     //
313     // Keep blocking used for exclusive access to a minimum.
314     // Depending on the situation, consider methods of transferring data that do not block, such as those that use OSMessageQueue.
315     //
316 
317     switch( type )
318     {
319     case MP_PORT_CB_TYPE_STARTUP:
320         OSReport( "PortCallback: startup notification\n" );
321         break;
322 
323     case MP_PORT_CB_TYPE_CLEANUP:
324         OSReport( "PortCallback: cleanup notification\n" );
325         break;
326 
327     case MP_PORT_CB_TYPE_CONNECTED:
328         // A connection notification was received from a child device.
329         sRecvFlag[info->dataReceived.fromAid] = TRUE;
330         OSReport( "PortCallback: connected(%d) " MP_MACADDRESS_PRINT_FORMAT "\n",
331                   info->connected.fromAid,
332                   MP_MACADDRESS_PRINT_LIST(info->connected.macAddress) );
333         break;
334 
335     case MP_PORT_CB_TYPE_DISCONNECTED:
336         // A disconnection notification was received from a child device.
337         sRecvFlag[info->dataReceived.fromAid] = FALSE;
338         OSReport( "PortCallback: disconnected(%d) " MP_MACADDRESS_PRINT_FORMAT "\n",
339                   info->disconnected.fromAid,
340                   MP_MACADDRESS_PRINT_LIST(info->disconnected.macAddress) );
341         break;
342 
343     case MP_PORT_CB_TYPE_DATA_RECEIVED:
344         // Data was received from a child device.
345         // The contents of info->dataReceived.data are guaranteed only within this callback and must therefore be quickly copied to an application buffer.
346         //
347         sRecvBuf[info->dataReceived.fromAid] = MPMPToH32(*(u32*)info->dataReceived.data);
348 //        OSReport( "PortCallback: received data from aid %d: %08x\n",
349 //                  info->dataReceived.fromAid,
350 //                  MPMPToH32(*(u32*)info->dataReceived.data) );
351         break;
352 
353     default:
354         OSReport( "PortCallback: Unknown Type: %d\n", type );
355         break;
356     }
357 }
358 
359 /*===========================================================================*/
360 
myAlloc(u32 size)361 void* myAlloc( u32 size )
362 {
363     return MEMAllocFromExpHeapEx( sUserHeap, size, 32 );
364 }
365 
myFree(void * ptr)366 void myFree( void* ptr )
367 {
368     MEMFreeToExpHeap( sUserHeap, ptr );
369 }
370 
371