/****************************************************************************
 * DECODER.C                                                                *
 *                                                                          *
 * Purpose: Sample program to demonstrate the video decoder capabilities    *
 *          of the Rage Theatre chip.                                       *
 *                                                                          *
 * Copyright (C) 1999 ATI Technologies Inc.  All rights reserved.           *
 ****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctype.h>
#include <string.h>
#include "..\util\main.h"
#include "..\util\defines.h"
#include "..\util\regdef.h"

DWORD SRCWIDTH = 640;
DWORD SRCHEIGHT = 240; // we're only capturing one field at a time.
DWORD OVWIDTH = 640;
DWORD OVHEIGHT = 480;
WORD CHANNEL = 33;
BYTE DEFAULT_VOLUME = 0x67;

void PrintStatus (void);
void SetOverlayDetailSurface(CAPTURE_DESCRIPTOR *cap);

/****************************************************************************
 * Main Program to demonstrate Rage Theatre video decoder                   *
 *  Function: To display video using the Rage Theatre as the video decoder  *
 *    Inputs: Arguments for mode spatial and colour resolution              *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void main (int argc, char *argv[])
{
    CAPTURE_DESCRIPTOR cap;
    DWORD x, y, phase = 1;
    char input;
    char buffer[80];
    BYTE volume = DEFAULT_VOLUME;

    RT_INFO = &RT_DATA;

    R128_StartUp (argc, argv);
    R128_ClearScreen (WHITE);
    R128_LoadText ();

    R128_GetPLLInfo ();

    AddressInfo.Tuner = 0xC6;

    // set up the I2C engine
    R128_SetI2CInfo (10000);  // use a 10 kHz clock

    // enable I2C hardware
    I2C_Enable ();

    
	R128_InitVIP ();

    RT_DEVICE_NUM = RT_GetVIPAddress ();

    if (RT_DEVICE_NUM < 0)
    {
        // Shut down and exit, we cannot find a Rage Theatre.
        I2C_Stop ();
        I2C_Disable ();
        R128_ShutDown ();
        printf ("\nRage Theatre not detected.\nProgram terminated.");
        exit (1);
    }

    // Read in the MMTABLE from the BIOS, for connector information
    R128_GetMMTable (&MMTABLE);

    // Initialize and enable the R128 capture 0 unit
    R128_InitCaptureDescriptor (&cap);
    // set up the capture buffers and other fields we want to use
    cap.buf0_offset = R128_AdapterInfo.xres * R128_AdapterInfo.bytepp * R128_AdapterInfo.yres;
//    cap.buf0_offset = 0;
    cap.buf0_even_offset = cap.buf0_offset + (SRCWIDTH * SRCHEIGHT * 2);//cap.buf0_offset + R128_AdapterInfo.xres * R128_AdapterInfo.bytepp * SRCHEIGHT;
	cap.buf1_offset = cap.buf0_even_offset;
	cap.buf1_even_offset = cap.buf1_offset;
    cap.input_mode = CAP_MODE_CONTINUOUS;
    cap.buf_mode = CAP_BUF_MODE_SINGLE;
    cap.buf_type = CAP_BUF_TYPE_ALTERNATING;
    cap.video_in_format = CAP_VIDEO_IN_FORMAT_VYUY422;
    cap.stream_format = CAP_STREAM_FORMAT_CCIR656;
    cap.buf_pitch = SRCWIDTH * 2;
    cap.width = SRCWIDTH;
    cap.height = SRCHEIGHT;

    // Set up the overlay.  The overlay buffer will be at offset
    // 0, at the start of the frame buffer.  The pitch of the 'surface'
    // will be equal to the pitch of the capture surface (in bytes)
    R128_InitOverlayDescriptor (&OverlayDescriptor);
    R128_GetBandwidthInfo (&OverlayDescriptor);
    R128_SetOverlayDefaults (0xB, SRCWIDTH, SRCHEIGHT, 1.0, 1.0, &OverlayDescriptor);
    R128_SetupOverlay (&OverlayDescriptor, &OverlayRegFields);
    SetOverlayDetailSurface(&cap);
    // Set the overlay to key on LIGHTMAGENTA.
//    R128_SetOverlayColourKey (LIGHTMAGENTA, WHITE, 5, 0, 0);

    R128_InitCapture (&cap);
    R128_EnableCapture ();
    R128_SetTunerChannel (CHANNEL);



    x = R128_AdapterInfo.xres-OVWIDTH;
    y = R128_AdapterInfo.yres-OVHEIGHT;

    // Draw the keying rectangle.
    R128_DrawRectangle (x, y, OVWIDTH, OVHEIGHT, LIGHTMAGENTA);
    sprintf (buffer, "Channel: %d", CHANNEL);
    R128_PrintText (buffer, x+5, y+5, LIGHTGREEN, WHITE, 1);
    R128_SetOverlay (x, y, OVWIDTH, OVHEIGHT);

    // Enable Rage Theatre.
    RT_Init ();

    // Enable audio.
    EnableMSP3430 ();
    MSP3430_SetVolume (volume);

//    PrintStatus ();

    while ((input = getch ())!=27)
    {
        switch (toupper(input))
        {
            case ' ':   // Reset Video Levels to default.
                        RT_ResetVideoLevels ();
                        if (RT_INFO->wConnector == DEC_TUNER)
                        {
                            volume = DEFAULT_VOLUME;
                            MSP3430_SetVolume (volume);
                        }
                        break;

            // Change brightness, Q and A
            case 'Q':   RT_INFO->iBrightness += 5;
                        RT_SetBrightness (RT_INFO->iBrightness);
                        break;
            case 'A':   RT_INFO->iBrightness -= 5;
                        RT_SetBrightness (RT_INFO->iBrightness);
                        break;

            // Change contrast, W and S
            case 'W':   RT_INFO->iContrast += 5;
                        RT_SetContrast (RT_INFO->iContrast);
                        break;
            case 'S':   RT_INFO->iContrast -= 5;
                        RT_SetContrast (RT_INFO->iContrast);
                        break;

            // Change Saturation, E and D
            case 'E':   RT_INFO->iSaturation += 5;
                        RT_SetSaturation (RT_INFO->iSaturation);
                        break;
            case 'D':   RT_INFO->iSaturation -= 5;
                        RT_SetSaturation (RT_INFO->iSaturation);
                        break;

            // Change Hue/Tint, R and F
            case 'R':   RT_INFO->iHue += 5;
                        RT_SetTint (RT_INFO->iHue);
                        break;
            case 'F':   RT_INFO->iHue -= 5;
                        RT_SetTint (RT_INFO->iHue);
                        break;

            // Change 'sharpness' between smooth and sharp
            case 'X':   if (!phase)
                        {
                            RT_SetSharpness (DEC_SMOOTH);
                        }
                        else
                        {
                            RT_SetSharpness (DEC_SHARP);
                        }
                        phase+=1;
                        if (phase >= 2) phase = 0;
                        break;

            // Increase/decrease volume (T and G)
            case 'T':   volume += 1;
                        if (volume > 0x7F)
                            volume = 0x7F;
                        MSP3430_SetVolume (volume);
                        break;
            case 'G':   volume -= 1;
                        if (volume <= 0)
                            volume = 0;
                        MSP3430_SetVolume (volume);
                        break;

            // Change the input connector from composite, tuner or SVideo
            case '1':   // set for composite input to be used.
                        RT_SetConnector (DEC_COMPOSITE, 0);
                        MSP3430_SetVolume (0);
                        break;
            case '2':   // set for tuner input.
                        // make sure we are in continuous capture mode first.
                        cap.input_mode = CAP_MODE_CONTINUOUS;
                        cap.buf_mode = CAP_BUF_MODE_SINGLE;
                        cap.buf_type = CAP_BUF_TYPE_ALTERNATING;
                        cap.video_in_format = CAP_VIDEO_IN_FORMAT_VYUY422;
                        R128_SetCaptureConfig (&cap);
                        RT_SetConnector (DEC_TUNER, 0);
                        MSP3430_SetVolume (volume);
                        break;
            case '3':   // set for S-video input
                        RT_SetConnector (DEC_SVIDEO, 0);
                        MSP3430_SetVolume (0);
                        break;

            // Change the channel on the tuner
            case '+':   if (RT_INFO->wConnector == DEC_TUNER)
                        {
                            CHANNEL++;
                            if (CHANNEL >= 125) CHANNEL = 1;
                            R128_SetTunerChannel (CHANNEL);
                        }
                        break;
            case '-':   if (RT_INFO->wConnector == DEC_TUNER)
                        {
                            CHANNEL--;
                            if (CHANNEL == 0) CHANNEL = 125;
                            R128_SetTunerChannel (CHANNEL);
                        }
                        break;
            default:    break;
        }

        // Clear the register setting text
        R128_DrawRectangle (0, 0, R128_AdapterInfo.xres, 100, WHITE);
        // Draw the keying rectangle.
        R128_DrawRectangle (x, y, OVWIDTH, OVHEIGHT, LIGHTMAGENTA);
        if (RT_INFO->wConnector == DEC_TUNER)
        {
            sprintf (buffer, "Channel: %d", CHANNEL);
            R128_PrintText (buffer, x+5, y+5, LIGHTGREEN, WHITE, 1);
        }
        R128_SetOverlay (x, y, OVWIDTH, OVHEIGHT);

        PrintStatus ();

    } // while

    // Shutting down...

    DisableMSP3430 ();
    RT_ShutDown ();
    R128_DisableCapture ();

    I2C_Stop ();
    I2C_Disable ();

    R128_DisableOverlay ();
    R128_Delay (5);

    R128_ShutDown ();

    exit (0);

} // main ()...


/****************************************************************************
 * PrintStatus (void)                                                       *
 *  Function: display the status of related registers and control values    *
 *    Inputs: NONE                                                          *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void PrintStatus (void)
{
    DWORD temp;
    WORD result;
    char buffer[80];

    // Print the video level settings
    sprintf (buffer, "X Sharpness: %2.2d", RT_INFO->wSharpness);
    R128_PrintText (buffer, 5, R128_AdapterInfo.yres-(6*TEXT_INFO.height), BLACK, WHITE, 0);

    sprintf (buffer, "Q A Brightness: %3.3d", RT_INFO->iBrightness);
    R128_PrintText (buffer, 5, R128_AdapterInfo.yres-(5*TEXT_INFO.height), BLACK, WHITE, 0);

    sprintf (buffer, "W S Contrast: %3.3d", RT_INFO->iContrast);
    R128_PrintText (buffer, 5, R128_AdapterInfo.yres-(4*TEXT_INFO.height), BLACK, WHITE, 0);

    sprintf (buffer, "E D Saturation: %3.3d", RT_INFO->iSaturation);
    R128_PrintText (buffer, 5, R128_AdapterInfo.yres-(3*TEXT_INFO.height), BLACK, WHITE, 0);

    sprintf (buffer, "R F Tint: %3.3d", RT_INFO->iHue);
    R128_PrintText (buffer, 5, R128_AdapterInfo.yres-(2*TEXT_INFO.height), BLACK, WHITE, 0);

    sprintf (buffer, " SPACEBAR to reset");
    R128_PrintText (buffer, 5, R128_AdapterInfo.yres-(1*TEXT_INFO.height), BLACK, WHITE, 0);

    // Print registers.
    RT_regr (VIP_LP_CONTRAST, &temp);
    sprintf (buffer, "LP CONTRAST: %8.8X", temp);
    R128_PrintText (buffer, 5, (0*TEXT_INFO.height), BLACK, WHITE, 0);

    RT_regr (VIP_LP_BRIGHTNESS, &temp);
    sprintf (buffer, "LP BRIGHTNESS: %8.8X", temp);
    R128_PrintText (buffer, 5, (1*TEXT_INFO.height), BLACK, WHITE, 0);

    RT_regr (VIP_CP_ACTIVE_GAIN, &temp);
    sprintf (buffer, "CP ACTIVE GAIN: %8.8X", temp);
    R128_PrintText (buffer, 5, (2*TEXT_INFO.height), BLACK, WHITE, 0);

    RT_regr (VIP_CP_HUE_CNTL, &temp);
    sprintf (buffer, "CP HUE CNTL: %8.8X", temp);
    R128_PrintText (buffer, 5, (3*TEXT_INFO.height), BLACK, WHITE, 0);

    result = ReadI2CWord (RD_DSP, 0x0000);
    sprintf (buffer, "VOL MAIN: %4.4X", result);
    R128_PrintText (buffer, 5, (4*TEXT_INFO.height), BLACK, WHITE, 0);

} // PrintStatus ()...
/****************************************************************************
 * SetOverlayDetailedSurface (CAPTURE_DESCRIPTOR *cap)                      *
 *  Function: sets the buffer addresses for multiple overlay buffers.       *
 *    Inputs: CAPTURE_DESCRIPTOR *cap - pointer to capture structure        *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void SetOverlayDetailSurface(CAPTURE_DESCRIPTOR *cap)
{
    DWORD offset, offset2, offset3, offset4;

    offset = cap->buf0_offset;
    offset2 = cap->buf0_even_offset;
    offset3 = cap->buf1_offset;
	offset4 = cap->buf1_even_offset;

    OverlayDescriptor.USE_DETAILED_SURFACE_DESCRIPTION = 1;
    OverlayDescriptor.AutoFlipVideoProvider = 0; // use cap port 0

    OverlayDescriptor.BaseOffsetOfSurface[0] = offset;
    OverlayDescriptor.BaseOffsetOfSurface[1] = offset2;
    OverlayDescriptor.BaseOffsetOfSurface[2] = offset3;
    OverlayDescriptor.BaseOffsetOfSurface[3] = offset4;
    OverlayDescriptor.PitchSelectOfSurface[0] = 0;
    OverlayDescriptor.PitchSelectOfSurface[1] = 0;
    OverlayDescriptor.TiledFlagOfSurface[0] = 0;
    OverlayDescriptor.TiledFlagOfSurface[1] = 0;
    OverlayDescriptor.SurfacePitch[0] = SRCWIDTH*2;
    OverlayDescriptor.SurfacePitch[1] = SRCWIDTH*2;
    R128_SetupOverlay (&OverlayDescriptor, &OverlayRegFields);

    OverlayRegFields.val_OV0_VID_PORT_SELECT = 0;
    OverlayRegFields.val_OV0_DEINT_PAT = 0xAAAAA;
    R128_WriteOverlayFields (&OverlayRegFields);

} // SetOverlayDetailedSurface ()...

