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