/*---------------------------------------------------------------------------*
  Project:  NitroSDK - SPI - demos
  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.7  2004/09/06 13:02:48  terui
  Only fix indent.

  Revision 1.6  2004/08/23 07:27:27  yasu
  Workaround for pushing A button in IPL

  Revision 1.5  2004/08/02 08:23:35  ida
  update NitroSystem modules

  Revision 1.4  2004/07/28 10:38:29  yasu
  Switch playing screen to the below.

  Revision 1.3  2004/06/30 06:55:48  ida
  update NitroSystem modules

  Revision 1.2  2004/06/10 09:43:53  terui
  Change debug print string.

  Revision 1.1  2004/06/02 09:53:25  terui
  Initial upload.

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

#include    <nitro.h>
#include    "monkey.h"
#include    "snd_data.h"


/*---------------------------------------------------------------------------*
    Constant definition
 *---------------------------------------------------------------------------*/
#define     KEY_REPEAT_START    25              // Number of frames before start of key repeat
#define     KEY_REPEAT_SPAN     10              // Number of frames of key repeat interval


/*---------------------------------------------------------------------------*
    Structure definition
 *---------------------------------------------------------------------------*/
// Key input information
typedef struct KeyInformation
{
    u16     cnt;    // Unprocessed input value
    u16     trg;    // Pressing trigger input
    u16     up;     // Releasing trigger input
    u16     rep;    // Pressing hold repeat input

} KeyInformation;

/*---------------------------------------------------------------------------*
    Internal function definition
 *---------------------------------------------------------------------------*/
static void     Init3D( void );
static void     Draw3D( void );
static void     DrawLine( s16 sx , s16 sy , s16 ex , s16 ey , GXRgb color );
static void     VBlankIntr( void );
static void     KeyRead( KeyInformation* pKey );


/*---------------------------------------------------------------------------*
    Internal variable definition
 *---------------------------------------------------------------------------*/
static KeyInformation   gKey;
static MICAutoParam     gMicAutoParam;
static u16              gMicData[ 192 ];
static TPData           gTpData[ 4 ];


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

  Description:  Initialization and main loop

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void
NitroMain( void )
{
    // Various initialization
    OS_InitPrintServer();
    OS_Init();
    OS_InitThread();
    OS_InitTick();
    OS_InitAlarm();
    FX_Init();
    GX_Init();
    PXI_Init();
    GX_DispOff();
    GXS_DispOff();
    GX_SetDispSelect(GX_DISP_SELECT_SUB_MAIN);

    // Display setup initialization
    GX_SetBankForLCDC( GX_VRAM_LCDC_ALL );
    MI_CpuClearFast( (void*)HW_LCDC_VRAM , HW_LCDC_VRAM_SIZE );
    (void)GX_DisableBankForLCDC();
    MI_CpuFillFast( (void*)HW_OAM , 192 , HW_OAM_SIZE );
    MI_CpuClearFast( (void*)HW_PLTT , HW_PLTT_SIZE );
    MI_CpuFillFast( (void*)HW_DB_OAM , 192 , HW_DB_OAM_SIZE );
    MI_CpuClearFast( (void*)HW_DB_PLTT , HW_DB_PLTT_SIZE );

    // 3D related initialization
    Init3D();

    // Interrupt setup
    OS_SetIrqFunction( OS_IE_V_BLANK , VBlankIntr );
    (void)OS_EnableIrqMask( OS_IE_V_BLANK );
    (void)OS_EnableIrq();
    (void)OS_EnableInterrupts();
    (void)GX_VBlankIntr( TRUE );

    // Start thread for device sampling
    MonkeyInit();

    // Start thread for device sampling
    {
        SND_Init();
        SND_AssignWaveArc(
            (SNDBankData*)sound_bank_data ,
            0,
            (SNDWaveArc*)sound_wave_data
        );
        SND_StartSeq(
            0 ,
            sound_seq_data ,
            0 ,
            (SNDBankData*)sound_bank_data
        );
    }

    // Start LCD display
    GX_DispOn();
    GXS_DispOn();

    // Debug character string output
    OS_Printf("ARM9: SPI parallel sampling demo \"spiMonkey\" started.\n");

    // empty call that gets key input information (push the A button in IPL)
    KeyRead( &gKey );

    // Main loop
    while(TRUE)
    {
        // Get key input information
        KeyRead(&gKey);

        // Get mike and touch panel input information
        MonkeyGetNewMicData( 192 , gMicData );
        MonkeyGetNewTpData( 4 , gTpData );

        // Draw
        Draw3D();

        // Sound
        while( SND_RecvCommandReply( SND_COMMAND_NOBLOCK ) != NULL )
        {
        }
        (void)SND_FlushCommand( SND_COMMAND_NOBLOCK );

        // V-blank waiting
        SVC_WaitVBlankIntr();
        // Output debug print of ARM7
        OS_PrintServer();
    }
}

/*---------------------------------------------------------------------------*
  Name:         Init3D

  Description:  Initialization process for display in 3D

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void
Init3D( void )
{
    G3X_Init();
    G3X_InitMtxStack();
    G3_SwapBuffers( GX_SORTMODE_AUTO , GX_BUFFERMODE_W );
    GX_SetGraphicsMode( GX_DISPMODE_GRAPHICS , GX_BGMODE_0,GX_BG0_AS_3D );
    GX_SetVisiblePlane( GX_PLANEMASK_BG0 );
    G2_SetBG0Priority( 0 );
    G3X_SetShading( GX_SHADING_TOON );
    G3X_AlphaTest( FALSE , 0 );
    G3X_AlphaBlend( TRUE );
    G3X_AntiAlias( TRUE );
    G3X_EdgeMarking( FALSE );
    G3X_SetFog( FALSE , (GXFogBlend)0 , (GXFogSlope)0 , 0 );
    G3X_SetClearColor( 0 , 0 , 0x7fff , 63 , FALSE );
    G3_ViewPort( 0 , 0 , 255 , 191 );
}

/*---------------------------------------------------------------------------*
  Name:         Draw3D

  Description:  Display waveform in 3D display

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void
Draw3D( void )
{
    G3X_Reset();

    G3_MtxMode( GX_MTXMODE_PROJECTION );
    G3_Identity();
    G3_MtxMode( GX_MTXMODE_POSITION_VECTOR );
    G3_Identity();

    G3_PolygonAttr(
        GX_LIGHTMASK_NONE ,
        GX_POLYGONMODE_MODULATE ,
        GX_CULL_NONE ,
        0 ,
        31 ,
        0
    );

    {
        s32     i;

        // Display mike data in waveform
        for( i = 0 ; i < 191 ; i ++ )
        {
            DrawLine(
                (s16)( gMicData[ i ] >> 8 ) ,
                (s16)( i ) ,
                (s16)( gMicData[ i + 1 ] >> 8 ) ,
                (s16)( i + 1 ) ,
                GX_RGB( 31 , 31 , 0 )
            );
        }

        // Display touch panel contact in the shape of a plus
        for( i = 0 ; i < 4 ; i ++ )
        {
            if( gTpData[ i ].touch == TP_TOUCH_ON )
            {
                if( ! ( gTpData[ i ].validity & TP_VALIDITY_INVALID_X ) )
                {
                    // Display x coordinate by line
                    DrawLine(
                        (s16)( gTpData[ i ].x ) ,
                        (s16)( 0 ) ,
                        (s16)( gTpData[ i ].x ) ,
                        (s16)( 191 ) ,
                        GX_RGB(
                            31 - ( i * 6 ) ,
                            31 - ( i * 6 ) ,
                            31 - ( i * 6 )
                        )
                    );
                }
                if( ! ( gTpData[ i ].validity & TP_VALIDITY_INVALID_Y ) )
                {
                    // Display y coordinate by line
                    DrawLine(
                        (s16)( 0 ) ,
                        (s16)( gTpData[ i ].y ) ,
                        (s16)( 255 ) ,
                        (s16)( gTpData[ i ].y ) ,
                        GX_RGB(
                            31 - ( i * 6 ) ,
                            31 - ( i * 6 ) ,
                            31 - ( i * 6 )
                        )
                    );
                }
            }
        }
    }

    G3_SwapBuffers( GX_SORTMODE_AUTO , GX_BUFFERMODE_W );
}

/*---------------------------------------------------------------------------*
  Name:         DrawLine

  Description:  Draw line by triangular polygon

  Arguments:    sx    - x coordinate for starting point of line to draw
                sy    - y coordinate for starting point of line to draw
                ex    - x coordinate for ending point of line to draw
                ey    - y coordinate for ending point of line to draw
                color - Color of line to draw

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void
DrawLine( s16 sx , s16 sy , s16 ex , s16 ey , GXRgb color )
{
    fx16    fsx;
    fx16    fsy;
    fx16    fex;
    fx16    fey;

    fsx = (fx16)( ( ( sx - 128 ) * 0x1000 ) / 128 );
    fsy = (fx16)( ( ( 96 - sy ) * 0x1000 ) / 96 );
    fex = (fx16)( ( ( ex - 128 ) * 0x1000 ) / 128 );
    fey = (fx16)( ( ( 96 - ey ) * 0x1000 ) / 96 );

    G3_Begin( GX_BEGIN_TRIANGLES );
    {
        G3_Color( color );
        G3_Vtx( fsx , fsy , 0 );
        G3_Color( color );
        G3_Vtx( fex , fey , 0 );
        G3_Color( color );
        G3_Vtx( fsx , fsy , 1 );
    }
    G3_End();
}

/*---------------------------------------------------------------------------*
  Name:         VBlankIntr

  Description:  V blank interrupt vector

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void
VBlankIntr( void )
{
    // Set IRQ check flag
    OS_SetIrqCheckFlag( OS_IE_V_BLANK );
}

/*---------------------------------------------------------------------------*
  Name:         KeyRead

  Description:  Edit key input information
                Detect pressing trigger input, releasing trigger input, and pressing hold repeat input

  Arguments:    pKey  - Key input information structure to edit

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void
KeyRead( KeyInformation* pKey )
{
    static u16  repeat_count[ 12 ];
    int         i;
    u16         r;

    r = PAD_Read();
    pKey->trg = 0x0000;
    pKey->up = 0x0000;
    pKey->rep = 0x0000;

    for( i = 0 ; i < 12 ; i ++ )
    {
        if( r & ( 0x0001 << i ) )
        {
            if( !( pKey->cnt & ( 0x0001 << i ) ) )
            {
                pKey->trg |= ( 0x0001 << i );       // Pressing trigger input
                repeat_count[ i ] = 1;
            }
            else
            {
                if( repeat_count[ i ] > KEY_REPEAT_START )
                {
                    pKey->rep |= ( 0x0001 << i );       // Pressing trigger input
                    repeat_count[ i ] = KEY_REPEAT_START - KEY_REPEAT_SPAN;
                }
                else
                {
                    repeat_count[ i ] ++;
                }
            }
        }
        else
        {
            if( pKey->cnt & ( 0x0001 << i ) )
            {
                pKey->up |= ( 0x0001 << i );        // Releasing trigger input
            }
        }
    }
    pKey->cnt = r;      // Unprocessed key input
}

/*---------------------------------------------------------------------------*
  End of file
 *---------------------------------------------------------------------------*/
