/****************************************************************************
 * CAPTURE.C                                                                *
 *                                                                          *
 * Purpose: Demonstrates how to setup basic video capture using the         *
 *          Rage 128 and the ATI TV Tuner card (Brooktree 8x9 decoder)      *
 *                                                                          *
 * Copyright (C) 1999 ATI Technologies Inc.  All rights reserved.           *
 ****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctype.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;
BYTE FORMAT = 0; // 0 = 640x480, 1 = 720x480, 2 = 320x240
BYTE INPUT = DEC_SRC_TUNER; // 1 = COMPOSITE, 2 = TUNER, 3 = SVIDEO
WORD CHANNEL = 24;

void InitCapture (void);
void EnableCapture (void);
void DisableCapture (void);

/****************************************************************************
 * Main Program to demonstrate video capture for the Rage 128               *
 *  Function: Enables capture with the Bt8x9 chip, using the composite      *
 *            video input.                                                  *
 *    Inputs: Arguments for mode spatial and colour resolution              *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void main (int argc, char *argv[])
{
    SURFACE Surface;
    DWORD x, y, offset, temp;
    char input;
    char buffer[40];
    char *input_str[4] = { "COMPOSITE", "TUNER", "SVIDEO", NULL };
    BYTE retval;

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

    if (R128_AdapterInfo.xres < 640)
    {
        R128_ShutDown ();
        printf ("\nThis program must be run at 640x480 resolution or higher.");
        printf ("\nShutting down.");
        exit (1);
    }

    if (R128_AdapterInfo.xres == 640)
    {
        OVWIDTH = 512;
        OVHEIGHT = 384;
    }

    // Initialize and enable the R128 capture 0 unit
    InitCapture ();
    EnableCapture ();

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

    // enable I2C hardware
    I2C_Enable ();

    R128_GetI2CAddressInfo ();
    GetCaptureCardType ();

    // Check for the presence of the ATI TV Tuner
/*    retval = R128_IsTVTunerInstalled ();
    if (!retval)
    {
        R128_DisableCapture ();
        I2C_Stop ();
        I2C_Disable ();
        R128_ShutDown ();
        printf ("\nThis program requires an ATI TV Tuner card.");
        printf ("\nShutting down.");
        exit (1);
    }
*/
    // Set up the overlay.
    // The overlay buffer will be at the beginning of offscreen memory.
    offset = R128_AdapterInfo.xres * R128_AdapterInfo.bytepp * R128_AdapterInfo.yres;
    CreateSurface (SRCWIDTH, SRCHEIGHT, 0xB, 0, offset, &Surface);
    R128_InitOverlayDescriptor (&OverlayDescriptor);
    R128_GetBandwidthInfo (&OverlayDescriptor);
    R128_SetOverlayDefaults (0xB, SRCWIDTH, SRCHEIGHT, 1.0, 1.0, &OverlayDescriptor);
    OverlayDescriptor.SimpleSurfacePitch = SRCWIDTH*2; // in bytes.
    OverlayDescriptor.SimpleBaseOffsetOfSurface = offset;
    R128_SetupOverlay (&OverlayDescriptor, &OverlayRegFields);
    // Set a light magenta colour key for the overlay.
//    R128_SetOverlayColourKey (LIGHTMAGENTA, WHITE, 5, 0, 0);

    // Enable the decoder for default operation: 640x480 NTSC capture,
    // composite input.
    R128_SetDecoderDefaults (FORMAT, INPUT);
    R128_SetTunerChannel (CHANNEL);

    EnableDecoder();

    x = (R128_AdapterInfo.xres-OVWIDTH)/2;
    y = (R128_AdapterInfo.yres-OVHEIGHT)/2;

    // Draw the colour keying rectangle.
    R128_DrawRectangle (x, y, OVWIDTH, OVHEIGHT, LIGHTMAGENTA);
    R128_SetOverlay (x, y, OVWIDTH, OVHEIGHT);
    sprintf (buffer, "Input source: %s", input_str[INPUT-1]);
    R128_PrintText (buffer, 5, 5, BLACK, WHITE, 1);
    R128_PrintText ("PLUS key: channel up      MINUS key: channel down",
                     5, 5+TEXT_INFO.height, BLACK, WHITE, 1);
    R128_PrintText ("C: continuous capture   T: one shot capture", 5,
                    R128_AdapterInfo.yres-(2*TEXT_INFO.height), BLACK, WHITE, 1);
    R128_PrintText ("1: composite  2: tuner  3: Svideo", 5,
                    R128_AdapterInfo.yres-TEXT_INFO.height, BLACK, WHITE, 1);

    while ((input = getch ())!=27)
    {

        R128_ClearScreen (WHITE);

        switch (toupper(input))
        {
            case 'C':   R128_WaitForFifo (1);
                        regw (CAP0_CONFIG, CAP_VIDEO_IN_FORMAT_VYUY422 | CAP_MODE_CONTINUOUS);
                        break;
            case 'T':   R128_WaitForFifo (3);
                        regw (CAP0_CONFIG, CAP_VIDEO_IN_FORMAT_VYUY422 | CAP_MODE_ONE_SHOT);
                        // Set the trigger to capture the image.
                        temp = regr (CAP0_TRIG_CNTL) | 0x1;
                        regw (CAP0_TRIG_CNTL, temp);
                        break;
            case '1':   // set for composite input to be used.
                        INPUT = DEC_SRC_COMPOSITE;
                        R128_SetDecoderSource (INPUT);
                        break;
            case '2':   // set for tuner input.
                        // make sure we are in continuous capture mode first.
                        R128_WaitForFifo (1);
                        regw (CAP0_CONFIG, CAP_VIDEO_IN_FORMAT_VYUY422 | CAP_MODE_CONTINUOUS);
                        INPUT = DEC_SRC_TUNER;
                        R128_SetDecoderSource (INPUT);
                        R128_SetTunerChannel (CHANNEL);
                        break;
            case '3':   // set for S-video input
                        INPUT = DEC_SRC_SVIDEO;
                        R128_SetDecoderSource (INPUT);
                        break;
            case '+':   if (INPUT == DEC_SRC_TUNER)
                        {
                            CHANNEL++;
                            if (CHANNEL >= 125) CHANNEL = 1;
                            R128_SetTunerChannel (CHANNEL);
                        }
                        break;
            case '-':   if (INPUT == DEC_SRC_TUNER)
                        {
                            CHANNEL--;
                            if (CHANNEL == 0) CHANNEL = 125;
                            R128_SetTunerChannel (CHANNEL);
                        }
                        break;
            default:    break;
        }

        // Draw the colour keying rectangle.
        R128_DrawRectangle (x, y, OVWIDTH, OVHEIGHT, LIGHTMAGENTA);

        // If we're using the tuner, display the channel in the overlay.
        if (INPUT == DEC_SRC_TUNER)
        {
            sprintf (buffer, "Channel: %d", CHANNEL);
            R128_PrintText (buffer, x+5, y+5, LIGHTGREEN, WHITE, 1);
        }

        sprintf (buffer, "Input source: %s", input_str[INPUT-1]);
        R128_PrintText (buffer, 5, 5, BLACK, WHITE, 1);
        R128_PrintText ("PLUS key: channel up      MINUS key: channel down",
                         5, 5+TEXT_INFO.height, BLACK, WHITE, 1);
        R128_SetOverlay (x, y, OVWIDTH, OVHEIGHT);
        R128_PrintText ("C: continuous capture   T: one shot capture", 5,
                        R128_AdapterInfo.yres-(2*TEXT_INFO.height), BLACK, WHITE, 1);
        R128_PrintText ("1: composite  2: tuner  3: Svideo", 5,
                        R128_AdapterInfo.yres-TEXT_INFO.height, BLACK, WHITE, 1);

    }

    R128_DisableCapture ();

    I2C_Stop ();
    I2C_Disable ();

    R128_DisableOverlay ();
    R128_Delay (5);
    R128_ShutDown ();

    exit (0);
} // main ()...


/****************************************************************************
 * InitCapture (void)                                                       *
 *  Function: Initializes the Rage 128 capture engine, setting a single     *
 *            capture buffer, basic setup for the Bt8x9 decoder stream.     *
 *    Inputs: NONE                                                          *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void InitCapture (void)
{
    DWORD offset;

    offset = R128_AdapterInfo.xres * R128_AdapterInfo.bytepp * R128_AdapterInfo.yres;

    R128_WaitForFifo (11);

    regw (CAP0_BUF0_OFFSET, offset);

    // We program this even though we don't use it, otherwise enabling
    // TRIG_CNTL can write to this buffer pointer as well!
    regw (CAP0_ONESHOT_BUF_OFFSET, offset);

    regw (CAP0_BUF_PITCH, SRCWIDTH*2);
    regw (CAP0_V_WINDOW, IGNORE_VBI | (IGNORE_VBI + SRCHEIGHT << 16));

    // This is in bytes, not pixels
    regw (CAP0_H_WINDOW, 0 | ((SRCWIDTH*2)<<16) );

    // 8 bit for BT, 16 bit for ZV.  Use lower byte.
    regw (CAP0_PORT_MODE_CNTL, 0);

    // Set the downscaler to 1.0 ratios
    regw (CAP0_DWNSC_XRATIO, 0x10001000);

    // Set up CAP0_CONFIG for the following:
    // CAP0_VIDEO_IN_FORMAT - YVYU
    // CAP0_INPUT_MODE - continuous
    regw (CAP0_CONFIG, CAP_VIDEO_IN_FORMAT_VYUY422 | CAP_MODE_CONTINUOUS);
    regw (CAP0_TRIG_CNTL, 0);    // Initially capture is disabled

    // Turn Debug off
    regw (TEST_DEBUG_CNTL, 0);

    // Connect Capture engine to AMC connector
    regw (VIDEOMUX_CNTL,  regr (VIDEOMUX_CNTL) | 0x01);

} // InitCapture ()...

/****************************************************************************
 * EnableCapture (void)                                                     *
 *  Function: Triggers the Rage 128 capture engine                          *
 *    Inputs: NONE                                                          *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void EnableCapture (void)
{
    // Select the CLOCK the capture engine will be using
    // Set it to PCLK
    PLL_regw (FCP_CNTL, 0x00000101);
    // CAP0_TRIG_CNTL__CAP0_TRIGGER_W | CAP0_TRIG_CNTL__CAP0_EN
    regw (CAP0_TRIG_CNTL, 0x00000011);

}   // EnableCapture ()...

/****************************************************************************
 * DisableCapture (void)                                                    *
 *  Function: Shuts down the Rage 128 capture engine                        *
 *    Inputs: NONE                                                          *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void DisableCapture (void)
{
    regw (CAP0_TRIG_CNTL, 0);
    // Disable the capture engine clock (set to ground)
    PLL_regw (FCP_CNTL, 0x00000404);

} // DisableCapture ()...

