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