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