/*---------------------------------------------------------------------------*
  Project:  NitroSDK - MB - demos - cloneboot
  File:     child.c

  Copyright 2003,2004 Nintendo.  All rights reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law.  They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Log: child.c,v $
  Revision 1.1  2004/11/15 06:21:18  yosizaki
  initial update.

  $NoKeywords: $
 *---------------------------------------------------------------------------*/

#include <nitro.h>
#include <nitro/wm.h>
#include <nitro/mb.h>

#include "common.h"
#include "disp.h"
#include "gmain.h"
#include "wh.h"

//============================================================================
//  Prototype declarations
//============================================================================

static void ModeConnect( void );    // Start connection to parent 
static void ModeError( void );      // Error display screen 
static void ModeWorking( void );    // Busy screen
static void ChildReceiveCallback( WMmpRecvBuf* data );


//============================================================================
//  Variable definitions
//============================================================================

static s32  gFrame;                 // Frame counter

static WMBssDesc  gMBParentBssDesc ATTRIBUTE_ALIGN(32);

//============================================================================
//  Function definitions
//============================================================================

/*---------------------------------------------------------------------------*
  Name:         ChildMain

  Description:  Child main routine

  Arguments:    None

  Returns:      None
 *---------------------------------------------------------------------------*/
void ChildMain( void )
{
    
    // Initialize screen and OS
    CommonInit();
    
    // Check if this machine is a child that was booted from multiboot.
    if ( ! MB_IsMultiBootChild() )
    {
        OS_Panic("not found Multiboot child flag!\n");
    }
    
    //--------------------------------------------------------------
    // If multibooted, reset and disconnect. 
    // After booting, the child will have the parent's BssDesc and using
    // this info, it can reconnect to the parent. 
    // At this time, it can connect to the parent without a problem by specifying
    // the MAC address extracted from the BssDesc and connecting by  
    // a parent scan. But if it connects directly to the parent 
    // using the saved BssDesc, the parent and child must agree on the 
    // communication size and transfer mode in advance.   
    //--------------------------------------------------------------
    
    /* 
     * Gets the parent info used to reconnect with the parent.                   
     * The WMBssDesc used for connection must be 32-byte aligned. 
     * If reconnecting without scanning for the parent's MAC address, 
     * make sure the parent and child have the same max transmission size and 
     * KS/CS flags settings before connecting. 
     * If it connects after rescanning, these values can all be zero. 
     */
    MB_ReadMultiBootParentBssDesc( &gMBParentBssDesc, 
                                   WH_PARENT_MAX_SIZE,  // Parent max transmission size
                                   WH_CHILD_MAX_SIZE,   // Child max transmission size
                                   0,                   // Key sharing flag
                                   0 );                 // Continuous transfer mode flag 
    
    // When connecting without rescanning, the parent's tgid must match the child's. 
    // After the parent restarts, it changes its tgid to prevent connections from unrelated IPL, 
    // and the child must change its tgid to match the parent. 
    // In this demo, the parent and child tgids have increments of 1. 
    gMBParentBssDesc.gameInfo.tgid++;
    
    // Initialize the screen 
    DispInit();
    // Initialize the heap
    InitAllocateSystem();
    
    // Enable interrupts
    (void)OS_EnableIrq();
    (void)OS_EnableInterrupts();
    
    GInitDataShare();
    
    //********************************
    // Initialize wireless
    (void)WH_Initialize();
    //********************************
    
    // Start LCD display
    GX_DispOn();
    GXS_DispOn();

    // Debug text string output
    OS_TPrintf("MB child: Simple DataSharing demo started.\n");

    // Dunny call to get key input info (To handle pressing of A button with IPL)
    ReadKey();
    
    // Main loop 
    for ( gFrame = 0 ; TRUE ; gFrame ++ )
    {
        // Get key input info 
        ReadKey();
        
        // Clear screen 
        BgClear();
        
        // Process according to communication status 
        switch( WH_GetSystemState() )
        {
        case WH_SYSSTATE_IDLE:
        case WH_SYSSTATE_CONNECT_FAIL:
            {
                static retry = 0;
                enum {
                    MAX_RETRY = 5
                };
                
                if ( retry < MAX_RETRY )
                {
                    ModeConnect();
                    retry++;
                    break;
                }
                // If child cannot connect to parent after trying MAX_RETRY times, display error 
            }
        case WH_SYSSTATE_ERROR:
            ModeError();
            break;
        case WH_SYSSTATE_BUSY:
        case WH_SYSSTATE_SCANNING:
            ModeWorking();
            break;
            
        case WH_SYSSTATE_CONNECTED:
        case WH_SYSSTATE_KEYSHARING:
        case WH_SYSSTATE_DATASHARING:
            {
                BgPutString( 8 , 1 , 0x2 , "Child mode" );
                GStepDataShare( gFrame );
                GMain();
            }
            break;
        }

        // Display incoming signal strength
        {
            int level;
            level = WH_GetLinkLevel();
            BgPrintStr( 31, 23, 0xf, "%d", level );
        }
        
        // Wait for V blank 
        SVC_WaitVBlankIntr();
    }
}

/*---------------------------------------------------------------------------*
  Name:         ModeConnect

  Description:  Start connection 

  Arguments:    None

  Returns:      None
 *---------------------------------------------------------------------------*/
static void ModeConnect( void )
{
#define USE_DIRECT_CONNECT
    
    // When connecting directly without parent rescan 
#ifdef USE_DIRECT_CONNECT
    //********************************
    (void)WH_ChildConnect( WH_CONNECTMODE_DS_CHILD, &gMBParentBssDesc );
    // WH_ChildConnect(WH_CONNECTMODE_MP_CHILD, &gMBParentBssDesc, TRUE);
    // WH_ChildConnect(WH_CONNECTMODE_KS_CHILD, &gMBParentBssDesc, TRUE);
    //********************************
#else
    WH_SetGgid( gMBParentBssDesc.gameInfo.ggid );
    // When using parent rescan 
    //********************************
    (void)WH_ChildConnectAuto( WH_CONNECTMODE_DS_CHILD, gMBParentBssDesc.bssid, gMBParentBssDesc.channel );
    // WH_ChildConnect(WH_CONNECTMODE_MP_CHILD, &gMBParentBssDesc, TRUE);
    // WH_ChildConnect(WH_CONNECTMODE_KS_CHILD, &gMBParentBssDesc, TRUE);
    //********************************
#endif
}

/*---------------------------------------------------------------------------*
  Name:         ModeError

  Description:  Display error message screen 

  Arguments:    None

  Returns:      None
 *---------------------------------------------------------------------------*/
static void ModeError( void )
{
    BgPrintStr( 5 , 10 , 0x1 , "======= ERROR! =======" );

    if ( WH_GetLastError() == WM_ERRCODE_OVER_MAX_ENTRY )
    {
        BgPrintStr( 5 , 13 , 0xf , "OVER_MAX_ENTRY");
    }
}

/*---------------------------------------------------------------------------*
  Name:         ModeWorking

  Description:  Display working screen 

  Arguments:    None

  Returns:      None
 *---------------------------------------------------------------------------*/
static void ModeWorking( void )
{
    BgPrintStr( 9 , 11 , 0xf , "Now working..." );

    if ( IS_PAD_TRIGGER( PAD_BUTTON_START ) )
    {
        //********************************
        (void)WH_Finalize();
        //********************************
    }
}



