1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - MB - demos - multiboot-PowerSave
3 File: parent.c
4
5 Copyright 2006-2008 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 $Date:: 2009-03-02#$
14 $Rev: 10122 $
15 $Author: kitase_hirotake $
16 *---------------------------------------------------------------------------*/
17
18
19 #ifdef SDK_TWL
20 #include <twl.h>
21 #else
22 #include <nitro.h>
23 #endif
24
25 #include "common.h"
26 #include "dispfunc.h"
27
28
29 /*
30 * Basic processing on the parent
31 *
32 * Because the MB library samples use multiboot functionality, multiple development units with the same communications environment (wired or wireless) are required
33 *
34 * The mb_child_NITRO.srl and mb_child_TWL.srl sample programs in the $TwlSDK/bin/ARM9-TS/Rom/ directory provide the same features as a multiboot child for retail units. Load these binaries on other hardware as with any sample program, and run them together.
35 *
36 *
37 *
38 *
39 */
40
41
42 /******************************************************************************/
43 /* Declaration */
44
45 static void ParentInit(void);
46 static void ParentDraw(void);
47 static void ParentUpdate(void);
48
49
50 /******************************************************************************/
51 /* Constants */
52
53 /* DMA number to allocate to the MB library */
54 #define MB_DMA_NO 2
55
56 /* Parent's own GGID */
57 #define SDK_MAKEGGID_SYSTEM(num) (0x003FFF00 | (num))
58 #define MY_GGID SDK_MAKEGGID_SYSTEM(0x20)
59
60 /* Parent's initial distribution channel */
61 #define PARENT_CHANNEL 13
62
63
64 /******************************************************************************/
65 /* Variables */
66
67 /* The work region to be allocated to the MB library */
68 static u8 cwork[MB_SYSTEM_BUF_SIZE];
69
70 static u16 parent_channel = PARENT_CHANNEL;
71
72 static BOOL mb_running = FALSE;
73
74 /* The array of program information that this demo downloads */
75 static MBGameRegistry mbGameList[] = {
76 {
77 "/em.srl",
78 L"edgeDemo",
79 L"edgemarking demo",
80 "/data/icon.char",
81 "/data/icon.plt",
82 0 /* GGID */ ,
83 16 /* player-num */ ,
84 },
85 {
86 "/pol_toon.srl",
87 L"PolToon",
88 L"toon rendering",
89 "/data/icon.char",
90 "/data/icon.plt",
91 0 /* GGID */ ,
92 8 /* player-num */ ,
93 },
94 };
95
96 enum
97 { GAME_PROG_MAX = sizeof(mbGameList) / sizeof(*mbGameList) };
98
99 static u8 *p_segbuf[GAME_PROG_MAX] = { NULL, };
100
101
102 /******************************************************************************/
103 /* Functions */
104
105 /*---------------------------------------------------------------------------*
106 Name: changeChannel
107
108 Description: Cyclically changes channels.
109
110 Arguments: p_channel: AID of the child devices for notification
111 status: Notification status
112 arg: Callback argument
113
114 Returns: None.
115 *---------------------------------------------------------------------------*/
changeChannel(u16 channel)116 static u16 changeChannel(u16 channel)
117 {
118 const u16 channel_bak = channel;
119 u16 channel_bmp, i;
120
121 /* Get channel bitmap. */
122 channel_bmp = WM_GetAllowedChannel();
123
124 /* If there are no usable channels, call OS_Panic */
125 if (channel_bmp == 0)
126 {
127 OS_Panic("No Available Parent channel\n");
128 }
129 /* If there is a channel that can be used, it searches for a different channel from last time */
130 for (i = 0; i < 16; i++, channel = (u16)((channel == 16) ? 1 : channel + 1))
131 {
132 if (channel_bmp & (1 << (channel - 1)))
133 {
134 if (channel_bak != channel)
135 {
136 break;
137 }
138 }
139
140 }
141 return channel;
142 }
143
144 /*---------------------------------------------------------------------------*
145 Name: ParentStateCallback
146
147 Description: MB library status notification callback.
148
149 Arguments: aid: AID of the child devices for notification
150 status: Notification status
151 arg: Callback argument
152
153 Returns: None.
154 *---------------------------------------------------------------------------*/
ParentStateCallback(u16 aid,u32 status,void * arg)155 static void ParentStateCallback(u16 aid, u32 status, void *arg)
156 {
157
158 switch (status)
159 {
160 case MB_COMM_PSTATE_INIT_COMPLETE:
161 BgSetMessage(WHITE, "MB lib Init complete");
162 break;
163
164 case MB_COMM_PSTATE_CONNECTED:
165 {
166 WMStartParentCallback *p = (WMStartParentCallback *)arg;
167 BgSetMessage(YELLOW, "Connected(%2d)%02X:%02X:%02X:%02X:%02X:%02X", aid,
168 p->macAddress[0], p->macAddress[1], p->macAddress[2],
169 p->macAddress[3], p->macAddress[4], p->macAddress[5]);
170 }
171 break;
172
173 case MB_COMM_PSTATE_DISCONNECTED:
174 BgSetMessage(RED, "Disconnected [%2d]", aid);
175 break;
176
177 case MB_COMM_PSTATE_KICKED:
178 BgSetMessage(RED, "Entry Refused [%2d]", aid);
179 break;
180
181 case MB_COMM_PSTATE_REQ_ACCEPTED:
182 BgSetMessage(YELLOW, "Download Request [%2d]", aid);
183 break;
184
185 case MB_COMM_PSTATE_SEND_PROCEED:
186 BgSetMessage(CYAN, "Start Sending [%2d]", aid);
187 break;
188
189 case MB_COMM_PSTATE_SEND_COMPLETE:
190 BgSetMessage(CYAN, "Send Completed [%2d]", aid);
191 (void)MB_CommBootRequest(aid);
192 BgSetMessage(WHITE, "-->Boot Request [%2d]", aid);
193 break;
194
195 case MB_COMM_PSTATE_BOOT_REQUEST:
196 BgSetMessage(CYAN, "Send boot request [%2d]", aid);
197 break;
198
199 case MB_COMM_PSTATE_BOOT_STARTABLE:
200 BgSetMessage(YELLOW, "Boot ready [%2d]", aid);
201 break;
202
203 case MB_COMM_PSTATE_REQUESTED:
204 BgSetMessage(YELLOW, "Entry Requested [%2d]", aid);
205 (void)MB_CommResponseRequest(aid, MB_COMM_RESPONSE_REQUEST_ACCEPT);
206 BgSetMessage(WHITE, "-->Entry Accept [%2d]", aid);
207 break;
208
209 case MB_COMM_PSTATE_MEMBER_FULL:
210 BgSetMessage(RED, "Entry Member full [%2d]", aid);
211 break;
212
213 case MB_COMM_PSTATE_END:
214 BgSetMessage(WHITE, "MB lib End");
215 mb_running = FALSE;
216 break;
217
218 case MB_COMM_PSTATE_WAIT_TO_SEND:
219 BgSetMessage(CYAN, "Waiting to send [%2d]", aid);
220 (void)MB_CommStartSending(aid);
221 BgSetMessage(WHITE, "-->Start Sending [%2d]", aid);
222 break;
223 }
224
225 }
226
227 /*---------------------------------------------------------------------------*
228 Name: ParentInit
229
230 Description: Initializes the parent's status in Single-Card Play
231
232 Arguments: None.
233
234 Returns: None.
235 *---------------------------------------------------------------------------*/
ParentInit(void)236 static void ParentInit(void)
237 {
238 int i;
239 /* Initializes the parent in Single-Card Play */
240 {
241 MBUserInfo user;
242 /* Deallocates the previous segment buffer */
243 for (i = 0; i < GAME_PROG_MAX; ++i)
244 {
245 if (p_segbuf[i])
246 {
247 OS_Free(p_segbuf[i]), p_segbuf[i] = NULL;
248 }
249 }
250 /* Selects the parent device's name in accordance with power-save mode */
251 if (g_power_save_mode)
252 {
253 MI_CpuCopy8(L"Power:Save", user.name, 10 * sizeof(u16));
254 user.favoriteColor = OS_FAVORITE_COLOR_BLUE;
255 }
256 else
257 {
258 MI_CpuCopy8(L"Power:Full", user.name, 10 * sizeof(u16));
259 user.favoriteColor = OS_FAVORITE_COLOR_YELLOW;
260 }
261 user.nameLength = 10;
262 /* Initializes MB */
263 (void)MB_Init(cwork, &user, MY_GGID, MB_TGID_AUTO, MB_DMA_NO);
264 MB_SetPowerSaveMode(g_power_save_mode);
265 (void)MB_CommSetParentStateCallback(ParentStateCallback);
266 // MB_StartParent calls WM_Initialize internally
267 if(MB_StartParent(parent_channel) != MB_SUCCESS)
268 {
269 OS_Panic("MB_StartParent failed.");
270 }
271 }
272
273 GX_DispOn();
274 GXS_DispOn();
275
276 BgClear();
277 BgSetMessage(WHITE, "Initializing Parent.");
278 BgSetMessage(WHITE, "** Parameters **");
279 BgSetMessage(WHITE, "channel : %2d", parent_channel);
280 BgSetMessage(WHITE, "GGID:%08x TGID:%04x", MY_GGID, MB_GetTgid());
281
282 /* Registers the download program file information */
283 for (i = 0; i < GAME_PROG_MAX; ++i)
284 {
285 BOOL succeeded = FALSE;
286 FSFile file[1];
287 FS_InitFile(file);
288
289 if (!FS_OpenFileEx(file, mbGameList[i].romFilePathp, FS_FILEMODE_R))
290 {
291 OS_TPrintf("ParentInit : file cannot open (mbGameList[i].romFilePathp=\"%s)\"\n",
292 mbGameList[i].romFilePathp ? mbGameList[i].romFilePathp : "(NULL)");
293 }
294 else if ((p_segbuf[i] = (u8 *)OS_Alloc(MB_SEGMENT_BUFFER_MIN)) == NULL)
295 {
296 OS_TPrintf("ParentInit : memory allocation failed. (%d BYTE)\n", MB_SEGMENT_BUFFER_MIN);
297 }
298 else if (!MB_ReadSegment(file, p_segbuf[i], MB_SEGMENT_BUFFER_MIN))
299 {
300 OS_TPrintf("ParentInit : failed to extract segment\n");
301 }
302 else if (!MB_RegisterFile(&mbGameList[i], p_segbuf[i]))
303 {
304 OS_TPrintf("ParentInit : failed to register file No %d\n", i);
305 }
306 else
307 {
308 BgSetMessage(LIGHT_GREEN, "Registered\"%s\"", mbGameList[i].romFilePathp);
309 succeeded = TRUE;
310 }
311
312 if (FS_IsFile(file))
313 {
314 (void)FS_CloseFile(file);
315 }
316 if (!succeeded && (p_segbuf[i] != NULL))
317 {
318 OS_Free(p_segbuf[i]), p_segbuf[i] = NULL;
319 }
320 }
321 }
322
323 /*---------------------------------------------------------------------------*
324 Name: ParentUpdate
325
326 Description: Updates the parent's status in Single-Card Play.
327
328 Arguments: None.
329
330 Returns: None.
331 *---------------------------------------------------------------------------*/
ParentUpdate(void)332 static void ParentUpdate(void)
333 {
334 const u16 keyData = ReadKeySetTrigger();
335
336 /* When SELECT is pressed, end and re-initialize */
337 if ((keyData & PAD_BUTTON_SELECT) != 0)
338 {
339 /* Change channel */
340 parent_channel = changeChannel(parent_channel);
341 MB_End();
342 }
343
344 }
345
346 /*---------------------------------------------------------------------------*
347 Name: ParentUpdate
348
349 Description: Draws the parent's status in Single-Card Play.
350
351 Arguments: None.
352
353 Returns: None.
354 *---------------------------------------------------------------------------*/
ParentDraw(void)355 static void ParentDraw(void)
356 {
357 static const char *(pstate_string[]) =
358 {
359 "NONE ",
360 "INIT OK ",
361 "CONNECTED ",
362 "DISCONNECTED",
363 "KICKED ",
364 "ENTRY OK ",
365 "SENDING ",
366 "SEND END ",
367 "BOOT REQ ",
368 "BOOT READY ",
369 "ENTRY REQ ", "MEMBER FULL ", "END ", "ERROR ", "WAIT TO SEND",};
370 enum
371 { PSTATE_NUM = sizeof(pstate_string) / sizeof(*pstate_string) };
372 enum
373 { DISP_OX = 2, DISP_OY = 3 };
374
375 BgPrintf(DISP_OX, DISP_OY - 2, WHITE, "CH:%2d", parent_channel);
376 BgPutString(DISP_OX, DISP_OY - 1, WHITE, "AID USERNAME STATE ", 32);
377 BgPutString(DISP_OX, DISP_OY + MB_MAX_CHILD + 1, WHITE, "SEL:restart", 32);
378
379 /*
380 * Update the display for the download management state.
381 * All interrupts are blocked to prevent inconsistency in the individual states that are obtained.
382 */
383 {
384 OSIntrMode enabled = OS_DisableInterrupts();
385 int i;
386
387 /* Child list display */
388 for (i = 0; i < 15; ++i)
389 {
390 const u16 aid = (u16)(i + 1);
391 const MBUserInfo *p = MB_CommGetChildUser(aid);
392 const int state = MB_CommGetParentState(aid);
393
394 BgPrintf(DISP_OX + 0, DISP_OY + i, WHITE, "%2d ", aid);
395 if (p)
396 {
397 char name[MB_USER_NAME_LENGTH * 2 + 1] = { 0, };
398 MI_CpuCopy8(p->name, name, (u32)(p->nameLength * 2));
399 BgPutString(DISP_OX + 4, DISP_OY + i, p->favoriteColor, name, 8);
400 }
401 if (state < PSTATE_NUM)
402 {
403 BgPrintf(DISP_OX + 13, DISP_OY + i, WHITE, "%s", pstate_string[state]);
404 }
405 }
406
407 (void)OS_RestoreInterrupts(enabled);
408 }
409
410 }
411
412 /*---------------------------------------------------------------------------*
413 Name: ParentMode
414
415 Description: DS Single-Card play parent processing.
416
417 Arguments: None.
418
419 Returns: None.
420 *---------------------------------------------------------------------------*/
ParentMode(void)421 void ParentMode(void)
422 {
423 ParentInit();
424 /* Main loop */
425 mb_running = TRUE;
426 while (mb_running)
427 {
428 ParentUpdate();
429 ParentDraw();
430
431 OS_WaitVBlankIntr();
432 }
433 }
434