/*---------------------------------------------------------------------------*
  Project:  NitroSDK - WM - demos - multiboot-Model
  File:     main.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: main.c,v $
  Revision 1.14  2004/11/26 02:39:24  takano_makoto
  Revised so that when connection to parent fails will always do WH_Reset one time.

  Revision 1.13  2004/11/02 09:19:09  takano_makoto
  fix comment.

  Revision 1.12  2004/10/29 02:07:35  takano_makoto
  Changed WH_ChildConnectAuto interface.

  Revision 1.11  2004/10/28 01:27:50  takano_makoto
  Moved wmhigh to wh under wireless_shared.

  Revision 1.10  2004/10/27 02:01:18  takano_makoto
  Revised to increment tgid after a restart.

  Revision 1.9  2004/10/21 00:42:56  yosizaki
  add SHARED_WH switch.

  Revision 1.8  2004/09/30 03:59:47  takano_makoto
  Changed so that it retries when connection to parent device fails.

  Revision 1.7  2004/09/27 08:34:30  takano_makoto
  Changed interfaces of WH_ChildConnect and WH_Initialize.

  Revision 1.6  2004/09/21 07:26:28  takano_makoto
  Comment addition

  Revision 1.3  2004/09/17 07:15:45  sato_masaki
  Changed the data for gMBParentBssDesc to be generated using MB_ReadMultiBootParentBssDesc.

  Revision 1.2  2004/09/17 02:20:23  sato_masaki
  Added reply comments for TODO.

  Revision 1.1  2004/09/16 14:07:26  takano_makoto
  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 Declaration
//============================================================================

static void ModeConnect( void );    // Starts connection to new machine
static void ModeError( void );      // Error display screen
static void ModeWorking( void );    // Busy screen
static void ChildReceiveCallback( WMmpRecvBuf* data );


//============================================================================
//  Variable Definition
//============================================================================

static s32  gFrame;                 // Frame counter

static WMBssDesc  gMBParentBssDesc ATTRIBUTE_ALIGN(32);

//============================================================================
//  Variable Definition
//============================================================================

/*---------------------------------------------------------------------------*
  Name:         NitroMain

  Description:  Chile main routine

  Arguments:    None

  Returns:      None
 *---------------------------------------------------------------------------*/
void NitroMain( void )
{

    // Screen and OS initialization
    CommonInit();

    // Checks whether the child started up from a multi-boot
    if ( ! MB_IsMultiBootChild() )
    {
        OS_Panic("not found Multiboot child flag!\n");
    }

    //--------------------------------------------------------------
    // Resets and cuts communication if started up from a multi-boot.
    // The BssDesc for the new booted machine is saved even after the boot,
    // use this information to reconnect to the new machine.
    // There is no problem with getting only the MAC address from the BssDesc and connecting
    // from a parent scan with the MAC address specification, but to connect
    // right away to the new machine using the saved BssDesc, it is necessary to set the communication size and transfer mode
    // between the parent and child beforehand.
    //--------------------------------------------------------------

    /*
     * Gets the new machine information for reconnecting with the parent.
     * The WMBssDesc used for connecting needs to be aligned to 32 bytes.
     * When reconnecting to the new machine with a MAC address without re-scanning,
     * Align the maximum communication size and KS/CS flags for the parent and children beforehand.
     * When connecting after a re-scan, all of these values may be 0.
     */
    MB_ReadMultiBootParentBssDesc( &gMBParentBssDesc,
                                   WH_PARENT_MAX_SIZE,  // Maximum parent communication size
                                   WH_CHILD_MAX_SIZE,   // Maximum child communication size
                                   0,                   // Key sharing flag
                                   0 );                 // Continuous transfer mode flag

    // When connecting without rescanning for a parent, the child and parent must align tgid.
    //
    // After restarting, the parent changes tgid in order to avoid connection from an unrelated IPL.
    // A child must also change tgid to align with it.
    // In this demo, parent and child increment the tgid by 1.
    gMBParentBssDesc.gameInfo.tgid++;

    // Screen initialization
    DispInit();
    // Heap initialization
    InitAllocateSystem();

    // Enables interrupt
    (void)OS_EnableIrq();
    (void)OS_EnableInterrupts();

    GInitDataShare();

    //********************************
    // Wireless initialization
    (void)WH_Initialize();
    //********************************

    // Starts the LCD display
    GX_DispOn();
    GXS_DispOn();

    // Outputs the debug string
    OS_TPrintf("MB child: Simple DataSharing demo started.\n");

    // Empty call of the key input information fetch (countermeasure for pressing the A button with the IPL)
    ReadKey();

    // Main loop
    for ( gFrame = 0 ; TRUE ; gFrame ++ )
    {
        // Gets the key input information
        ReadKey();

        // Clears the screen
        BgClear();

        // Sorts the processing according to the communication state
        switch( WH_GetSystemState() )
        {
        case WH_SYSSTATE_CONNECT_FAIL:
            {
                // When WM_StartConnect() fails, WM internal state becomes abnormal.
                // Therefore, always use WM_Reset one time to reset it to IDLE state.
                WH_Reset();
            }
            break;
        case WH_SYSSTATE_IDLE:
            {
                static retry = 0;
                enum {
                    MAX_RETRY = 5
                };

                if ( retry < MAX_RETRY )
                {
                    ModeConnect();
                    retry++;
                    break;
                }
                // display ERROR if unable to connect to parent device with MAX_RETRY
            }
        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;
        }

        // Displays the strength of the signal being received
        {
            int level;
            level = WH_GetLinkLevel();
            BgPrintStr( 31, 23, 0xf, "%d", level );
        }

        // Waiting for the V-blank
        SVC_WaitVBlankIntr();
    }
}

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

  Description:  Starts a connection

  Arguments:    None

  Returns:      None
 *---------------------------------------------------------------------------*/
static void ModeConnect( void )
{
#define USE_DIRECT_CONNECT

    // Case of directly connecting without rescanning for a parent.
#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 );
    // Case of rescanning for a parent.
    //********************************
    (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:  Displays the error notification 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:  Displays the screen currently being processed

  Arguments:    None

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

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