1   /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - wireless_shared - demos - mbp
3   File:     mbp.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:: 2008-10-02#$
14   $Rev: 8827 $
15   $Author: yosizaki $
16  *---------------------------------------------------------------------------*/
17 #include <nitro.h>
18 #include <nitro/wm.h>
19 #include <nitro/mb.h>
20 
21 #include "mbp.h"
22 
23 
24 
25 
26 //============================================================================
27 //  Prototype Declarations
28 //============================================================================
29 
30 static BOOL MBP_RegistFile(const MBGameRegistry *gameInfo);
31 static inline void MBP_AddBitmap(u16 *pBitmap, u16 aid);
32 static inline void MBP_RemoveBitmap(u16 *pBitmap, u16 aid);
33 static inline void MBP_DisconnectChild(u16 aid);
34 static inline void MBP_DisconnectChildFromBmp(u16 aid);
35 static void ParentStateCallback(u16 child_aid, u32 status, void *arg);
36 static void MBP_ChangeState(u16 state);
37 
38 
39 // Callbacks are run by IRQs, so it is safer to set a slightly large IRQ stack size in the LCF file when running complex processes within a callback.
40 //
41 //
42 // Because OS_Printf() in particular consumes a large amount of stack, try using the lighter version, OS_TPrintf(), in callbacks whenever possible.
43 //
44 
45 #define MBP_DEBUG
46 #if defined( MBP_DEBUG )
47 #define MBP_Printf          OS_TPrintf //
48 #else
49 #define MBP_Printf(...)     ((void)0)
50 #endif
51 
52 
53 
54 //============================================================================
55 //  Variable Definitions
56 //============================================================================
57 
58 // Child connection information
59 static MBPState mbpState;
60 static MBPChildInfo childInfo[MBP_CHILD_MAX];
61 
62 /* The work region to be allocated to the MB library */
63 static u32 *sCWork = NULL;
64 
65 /* Buffer for child device startup binary transmission */
66 static u8 *sFilebuf = NULL;
67 
68 //============================================================================
69 //  Function definitions
70 //============================================================================
71 
72 /*---------------------------------------------------------------------------*
73   Name:         MBP_Init
74 
75   Description:  Initializes the multiboot parent information.
76 
77   Arguments:    ggid  Specifies the parent's GGID when distributing a game
78                 tgid  Specifies the parent's TGID when distributing a game
79 
80   Returns:      None.
81  *---------------------------------------------------------------------------*/
MBP_Init(u32 ggid,u16 tgid)82 void MBP_Init(u32 ggid, u16 tgid)
83 {
84     /* For the configuration of the parent device information to be displayed to the child device screen */
85     MBUserInfo myUser;
86 
87     /* It is not precisely determined what type of value needs to be specified as the parent information to display on the MB child screen.
88      * Here, user information registered with the IPL is set as the MB parent information, but the name established within the game may be set.
89      * However, this must be set as 2-byte code.
90      *
91      * */
92     OSOwnerInfo info;
93 
94     OS_GetOwnerInfo(&info);
95     myUser.favoriteColor = info.favoriteColor;
96     myUser.nameLength = (u8)info.nickNameLength;
97     MI_CpuCopy8(info.nickName, myUser.name, (u32)(info.nickNameLength * 2));
98 
99 
100     myUser.playerNo = 0;               // The parent is number 0
101 
102     // Initialize the status information
103     mbpState = (const MBPState)
104     {
105     MBP_STATE_STOP, 0, 0, 0, 0, 0, 0};
106 
107     /* Begin MB parent device control */
108     // Allocate the MB work area
109 #if !defined(MBP_USING_MB_EX)
110     sCWork = OS_Alloc(MB_SYSTEM_BUF_SIZE);
111 #else
112     /* A small work size does not matter if WM initialization has been finished externally */
113     sCWork = OS_Alloc(MB_SYSTEM_BUF_SIZE - WM_SYSTEM_BUF_SIZE);
114 #endif
115 
116     if (MB_Init(sCWork, &myUser, ggid, tgid, MBP_DMA_NO) != MB_SUCCESS)
117     {
118         OS_Panic("ERROR in MB_Init\n");
119     }
120 
121     // Set the maximum number of children to be connected (set a value that excludes the parent)
122     (void)MB_SetParentCommParam(MB_COMM_PARENT_SEND_MIN, MBP_CHILD_MAX);
123 
124     MB_CommSetParentStateCallback(ParentStateCallback);
125 
126     MBP_ChangeState(MBP_STATE_IDLE);
127 }
128 
129 
130 /*---------------------------------------------------------------------------*
131   Name:         MBP_Start
132 
133   Description:  Starts multiboot parent.
134 
135   Arguments:    gameInfo Distribution binary information
136                 channel  Channel to be used
137 
138   Returns:      None.
139  *---------------------------------------------------------------------------*/
MBP_Start(const MBGameRegistry * gameInfo,u16 channel)140 void MBP_Start(const MBGameRegistry *gameInfo, u16 channel)
141 {
142     SDK_ASSERT(MBP_GetState() == MBP_STATE_IDLE);
143 
144     MBP_ChangeState(MBP_STATE_ENTRY);
145 #if !defined(MBP_USING_MB_EX)
146     if (MB_StartParent(channel) != MB_SUCCESS)
147 #else
148     /* Transfer the WM library to an IDLE state, and directly begin */
149     if (MB_StartParentFromIdle(channel) != MB_SUCCESS)
150 #endif
151     {
152         MBP_Printf("MB_StartParent fail\n");
153         MBP_ChangeState(MBP_STATE_ERROR);
154         return;
155     }
156 
157     /* --------------------------------------------------------------------- *
158      * This will have been initialized when MB_StartParent() is called.
159      * Use MB_RegisterFile() for registration after MB_StartParent().
160      * --------------------------------------------------------------------- */
161 
162     /* Register the download program file information */
163     if (!MBP_RegistFile(gameInfo))
164     {
165         OS_Panic("Illegal multiboot gameInfo\n");
166     }
167 }
168 
169 
170 /*---------------------------------------------------------------------------*
171   Name:         MBP_RegistFile
172 
173   Description:  Registers the multiboot binary.
174 
175   Arguments:    gameInfo Pointer to the multiboot binary information.
176                          Of these members, a romFilePathp value of NULL will cause operations to be the same as when a clone boot has been specified.
177 
178 
179   Returns:      Returns TRUE if the file open was successful.
180                 If failed, returns FALSE.
181  *---------------------------------------------------------------------------*/
MBP_RegistFile(const MBGameRegistry * gameInfo)182 static BOOL MBP_RegistFile(const MBGameRegistry *gameInfo)
183 {
184     FSFile  file, *p_file;
185     u32     bufferSize;
186     BOOL    ret = FALSE;
187 
188     /* --------------------------------------------------------------------- *
189      * This will already be initialized when MB_StartParent() is called, even if before that binary data was registered with MB_RegisterFile().
190      *
191      * Use MB_RegisterFile() for registration after MB_StartParent().
192      * --------------------------------------------------------------------- */
193 
194     /*
195      * As given by this function's specifications, this will operate as a clone boot if romFilePathp is NULL.
196      *
197      * If not, the specified file will be treated as a child program.
198      */
199     if (!gameInfo->romFilePathp)
200     {
201         p_file = NULL;
202     }
203     else
204     {
205         /*
206          * The program file must be read using FS_ReadFile().
207          * Usually, programs are maintained as files in CARD-ROM and pose no problems. If you anticipate a special multi-boot system, however, use FSArchive to build an original archive to handle it.
208          *
209          *
210          */
211         FS_InitFile(&file);
212         if (!FS_OpenFileEx(&file, gameInfo->romFilePathp, FS_FILEMODE_R))
213         {
214             /* Cannot open file */
215             OS_Warning("Cannot Register file\n");
216             return FALSE;
217         }
218         p_file = &file;
219     }
220 
221     /*
222      * Get the size of the segment information.
223      * If this is not a valid download program, 0 will be returned for this size.
224      *
225      */
226     bufferSize = MB_GetSegmentLength(p_file);
227     if (bufferSize == 0)
228     {
229         OS_Warning("specified file may be invalid format.\"%s\"\n",
230                    gameInfo->romFilePathp ? gameInfo->romFilePathp : "(cloneboot)");
231     }
232     else
233     {
234         /*
235          * Allocate memory for loading the download program's segment information.
236          * If file registration succeeded, this region will be used until MB_End() is called.
237          * This memory may be prepared statically as long as it is large enough.
238          *
239          */
240         sFilebuf = OS_Alloc(bufferSize);
241         if (sFilebuf == NULL)
242         {
243             /* Failed to allocate buffer that stores segment information */
244             OS_Warning("can't allocate Segment buffer size.\n");
245         }
246         else
247         {
248             /*
249              * Extract segment information from the file.
250              * The extracted segment information must stay resident in main memory while the download program is being distributed.
251              *
252              */
253             if (!MB_ReadSegment(p_file, sFilebuf, bufferSize))
254             {
255                 /*
256                  * Failed to extract segments because the file is invalid.
257                  * If extraction fails here even though the size was obtained successfully, it may be because the file handle was changed in some way.
258                  * (The file was closed, a seek to some location was run, and so on)
259                  *
260                  */
261                 OS_Warning(" Can't Read Segment\n");
262             }
263             else
264             {
265                 /*
266                  * Register the download program in the MBGameRegistry with the extracted segment information.
267                  *
268                  */
269                 if (!MB_RegisterFile(gameInfo, sFilebuf))
270                 {
271                     /* Registration failed because of incorrect program information */
272                     OS_Warning(" Illegal program info\n");
273                 }
274                 else
275                 {
276                     /* Process completed correctly */
277                     ret = TRUE;
278                 }
279             }
280             if (!ret)
281                 OS_Free(sFilebuf);
282         }
283     }
284 
285     /* Close file if not clone boot */
286     if (p_file == &file)
287     {
288         (void)FS_CloseFile(&file);
289     }
290 
291     return ret;
292 }
293 
294 
295 /*---------------------------------------------------------------------------*
296   Name:         MBP_AcceptChild
297 
298   Description:  Accepts a request from a child.
299 
300   Arguments:    child_aid       AID of a connected child.
301 
302   Returns:      None.
303  *---------------------------------------------------------------------------*/
MBP_AcceptChild(u16 child_aid)304 void MBP_AcceptChild(u16 child_aid)
305 {
306     if (!MB_CommResponseRequest(child_aid, MB_COMM_RESPONSE_REQUEST_ACCEPT))
307     {
308         // If the request fails, disconnect that child
309         MBP_DisconnectChild(child_aid);
310         return;
311     }
312 
313     MBP_Printf("accept child %d\n", child_aid);
314 }
315 
316 
317 /*---------------------------------------------------------------------------*
318   Name:         MBP_KickChild
319 
320   Description:  Kicks the connected child.
321 
322   Arguments:    child_aid       AID of a connected child
323 
324   Returns:      None.
325  *---------------------------------------------------------------------------*/
MBP_KickChild(u16 child_aid)326 void MBP_KickChild(u16 child_aid)
327 {
328     if (!MB_CommResponseRequest(child_aid, MB_COMM_RESPONSE_REQUEST_KICK))
329     {
330         // If the request fails, disconnect that child
331         MBP_DisconnectChild(child_aid);
332         return;
333     }
334 
335     {
336         OSIntrMode enabled = OS_DisableInterrupts();
337 
338         mbpState.requestChildBmp &= ~(1 << child_aid);
339         mbpState.connectChildBmp &= ~(1 << child_aid);
340 
341         (void)OS_RestoreInterrupts(enabled);
342     }
343 }
344 
345 
346 /*---------------------------------------------------------------------------*
347   Name:         MBP_StartDownload
348 
349   Description:  Sends the download start signals to the child.
350 
351   Arguments:    child_aid      AID of a connected child
352 
353   Returns:      None.
354  *---------------------------------------------------------------------------*/
MBP_StartDownload(u16 child_aid)355 void MBP_StartDownload(u16 child_aid)
356 {
357     if (!MB_CommStartSending(child_aid))
358     {
359         // If the request fails, disconnect that child
360         MBP_DisconnectChild(child_aid);
361         return;
362     }
363 
364     {
365         OSIntrMode enabled = OS_DisableInterrupts();
366 
367         mbpState.entryChildBmp &= ~(1 << child_aid);
368         mbpState.downloadChildBmp |= 1 << child_aid;
369 
370         (void)OS_RestoreInterrupts(enabled);
371     }
372 }
373 
374 /*---------------------------------------------------------------------------*
375   Name:         MBP_StartDownloadAll
376 
377   Description:  Starts the data transfer to all of the children currently being entered.
378                 After this, it does not accept entries from children.
379 
380   Arguments:    None.
381 
382   Returns:      None.
383  *---------------------------------------------------------------------------*/
MBP_StartDownloadAll(void)384 void MBP_StartDownloadAll(void)
385 {
386     u16     i;
387 
388     // Stop accepting entries
389     MBP_ChangeState(MBP_STATE_DATASENDING);
390 
391     for (i = 1; i < 16; i++)
392     {
393         if (!(mbpState.connectChildBmp & (1 << i)))
394         {
395             continue;
396         }
397 
398 #ifdef MBP_USING_PREVIOUS_DOWNLOAD
399         /* When data transfer has started immediately after entry */
400         // Disconnect children that are not being entered
401         if (MBP_GetChildState(i) == MBP_CHILDSTATE_CONNECTING)
402         {
403             MBP_DisconnectChild(i);
404             continue;
405         }
406 #else
407         /* When starting to send data to all child devices at once */
408         if (mbpState.requestChildBmp & (1 << i))
409         {
410             // The child currently being entered will be processed after it becomes ready
411             continue;
412         }
413 
414         // Disconnect children that are not being entered
415         if (!(mbpState.entryChildBmp & (1 << i)))
416         {
417             MBP_DisconnectChild(i);
418             continue;
419         }
420 
421         // Children that are being entered start downloading
422         MBP_StartDownload(i);
423 #endif
424     }
425 }
426 
427 /*---------------------------------------------------------------------------*
428   Name:         MBP_IsBootableAll
429 
430   Description:  Checks whether all the connected child devices are in a bootable state.
431 
432 
433   Arguments:    None.
434 
435   Returns:      TRUE if all of the children are bootable.
436                 FALSE if there is at least one child that is not bootable.
437  *---------------------------------------------------------------------------*/
MBP_IsBootableAll(void)438 BOOL MBP_IsBootableAll(void)
439 {
440     u16     i;
441 
442     if (mbpState.connectChildBmp == 0)
443     {
444         return FALSE;
445     }
446 
447     for (i = 1; i < 16; i++)
448     {
449         if (!(mbpState.connectChildBmp & (1 << i)))
450         {
451             continue;
452         }
453 
454         if (!MB_CommIsBootable(i))
455         {
456             return FALSE;
457         }
458     }
459     return TRUE;
460 }
461 
462 
463 /*---------------------------------------------------------------------------*
464   Name:         MBP_StartRebootAll
465 
466   Description:  Boots all of the connected children that are bootable.
467 
468   Arguments:    None.
469 
470   Returns:      None.
471  *---------------------------------------------------------------------------*/
MBP_StartRebootAll(void)472 void MBP_StartRebootAll(void)
473 {
474     u16     i;
475     u16     sentChild = 0;
476 
477     for (i = 1; i < 16; i++)
478     {
479         if (!(mbpState.bootableChildBmp & (1 << i)))
480         {
481             continue;
482         }
483         if (!MB_CommBootRequest(i))
484         {
485             // If the request fails, disconnect that child
486             MBP_DisconnectChild(i);
487             continue;
488         }
489         sentChild |= (1 << i);
490     }
491 
492     // If the connected child becomes 0, terminate with an error
493     if (sentChild == 0)
494     {
495         MBP_ChangeState(MBP_STATE_ERROR);
496         return;
497     }
498 
499     // Changes the state and stops accepting data transfer
500     MBP_ChangeState(MBP_STATE_REBOOTING);
501 }
502 
503 
504 /*---------------------------------------------------------------------------*
505   Name:         MBP_Cancel
506 
507   Description:  Cancels multiboot.
508 
509   Arguments:    None.
510 
511   Returns:      None.
512  *---------------------------------------------------------------------------*/
MBP_Cancel(void)513 void MBP_Cancel(void)
514 {
515     MBP_ChangeState(MBP_STATE_CANCEL);
516 #if !defined(MBP_USING_MB_EX)
517     MB_End();
518 #else
519     MB_EndToIdle();
520 #endif
521 }
522 
523 /*---------------------------------------------------------------------------*
524   Name:         MBPi_CheckAllReboot
525 
526   Description:  Determines whether all connected children are in the MB_COMM_PSTATE_BOOT_STARTABLE state and starts to shut down the MB library if they are.
527 
528 
529   Arguments:    None.
530 
531   Returns:      None.
532  *---------------------------------------------------------------------------*/
MBPi_CheckAllReboot(void)533 static void MBPi_CheckAllReboot(void)
534 {
535     if ((mbpState.state == MBP_STATE_REBOOTING) &&
536         (mbpState.connectChildBmp == mbpState.rebootChildBmp))
537     {
538         MBP_Printf("call MB_End()\n");
539 #if !defined(MBP_USING_MB_EX)
540         MB_End();
541 #else
542         MB_EndToIdle();
543 #endif
544     }
545 }
546 
547 /*---------------------------------------------------------------------------*
548   Name:         ParentStateCallback
549 
550   Description:  Parent state notification callback
551 
552   Arguments:    child_aid       AID of the child
553                 status          Callback status
554                 arg             Option argument
555   Returns:      None.
556  *---------------------------------------------------------------------------*/
ParentStateCallback(u16 child_aid,u32 status,void * arg)557 static void ParentStateCallback(u16 child_aid, u32 status, void *arg)
558 {
559 #if defined( MBP_DEBUG )
560     // For debug output
561     static const char *MB_CALLBACK_TABLE[] = {
562         "MB_COMM_PSTATE_NONE",
563         "MB_COMM_PSTATE_INIT_COMPLETE",
564         "MB_COMM_PSTATE_CONNECTED",
565         "MB_COMM_PSTATE_DISCONNECTED",
566         "MB_COMM_PSTATE_KICKED",
567         "MB_COMM_PSTATE_REQ_ACCEPTED",
568         "MB_COMM_PSTATE_SEND_PROCEED",
569         "MB_COMM_PSTATE_SEND_COMPLETE",
570         "MB_COMM_PSTATE_BOOT_REQUEST",
571         "MB_COMM_PSTATE_BOOT_STARTABLE",
572         "MB_COMM_PSTATE_REQUESTED",
573         "MB_COMM_PSTATE_MEMBER_FULL",
574         "MB_COMM_PSTATE_END",
575         "MB_COMM_PSTATE_ERROR",
576         "MB_COMM_PSTATE_WAIT_TO_SEND",
577     };
578 #endif
579 
580     MBP_Printf("get callback %s %d\n", MB_CALLBACK_TABLE[status], child_aid);
581 
582     switch (status)
583     {
584         //-----------------------------------------------------------
585         // Notification that the initialization process completed with the parent
586     case MB_COMM_PSTATE_INIT_COMPLETE:
587         // None.
588         break;
589 
590         //-----------------------------------------------------------
591         // Notification of the moment the child attempts to connect
592     case MB_COMM_PSTATE_CONNECTED:
593         {
594             // Connection is not accepted if the parent is not in entry accepting state
595             if (MBP_GetState() != MBP_STATE_ENTRY)
596             {
597                 break;
598             }
599 
600             MBP_AddBitmap(&mbpState.connectChildBmp, child_aid);
601             // Saves a child's MacAddress
602             WM_CopyBssid(((WMStartParentCallback *)arg)->macAddress,
603                          childInfo[child_aid - 1].macAddress);
604 
605             childInfo[child_aid - 1].playerNo = child_aid;
606         }
607         break;
608 
609         //-----------------------------------------------------------
610         // Notification when the child device has terminated connection
611     case MB_COMM_PSTATE_DISCONNECTED:
612         {
613             // Deletes the entry if it was disconnected by the condition other than rebooting of a child
614             if (MBP_GetChildState(child_aid) != MBP_CHILDSTATE_REBOOT)
615             {
616                 MBP_DisconnectChildFromBmp(child_aid);
617                 // Based on that, it determines whether every child has booted
618                 MBPi_CheckAllReboot();
619             }
620         }
621         break;
622 
623         //-----------------------------------------------------------
624         // Notification of the moment the entry request came from a child
625     case MB_COMM_PSTATE_REQUESTED:
626         {
627             const MBUserInfo *userInfo;
628 
629             userInfo = (MBUserInfo *)arg;
630 
631             OS_TPrintf("callback playerNo = %d\n", userInfo->playerNo);
632 
633             // Unequivocally kick child devices that requested entry when the parent device is not accepting entries
634             //
635             if (MBP_GetState() != MBP_STATE_ENTRY)
636             {
637                 MBP_KickChild(child_aid);
638                 break;
639             }
640 
641             // Accepts child's entry
642             mbpState.requestChildBmp |= 1 << child_aid;
643 
644             MBP_AcceptChild(child_aid);
645 
646             // UserInfo has still not been set during MB_COMM_PSTATE_CONNECTED, so it is meaningless to call MB_CommGetChildUser before the REQUESTED state
647             //
648             userInfo = MB_CommGetChildUser(child_aid);
649             if (userInfo != NULL)
650             {
651                 MI_CpuCopy8(userInfo, &childInfo[child_aid - 1].user, sizeof(MBUserInfo));
652             }
653             MBP_Printf("playerNo = %d\n", userInfo->playerNo);
654         }
655         break;
656 
657         //-----------------------------------------------------------
658         // Notify ACK for ACCEPT to a child
659     case MB_COMM_PSTATE_REQ_ACCEPTED:
660         // No processing needed
661         break;
662         //-----------------------------------------------------------
663         // Notification when received the download request from a child
664     case MB_COMM_PSTATE_WAIT_TO_SEND:
665         {
666             // Changes the status of a child from entered to download standby.
667             // Because this is the process in the interrupt, change it without prohibiting interrupt.
668             mbpState.requestChildBmp &= ~(1 << child_aid);
669             mbpState.entryChildBmp |= 1 << child_aid;
670 
671             // Starts the data transmission when MBP_StartDownload() is called from main routine.
672             // If it is already in data transmission state, it starts the data transmission to the child.
673 #ifdef MBP_USING_PREVIOUS_DOWNLOAD
674             /* When starting to send data immediately after entry */
675             MBP_StartDownload(child_aid);
676 #else
677             /* When starting to send data to all child devices at once */
678             if (MBP_GetState() == MBP_STATE_DATASENDING)
679             {
680                 MBP_StartDownload(child_aid);
681             }
682 #endif
683         }
684         break;
685 
686         //-----------------------------------------------------------
687         // Notification when kicking a child
688     case MB_COMM_PSTATE_KICKED:
689         // None.
690         break;
691 
692         //-----------------------------------------------------------
693         // Notification when starting the binary transmission to a child
694     case MB_COMM_PSTATE_SEND_PROCEED:
695         // None.
696         break;
697 
698         //-----------------------------------------------------------
699         // Notification when the binary transmission to the child completed
700     case MB_COMM_PSTATE_SEND_COMPLETE:
701         {
702             // Because this is the process in the interrupt, change it without prohibiting interrupt
703             mbpState.downloadChildBmp &= ~(1 << child_aid);
704             mbpState.bootableChildBmp |= 1 << child_aid;
705         }
706         break;
707 
708         //-----------------------------------------------------------
709         // Notify of a child when boot had completed properly
710     case MB_COMM_PSTATE_BOOT_STARTABLE:
711         {
712             // Because this is the process in the interrupt, change it without prohibiting interrupt
713             mbpState.bootableChildBmp &= ~(1 << child_aid);
714             mbpState.rebootChildBmp |= 1 << child_aid;
715 
716             // When all of the children completed booting, starts the reconnection process with the parent
717             MBPi_CheckAllReboot();
718         }
719         break;
720 
721         //-----------------------------------------------------------
722         // Notify when the boot request transmission to the target child has started.
723         // It does not return as a callback.
724     case MB_COMM_PSTATE_BOOT_REQUEST:
725         // None.
726         break;
727 
728         //-----------------------------------------------------------
729         // Notification when the members are full
730     case MB_COMM_PSTATE_MEMBER_FULL:
731         // None.
732         break;
733 
734         //-----------------------------------------------------------
735         // Notify when ending multiboot
736     case MB_COMM_PSTATE_END:
737         {
738             if (MBP_GetState() == MBP_STATE_REBOOTING)
739                 // When reboot process ends, it ends MB and reconnects with a child
740             {
741                 MBP_ChangeState(MBP_STATE_COMPLETE);
742             }
743             else
744                 // Shut down completed, and restore the STOP state
745             {
746                 MBP_ChangeState(MBP_STATE_STOP);
747             }
748 
749             // Clears the buffer used for distributing games.
750             // Work memory will have been released when the MB_COMM_PSTATE_END callback returns, so we can free memory.
751             //
752             if (sFilebuf)
753             {
754                 OS_Free(sFilebuf);
755                 sFilebuf = NULL;
756             }
757             if (sCWork)
758             {
759                 OS_Free(sCWork);
760                 sCWork = NULL;
761             }
762 
763             /* MB_UnregisterFile can be omitted because initialization will be caused by calling MB_End and releasing work memory
764              *                                         */
765 
766         }
767         break;
768 
769         //-----------------------------------------------------------
770         // Notify that the error occurred
771     case MB_COMM_PSTATE_ERROR:
772         {
773             MBErrorStatus *cb = (MBErrorStatus *)arg;
774 
775             switch (cb->errcode)
776             {
777                 //------------------------------
778                 // Notification level error. No process is necessary.
779             case MB_ERRCODE_WM_FAILURE:
780                 // None.
781                 break;
782                 //------------------------------
783                 // Error at the level that requires wireless to be reset
784             case MB_ERRCODE_INVALID_PARAM:
785             case MB_ERRCODE_INVALID_STATE:
786             case MB_ERRCODE_FATAL:
787                 MBP_ChangeState(MBP_STATE_ERROR);
788                 break;
789             }
790         }
791         break;
792 
793         //-----------------------------------------------------------
794     default:
795         OS_Panic("Get illegal parent state.\n");
796     }
797 }
798 
799 
800 /*---------------------------------------------------------------------------*
801   Name:         MBP_ChangeState
802 
803   Description:  Changes the parent state.
804 
805   Arguments:    state       State to change
806 
807   Returns:      None.
808  *---------------------------------------------------------------------------*/
MBP_ChangeState(u16 state)809 static void MBP_ChangeState(u16 state)
810 {
811 #if defined( MBP_DEBUG )
812     // For debug output
813     static const char *STATE_NAME[] = {
814         "MBP_STATE_STOP",
815         "MBP_STATE_IDLE",
816         "MBP_STATE_ENTRY",
817         "MBP_STATE_DATASENDING",
818         "MBP_STATE_REBOOTING",
819         "MBP_STATE_COMPLETE",
820         "MBP_STATE_CANCEL",
821         "MBP_STATE_ERROR"
822     };
823 #endif
824 
825     SDK_ASSERT(state < MBP_STATE_NUM);
826 
827     MBP_Printf("%s -> %s\n", STATE_NAME[mbpState.state], STATE_NAME[state]);
828     mbpState.state = state;
829 }
830 
831 
832 /*---------------------------------------------------------------------------*
833   Name:         MBP_GetState
834 
835   Description:  Gets the parent state.
836 
837   Arguments:    None.
838 
839   Returns:      Parent state.
840  *---------------------------------------------------------------------------*/
MBP_GetState(void)841 u16 MBP_GetState(void)
842 {
843     return mbpState.state;
844 }
845 
846 /*---------------------------------------------------------------------------*
847   Name:         MBP_GetConnectState
848 
849   Description:  Gets the connection information.
850 
851   Arguments:    Buffer area for getting the current connection state
852 
853   Returns:      None.
854  *---------------------------------------------------------------------------*/
MBP_GetConnectState(MBPState * state)855 void MBP_GetConnectState(MBPState * state)
856 {
857     MI_CpuCopy8(&mbpState, state, sizeof(MBPState));
858 }
859 
860 /*---------------------------------------------------------------------------*
861   Name:         MBP_GetChildBmp
862 
863   Description:  Gets the connection bitmap of a child.
864 
865   Arguments:    Type of the connection bitmap to get
866 
867   Returns:      Child state.
868  *---------------------------------------------------------------------------*/
MBP_GetChildBmp(MBPBmpType bmpType)869 u16 MBP_GetChildBmp(MBPBmpType bmpType)
870 {
871     u16     tmpBitmap;
872     static const u16 *BITMAP_TABLE[MBP_BMPTYPE_NUM] = {
873         &mbpState.connectChildBmp,
874         &mbpState.requestChildBmp,
875         &mbpState.entryChildBmp,
876         &mbpState.downloadChildBmp,
877         &mbpState.bootableChildBmp,
878         &mbpState.rebootChildBmp,
879     };
880 
881     SDK_ASSERT(bmpType < MBP_BMPTYPE_NUM);
882 
883     tmpBitmap = *(BITMAP_TABLE[bmpType]);
884 
885     return tmpBitmap;
886 }
887 
888 
889 /*---------------------------------------------------------------------------*
890   Name:         MBP_GetChildState
891 
892   Description:  Gets the connection state of a child.
893 
894   Arguments:    aid     Number for the connected child
895 
896   Returns:      Child state.
897  *---------------------------------------------------------------------------*/
MBP_GetChildState(u16 aid)898 MBPChildState MBP_GetChildState(u16 aid)
899 {
900     MBPState tmpState;
901     u16     bitmap = (u16)(1 << aid);
902 
903     // Because an interrupt may change the connection state unexpectedly, prohibit interrupts and get a snapshot of the state at that time
904     //
905     OSIntrMode enabled = OS_DisableInterrupts();
906     if ((mbpState.connectChildBmp & bitmap) == 0)
907     {
908         (void)OS_RestoreInterrupts(enabled);
909         return MBP_CHILDSTATE_NONE;    // Not connected
910     }
911     MI_CpuCopy8(&mbpState, &tmpState, sizeof(MBPState));
912     (void)OS_RestoreInterrupts(enabled);
913 
914     // Determining the connection status
915     if (tmpState.requestChildBmp & bitmap)
916     {
917         return MBP_CHILDSTATE_REQUEST; // Requesting connection
918     }
919     if (tmpState.entryChildBmp & bitmap)
920     {
921         return MBP_CHILDSTATE_ENTRY;   // Undergoing entry
922     }
923     if (tmpState.downloadChildBmp & bitmap)
924     {
925         return MBP_CHILDSTATE_DOWNLOADING;      // Downloading
926     }
927     if (tmpState.bootableChildBmp & bitmap)
928     {
929         return MBP_CHILDSTATE_BOOTABLE; // Boot preparation completed
930     }
931     if (tmpState.rebootChildBmp & bitmap)
932     {
933         return MBP_CHILDSTATE_REBOOT;  // Rebooted
934     }
935 
936     return MBP_CHILDSTATE_CONNECTING;  // Connecting
937 }
938 
939 
940 /*---------------------------------------------------------------------------*
941   Name:         MBP_AddBitmap
942 
943   Description:  Adds a child to the connection state bitmap.
944 
945   Arguments:    pBitmap     Pointer to the bitmap to add
946                 aid         AID of the child to be added
947 
948   Returns:      None.
949  *---------------------------------------------------------------------------*/
MBP_AddBitmap(u16 * pBitmap,u16 aid)950 static inline void MBP_AddBitmap(u16 *pBitmap, u16 aid)
951 {
952     // Prohibit interrupts to prevent an unexpected interrupt from breaking the state while values are being changed
953     //
954     OSIntrMode enabled = OS_DisableInterrupts();
955     *pBitmap |= (1 << aid);
956     (void)OS_RestoreInterrupts(enabled);
957 }
958 
959 
960 /*---------------------------------------------------------------------------*
961   Name:         MBP_RemoveBitmap
962 
963   Description:  Delete a child from the connection state bitmap.
964 
965   Arguments:    pBitmap     Pointer to the bitmap to delete
966                 aid         AID of the child to be deleted
967 
968   Returns:      None.
969  *---------------------------------------------------------------------------*/
MBP_RemoveBitmap(u16 * pBitmap,u16 aid)970 static inline void MBP_RemoveBitmap(u16 *pBitmap, u16 aid)
971 {
972     // Prohibit interrupts to prevent an unexpected interrupt from breaking the state while values are being changed
973     //
974     OSIntrMode enabled = OS_DisableInterrupts();
975     *pBitmap &= ~(1 << aid);
976     (void)OS_RestoreInterrupts(enabled);
977 }
978 
979 /*---------------------------------------------------------------------------*
980   Name:         MBP_DisconnectChildFromBmp
981 
982   Description:  Deletes the child device flag from all bitmaps when a child device is disconnected.
983 
984 
985   Arguments:    aid     AID of the child that was disconnected
986 
987   Returns:      None.
988  *---------------------------------------------------------------------------*/
MBP_DisconnectChildFromBmp(u16 aid)989 static inline void MBP_DisconnectChildFromBmp(u16 aid)
990 {
991     u16     aidMask = (u16)~(1 << aid);
992 
993     OSIntrMode enabled = OS_DisableInterrupts();
994 
995     mbpState.connectChildBmp &= aidMask;
996     mbpState.requestChildBmp &= aidMask;
997     mbpState.entryChildBmp &= aidMask;
998     mbpState.downloadChildBmp &= aidMask;
999     mbpState.bootableChildBmp &= aidMask;
1000     mbpState.rebootChildBmp &= aidMask;
1001 
1002     (void)OS_RestoreInterrupts(enabled);
1003 }
1004 
1005 /*---------------------------------------------------------------------------*
1006   Name:         MBP_DisconnectChild
1007 
1008   Description:  Disconnects a child.
1009 
1010   Arguments:    aid     AID of the child to be disconnected
1011 
1012   Returns:      None.
1013  *---------------------------------------------------------------------------*/
MBP_DisconnectChild(u16 aid)1014 static inline void MBP_DisconnectChild(u16 aid)
1015 {
1016     // MB_Disconnect may be provided in the future
1017     MBP_Printf(" WM_Disconnect %d\n", aid);
1018     MBP_DisconnectChildFromBmp(aid);
1019     MB_DisconnectChild(aid);
1020 }
1021 
1022 /*---------------------------------------------------------------------------*
1023   Name:         MBP_GetChildInfo
1024 
1025   Description:  Gets a pointer to the user information on a child.
1026 
1027   Arguments:    child_aid   AID of the child
1028 
1029   Returns:      A pointer to user information.
1030  *---------------------------------------------------------------------------*/
MBP_GetChildInfo(u16 child_aid)1031 const MBPChildInfo *MBP_GetChildInfo(u16 child_aid)
1032 {
1033     if (!(mbpState.connectChildBmp & (1 << child_aid)))
1034     {
1035         return NULL;
1036     }
1037     return &childInfo[child_aid - 1];
1038 }
1039 
1040 
1041 /*---------------------------------------------------------------------------*
1042   Name:         MBP_GetPlayerNo
1043 
1044   Description:  Allows you to search for and obtain the player number (AID) used by a child device when it was a multiboot child, based on its MAC address, after that child has been rebooted and reconnected.
1045 
1046 
1047   Arguments:    macAddress      MAC address of a child
1048 
1049   Returns:      Child AID at the time of multiboot connection.
1050  *---------------------------------------------------------------------------*/
MBP_GetPlayerNo(const u8 * macAddress)1051 u16 MBP_GetPlayerNo(const u8 *macAddress)
1052 {
1053     u16     i;
1054 
1055     for (i = 1; i < MBP_CHILD_MAX + 1; i++)
1056     {
1057         if ((mbpState.connectChildBmp & (1 << i)) == 0)
1058         {
1059             continue;
1060         }
1061         if (WM_IsBssidEqual(macAddress, childInfo[i - 1].macAddress))
1062         {
1063             return childInfo[i - 1].playerNo;
1064         }
1065     }
1066 
1067     return 0;
1068 }
1069 
1070 
1071 /*---------------------------------------------------------------------------*
1072   Name:         MBP_GetChildMacAddress
1073 
1074   Description:  Gets MAC address of the multiboot child.
1075 
1076   Arguments:    aid     AID of the child
1077 
1078   Returns:      Pointer to MAC address.
1079  *---------------------------------------------------------------------------*/
MBP_GetChildMacAddress(u16 aid)1080 const u8 *MBP_GetChildMacAddress(u16 aid)
1081 {
1082     if (!(mbpState.connectChildBmp & (1 << aid)))
1083     {
1084         return NULL;
1085     }
1086     return childInfo[aid - 1].macAddress;
1087 }
1088