/*---------------------------------------------------------------------------*
  Project:  NitroSDK - OS - demos - interrupt-key-1
  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.20  2004/08/06 12:45:23  yada
  change key interrupt logic enum

  Revision 1.19  2004/08/06 05:14:30  yada
  PAD_SetIrq -> PADi_SetIrq

  Revision 1.18  2004/06/09 02:08:01  yada
  back to 1.16

  Revision 1.17  2004/06/09 02:05:47  yada
  temporary for SDK1.2PR2

  Revision 1.16  2004/04/15 06:51:12  yada
  only arrange comment

  Revision 1.15  2004/04/13 07:46:22  yada
  Modified mask value for interrupt key setting

  Revision 1.14  2004/03/08 08:31:58  yada
  fix top comment

  Revision 1.13  2004/02/24 05:25:21  yasu
  Use OS_EnableIrqMask instead of OS_SetIrqMask

  Revision 1.12  2004/02/10 05:47:46  yasu
  delete macro CODE32

  Revision 1.11  2004/02/05 07:09:03  yasu
  change SDK prefix iris -> nitro

  Revision 1.10  2004/02/02 05:34:12  yada
  OS_EnableIrqMask() -> OS_EnableIrqMask()

  Revision 1.9  2004/01/29 08:07:40  yada
  Added GX_DispOn()

  Revision 1.8  2004/01/18 07:29:23  yada
  Modified due to the change of GX function name

  Revision 1.7  2004/01/18 06:49:20  yada
  (none)

  Revision 1.6  2004/01/17 11:44:44  yada
  Just modified comment

  Revision 1.5  2004/01/14 11:25:47  nishida_kenji
  add G2_OBJMosaic,
  remove GXOamMosaic

  Revision 1.4  2004/01/14 08:43:06  yada
  Just modified comment

  Revision 1.3  2004/01/09 10:53:49  yada
  Rewrote set function of interrupt check flag

  Revision 1.2  2004/01/08 12:06:11  yada
   Flush the cache before OAM data transfer

  Revision 1.1  2004/01/08 07:06:36  yada
  Initial version

  Revision 1.1  2004/01/08 06:32:45  yada
  Initial version


  $NoKeywords: $
 *---------------------------------------------------------------------------*/
#include <nitro.h>
#include "data.h"

static GXOamAttr  oamBak[ 128 ];

void    VBlankIntr( void );
void    ObjSet( int objNo, int x, int y, int charNo, int paletteNo );
void    KeyIntrSet( void );
void    KeyIntr( void );

static volatile u32 keyCnt = 0;

//---- Return 0-9, A-F codes by last 4 bit after shift ( right shift) cnt for OBJ display
inline int ObjChar( u32 cnt, int shift )
{
    u32 d = ( cnt >> shift ) & 0xf;
    return (int)( ( d < 10 )? '0'+d: 'A'+d-10 );
}

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

  Description:  main

  Arguments:    None

  Returns:      None
 *---------------------------------------------------------------------------*/
void NitroMain()
{
    //================ Initialization
    //---- OS Initialization
    OS_Init();
    
    //---- GX Initialization
    GX_Init();
    
    //================ Setting
    //---- All power ON
    GX_SetPower( GX_POWER_ALL );
    
    //----  Enable Vblank interrupt
    (void)OS_SetIrqFunction( OS_IE_V_BLANK, VBlankIntr );
    (void)OS_EnableIrqMask( OS_IE_V_BLANK );
    (void)OS_EnableIrq();

    //---- V blank occurrence setting
    (void)GX_VBlankIntr( TRUE );
    
    //---- VRAM Clear
    GX_SetBankForLCDC( GX_VRAM_LCDC_ALL );
    MI_CpuClearFast( (void*)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE );
    (void)GX_DisableBankForLCDC();
    
    //---- OAM and palette clear
    MI_CpuFillFast(  (void*)HW_OAM,  192, HW_OAM_SIZE  );
    MI_CpuClearFast( (void*)HW_PLTT,      HW_PLTT_SIZE );

    //---- Set bank A for OBJ
    GX_SetBankForOBJ( GX_VRAM_OBJ_128_A ); // Assign bank A for OBJ
    
    //---- Set graphics display mode
    GX_SetGraphicsMode( GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D );

    //---- Set only OBJ display ON
    GX_SetVisiblePlane( GX_PLANEMASK_OBJ );
    
    //---- Used in 32K byte OBJ with 2D mapping mode
    GX_SetOBJVRamModeChar( GX_OBJVRAMMODE_CHAR_2D ); // Used in 32K byte OBJ with 2D mapping mode
    
    //---- Data load
    MI_DmaCopy32( 3, sampleCharData, (void*)HW_OBJ_VRAM, sizeof( sampleCharData ) );
    MI_DmaCopy32( 3, samplePlttData, (void*)HW_OBJ_PLTT, sizeof( samplePlttData ) );
    
    //---- Moved non-display OBJ to outside of screen
    MI_DmaFill32( 3, oamBak, 0xc0, sizeof(oamBak) );

    //---- Start display
    SVC_WaitVBlankIntr();
    GX_DispOn();

    //================ Main loop
    //---- Key interrupt setting
    KeyIntrSet();

    while(1)
    {
        u16 keyData;

        //---- Wait for Vblank interrupt ends
        SVC_WaitVBlankIntr();

        //---- Read pad data
        keyData = PAD_Read();

        //---- Display counter value
        ObjSet( 0,  50,  100, ObjChar( keyCnt, 28 ), 2 );
        ObjSet( 1,  60,  100, ObjChar( keyCnt, 24 ), 2 );
        ObjSet( 2,  70,  100, ObjChar( keyCnt, 20 ), 2 );
        ObjSet( 3,  80,  100, ObjChar( keyCnt, 16 ), 2 );
        ObjSet( 4,  90,  100, ObjChar( keyCnt, 12 ), 2 );
        ObjSet( 5, 100,  100, ObjChar( keyCnt,  8 ), 2 );
        ObjSet( 6, 110,  100, ObjChar( keyCnt,  4 ), 2 );
        ObjSet( 7, 120,  100, ObjChar( keyCnt,  0 ), 2 );

        //---- Enable/disable timer interrupt with button
        if ( keyData & PAD_BUTTON_A ){ (void)OS_EnableIrqMask( OS_IE_TIMER0 );   }
        if ( keyData & PAD_BUTTON_B ){ (void)OS_DisableIrqMask( OS_IE_TIMER0 );  }
    }
}

//--------------------------------------------------------------------------------
//      OBJ setting
//
void ObjSet( int objNo, int x, int y, int charNo, int paletteNo )
{
    G2_SetOBJAttr(
        (GXOamAttr*)&oamBak[ objNo ],
        x,
        y,
        0,
        GX_OAM_MODE_NORMAL,
        FALSE,
        GX_OAM_EFFECT_NONE,
        GX_OAM_SHAPE_8x8,
        GX_OAM_COLOR_16,
        charNo,
        paletteNo,
        0 );
}


//--------------------------------------------------------------------------------
//    Vblank interrupt processing
//
void VBlankIntr(void)
{
    //---- Update OAM
    DC_FlushRange( oamBak, sizeof( oamBak ) );
    MI_DmaCopy32( 3, oamBak, (void*)HW_OAM, sizeof( oamBak ) );
    
    //---- Interrupt check flag
    OS_SetIrqCheckFlag( OS_IE_V_BLANK );
}

//--------------------------------------------------------------------------------
//              Key interrupt setting
//
void KeyIntrSet( void )
{
    //---- Key interrupt routine setting
    OS_SetIrqFunction( OS_IE_KEY, KeyIntr );

    //---- Enable Key interrupt
    (void)OS_EnableIrqMask( OS_IE_KEY );

    //---- Key interrupt setting
#if 1
    PADi_SetIrq( PAD_LOGIC_OR, TRUE, PAD_KEYPORT_MASK ); // Interrupt when any of all button is pushed 
#else
    // Try this too
    PADi_SetIrq( PAD_LOGIC_AND, TRUE, PAD_BUTTON_A | PAD_BUTTON_B ); // Interrupt by pushing both A and B buttons
#endif
}

//--------------------------------------------------------------------------------
//              Key interrupt processing
//
void KeyIntr( void )
{
    keyCnt = keyCnt + 1;

    //---- Interrupt check flag
    OS_SetIrqCheckFlag( OS_IE_KEY );
}

/*====== End of main.c ======*/
