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