1 /*---------------------------------------------------------------------------*
2   Project:  Revolution MP simple 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: mpsimple.c,v $
14   Revision 1.17  2007/10/26 07:29:51  seiki_masashi
15   Cleaned up the code.
16 
17   Revision 1.16  2007/10/26 07:05:24  seiki_masashi
18   Revised the link level display.
19 
20   Revision 1.14  2007/10/26 05:48:03  seiki_masashi
21   Changed the prefix character for variables from 'g' to 's'.
22 
23   Revision 1.9  2007/10/04 09:41:19  seiki_masashi
24   Support for MP_BEACON_PERIOD_AUTO.
25 
26   Revision 1.8  2007/08/24 04:44:59  seiki_masashi
27   Changed the working memory size for the MP library from 32k to 64k.
28 
29   Revision 1.7  2006/11/26 14:22:12  seiki_masashi
30   Reduced the MP heap size to the current minimum value, 32kB.
31   Removed the debug output at data receive/transfer.
32 
33   Revision 1.6  2006/11/13 06:54:05  kitase_hirotake
34   Made changes so that buffer passed to MP is taken from MEM2.
35   Made changes so that REXDEMO will be used.
36 
37   Revision 1.5  2006/08/30 02:45:46  seiki_masashi
38   Made changes so that communication can be restarted with A Button.
39 
40   Revision 1.4  2006/08/14 14:39:50  yasu
41   Suppressed return value ignored warnings
42 
43   Revision 1.3  2006/07/03 13:38:41  seiki_masashi
44   added Life Time
45 
46   Revision 1.2  2006/07/03 08:36:31  seiki_masashi
47   Changed the thread priority level of MP communications.
48 
49   Revision 1.1  2006/07/02 11:34:43  seiki_masashi
50   Initial check-in
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 MPSend synchronous 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 /*===========================================================================*/
82 
83 static const GXColor white = { 0xFF, 0xFF, 0xFF, };
84 static const GXColor yellow = { 0xFF, 0xFF, 0x00, };
85 static const GXColor gray = { 0x80, 0x80, 0x80, };
86 static const GXColor black = { 0x00, 0x00, 0x00, };
87 static const GXColor red = { 0xFF, 0x00, 0x18 };
88 static const GXColor green = { 0x00, 0xFF, 0x00 };
89 
90 /*===========================================================================*/
91 
92 static void DoMPCommunication( void );
93 
94 static void* mpAlloc( u32 size );
95 static void mpFree( void* ptr );
96 static void PortCallbackFunction( s32 type, MPPortCallbackInfo* info );
97 
98 /*===========================================================================*/
99 
100 // The GGID is a unique ID for MP communications assigned to each application.
101 //   You must receive a GGID assignment from Nintendo for an actual application.
102 //   Here, a GGID is used that is identical to that of the demos/wm/simple-1 demo.
103 #define MY_GGID     0x003fff10
104 
105 // the port number used by MP communications to send and receive data
106 #define MY_PORT     4
107 
108 // MP communication settings
109 static MPConfig config =
110 {
111     mpAlloc,
112     mpFree,
113 
114     8,                  // threadPriority; set to a priority that is higher than the main thread by 4 or more
115 
116     MP_MODE_PARENT,     // mode
117 
118     MY_GGID,            // ggid
119     MP_TGID_AUTO,       // tgid
120 
121     1,                  // channel
122                         // Because the simple-1 demo of NITRO-SDK is fixed to ch1, parent device is also fixed to ch1
123                         //
124                         // Normally applications should use automatic settings by specifying MP_CHANNEL_AUTO
125 
126     MP_LIFETIME_DEFAULT,// lifeTime; usually equal to MP_LIFETIME_DEFAULT
127 
128     MP_BEACON_PERIOD_AUTO,  // beaconPeriod; normally MP_BEACON_PERIOD_AUTO
129     15,                 // maxNodes
130     4,                  // parentMaxSize
131     4,                  // childMaxSize
132     TRUE,               // entryFlag
133     FALSE,              // multiBootFlag; usually FALSE
134 
135     1,                  // frequency
136 
137     0,                  // userGameInfoLength
138     { 0, },             // userGameInfo
139 
140     NULL,               // indicationCallbackFunction
141 
142     /// ...             // port configuration (can be set up using MPSetPortConfig)
143 };
144 
main(void)145 void main(void)
146 {
147     /* initialize OS and memory heap */
148     OSReport("test program started.\n");
149     REXDEMOKPadInit();
150     REXDEMOInitScreen( FALSE );
151     REXDEMOSetGroundColor( black );
152     REXDEMOSetFontSize( 10, 20 );
153     REXDEMOBeginRender();
154     REXDEMOWaitRetrace();
155 
156     /* initialize heap for MP library */
157     {
158         void*   heapAddress;
159 
160         heapAddress = OSGetMEM2ArenaLo();
161         OSSetMEM2ArenaLo( (void*)OSRoundUp32B( (u32)heapAddress + USERHEAP_SIZE ) );
162         sUserHeap   = MEMCreateExpHeapEx( heapAddress, USERHEAP_SIZE, MEM_HEAP_OPT_THREAD_SAFE );
163         if( sUserHeap == NULL )
164         {
165             OSHalt( "Could not create heap.\n" );
166         }
167     }
168 
169     (void)PADInit();
170 
171     OSReport("push <A> button to restart.\n");
172     while (TRUE)
173     {
174         DoMPCommunication();
175     }
176 }
177 
DoMPCommunication(void)178 void DoMPCommunication( void )
179 {
180     s32 result;
181 
182     MPSetPortConfig( &config, MY_PORT, PortCallbackFunction, MP_PRIORITY_NORMAL );
183     OSReport("MPStartup()\n");
184     result = MPStartup( &config );
185     if( result != MP_RESULT_OK )
186     {
187         OSReport( "MPStartup returns %08x\n", result );
188         OSHalt( "** panic **\n" );
189     }
190 
191     {
192         static u32 frameData[512/sizeof(u32)] ATTRIBUTE_ALIGN(32);
193         u32 count;
194 
195         for( count = 0; TRUE; count++ )
196         {
197             u32 restBits;
198 
199             REXDEMOKPadRead();
200 
201             if( REXDEMOGetAnyMixedPadTrigger() & (KPAD_BUTTON_A | (PAD_BUTTON_A << 16)) )
202             {
203                 break;
204             }
205 
206             frameData[0] = MPHToMP32(count);
207 
208             result = MPSend( frameData, sizeof(u32), 0xfffe, MY_PORT, &restBits );
209 
210             if( result == MP_RESULT_OK )
211             {
212                 if( restBits == 0 )
213                 {
214                     // transmissions to all destinations succeeded
215                 }
216                 else
217                 {
218                     // transmissions to some child devices failed
219                     // A list of the child devices for whom transmission failed is stored in restBits.
220                 }
221             }
222             else
223             {
224                 // failed to send an asynchronous transmission request
225                 OSReport("MPSend failed: %08x\n", result);
226             }
227 
228             REXDEMOBeginRender();
229 
230             REXDEMOSetTextColor(green);
231             REXDEMOPrintf(40, 8, 0, "Parent mode");
232             REXDEMOSetTextColor(white);
233             REXDEMOPrintf(4, 400, 0, "push <A> button to restart.");
234 
235             REXDEMOSetTextColor(green);
236             {
237                 s32 linkLevel = MPGetLinkLevel();
238                 REXDEMOPrintf(480, 400, 0, "Link Level: %d", (linkLevel >= 0) ? linkLevel : 0);
239             }
240 
241             REXDEMOSetTextColor(yellow);
242             REXDEMOPrintf(4, 30, 0, "Send:     %08X", count);
243             REXDEMOPrintf(4, 52, 0, "Receive:");
244             {
245                 s32     i;
246 
247                 for (i = 1; i < MP_AID_MAX; i++)
248                 {
249                     if (sRecvFlag[i])
250                     {
251                         REXDEMOSetTextColor(yellow);
252                         REXDEMOPrintf(40, (s16)(60 + i * 20), 0, "Child%02d: %08X", i, sRecvBuf[i]);
253                     }
254                     else
255                     {
256                         REXDEMOSetTextColor(red);
257                         REXDEMOPrintf(40, (s16)(60 + i * 20), 0, "No child");
258                     }
259                 }
260             }
261 
262             REXDEMOSetTextColor(white);
263             REXDEMOWaitRetrace();
264         }
265     }
266 
267     OSReport("MPCleanup()\n");
268     (void)MPCleanup();
269 }
270 
271 /*===========================================================================*/
272 
PortCallbackFunction(s32 type,MPPortCallbackInfo * info)273 void PortCallbackFunction( s32 type, MPPortCallbackInfo* info )
274 {
275 
276     // This function is called from a thread for MP library callbacks.
277     // 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.
278     //
279     // Keep blocking used for exclusive access to a minimum.
280     // Depending on the situation, consider methods of transferring data that do not block, such as those that use OSMessageQueue.
281     //
282 
283     switch( type )
284     {
285     case MP_PORT_CB_TYPE_STARTUP:
286         OSReport( "PortCallback: startup notification\n" );
287         break;
288 
289     case MP_PORT_CB_TYPE_CLEANUP:
290         OSReport( "PortCallback: cleanup notification\n" );
291         break;
292 
293     case MP_PORT_CB_TYPE_CONNECTED:
294         // A connection notification was received from a child device.
295         sRecvFlag[info->dataReceived.fromAid] = TRUE;
296         OSReport( "PortCallback: connected(%d) " MP_MACADDRESS_PRINT_FORMAT "\n",
297                   info->connected.fromAid,
298                   MP_MACADDRESS_PRINT_LIST(info->connected.macAddress) );
299         break;
300 
301     case MP_PORT_CB_TYPE_DISCONNECTED:
302         // A disconnection notification was received from a child device.
303         sRecvFlag[info->dataReceived.fromAid] = FALSE;
304         OSReport( "PortCallback: disconnected(%d) " MP_MACADDRESS_PRINT_FORMAT "\n",
305                   info->disconnected.fromAid,
306                   MP_MACADDRESS_PRINT_LIST(info->disconnected.macAddress) );
307         break;
308 
309     case MP_PORT_CB_TYPE_DATA_RECEIVED:
310         // Data was received from a child device.
311         // The contents of info->dataReceived.data are guaranteed only within this callback and must therefore be quickly copied to an application buffer.
312         //
313         sRecvBuf[info->dataReceived.fromAid] = MPMPToH32(*(u32*)info->dataReceived.data);
314 //        OSReport( "PortCallback: received data from aid %d: %08x\n",
315 //                  info->dataReceived.fromAid,
316 //                  MPMPToH32(*(u32*)info->dataReceived.data) );
317         break;
318 
319     default:
320         OSReport( "PortCallback: Unknown Type: %d\n", type );
321         break;
322     }
323 }
324 
325 /*===========================================================================*/
326 
mpAlloc(u32 size)327 void* mpAlloc( u32 size )
328 {
329     return MEMAllocFromExpHeapEx( sUserHeap, size, 32 );
330 }
331 
mpFree(void * ptr)332 void mpFree( void* ptr )
333 {
334     MEMFreeToExpHeap( sUserHeap, ptr );
335 }
336 
337