/*****************************************************************************/

/*
 *     fmpcontrol.c -- REALmagic FMP generic controls
 *
 *      Copyright (C) 2001 Sigma Designs
 *                    written by Pascal Cannenterre <pascal_cannenterre@sdesigns.com>
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define _DEFINE_FMP_TYPES_
#include "fmp.h"
#include "fmpcontrol.h"

#define UNUSED_ARG 0xdeadbeef

BOOL check_vga_cable_presence()
{
  if (FMPAnalogOverlay(FMP_ANALOG_OVERLAY_GET,FMP_ANALOG_OVERLAY_ATTRIBUTE_OVERLAY_CABLE_PRESENT,
		       UNUSED_ARG,UNUSED_ARG,UNUSED_ARG,UNUSED_ARG))
    return TRUE;
  else 
    return FALSE; 
}

BOOL waitForAnalogOverlayAccess()
{
  while (FMPAnalogOverlay(FMP_ANALOG_OVERLAY_ACCESS,0,0,0,0,0)!=FMPE_OK)
    sleep(1);
  
  return TRUE;  
}

DWORD setOverlayDestination(DWORD xx, DWORD yy, DWORD width, DWORD height)
{
  return FMPSetDestination (xx, yy, width, height);
}

DWORD setOverlayResolution(DWORD xres, DWORD yres, DWORD depth)
{
  return FMPAnalogOverlay (FMP_ANALOG_OVERLAY_SET,FMP_ANALOG_OVERLAY_ATTRIBUTE_DISPLAYRESOLUTION,depth,xres,yres,UNUSED_ARG);
}

DWORD setOverlayCalibration(DWORD color_code)
{
  return FMPAnalogOverlay(FMP_ANALOG_OVERLAY_AUTOCALIBRATION, color_code ,UNUSED_ARG,UNUSED_ARG,UNUSED_ARG,UNUSED_ARG);
}


DWORD setOverlay(DWORD overlay_mode, DWORD key_color)
{
  /* Switch output to VGA */
  setOutputMode(FMPV_VIDEOOUT_VGA);
  
  switch(overlay_mode)
    {
    case 0:
      FMPAnalogOverlay(FMP_ANALOG_OVERLAY_SET,FMP_ANALOG_OVERLAY_ATTRIBUTE_MODE,0,UNUSED_ARG,UNUSED_ARG,UNUSED_ARG);
      break;
    case 1:
      FMPAnalogOverlay(FMP_ANALOG_OVERLAY_SET,FMP_ANALOG_OVERLAY_ATTRIBUTE_MODE,1,UNUSED_ARG,UNUSED_ARG,UNUSED_ARG);
	break;
    case 2:
      FMPAnalogOverlay(FMP_ANALOG_OVERLAY_SET,FMP_ANALOG_OVERLAY_ATTRIBUTE_MODE,2,UNUSED_ARG,UNUSED_ARG,UNUSED_ARG);
      /* Set key color */
      if(key_color != NO_KEYCOLOR)
	FMPAnalogOverlay(FMP_ANALOG_OVERLAY_SET,FMP_ANALOG_OVERLAY_ATTRIBUTE_VGAKEY,key_color,UNUSED_ARG,UNUSED_ARG,UNUSED_ARG);
      break;
    default:
      return FMPE_ERROR;
      break;
    }
  return FMPE_OK;
}




DWORD setMute(BOOL mute)
{
  return FMPSet(FMPI_MUTE, (DWORD) mute);
}

DWORD getMute(BOOL *mute)
{
  DWORD muting;
  if(mute == NULL)
    return FMPE_ERROR;
  
  muting = FMPGet(FMPI_MUTE);
  *mute = (BOOL)muting;
  return FMPE_OK;
}

DWORD setAudioBalance(DWORD volume, long balance)
{
  DWORD volumeleft, volumeright;
  long adjust; 
  
  adjust = volume * (balance / 100.0);

  if (balance < 0)
    {
      volumeleft = volume;
      volumeright = volume + adjust;
      FMPSet(FMPI_LEFT_VOLUME, volumeleft);
      FMPSet(FMPI_RIGHT_VOLUME, volumeright);
    }
  else if (balance > 0)
    {
      volumeright = volume;
      volumeleft = volume - adjust;
      FMPSet(FMPI_RIGHT_VOLUME, volumeright);
      FMPSet(FMPI_LEFT_VOLUME, volumeleft);    
    }
  else
    {
      volumeleft = volume;
      FMPSet(FMPI_RIGHT_VOLUME, volumeleft);
      FMPSet(FMPI_LEFT_VOLUME, volumeleft); 
    }
  
  return FMPE_OK;
}

DWORD getAudioBalance(DWORD *vol, long *bal)
{
  DWORD volumeleft;
  DWORD volumeright;
  DWORD balance;
  
  if(vol == NULL || bal == NULL)
    return FMPE_ERROR;
  
  volumeleft = FMPGet(FMPI_LEFT_VOLUME);
  volumeright = FMPGet(FMPI_RIGHT_VOLUME);

  if(volumeleft == volumeright)
    {
      *bal = 0;
      *vol = volumeleft;
    }
  else if(volumeleft > volumeright)
    {
     balance = 100 *(1-(volumeright / (1.0*volumeleft) )); 
     *bal = -1*balance;
     *vol = volumeleft;
    }
  else if(volumeleft < volumeright)
    {
      balance = 100 *(1-(volumeleft / (1.0*volumeright) ));
      *bal = balance;
      *vol = volumeright;
    }
  
  return FMPE_OK;
}

DWORD setTvStandard(DWORD  newtvmode) 
{
  DWORD tvmode;
  tvmode = FMPGet(FMPI_VIDEOOUT);
  tvmode = tvmode & (~FMPV_VIDEOOUT_STANDARDTV_MASK);
  tvmode = tvmode | newtvmode;                       
  return FMPSet(FMPI_VIDEOOUT, tvmode);
}

DWORD getTvStandard(DWORD *ovl)
{
  DWORD tvmode;
  if(ovl == NULL)
    return FMPE_ERROR;
  tvmode = FMPGet(FMPI_VIDEOOUT);
  tvmode = tvmode & (~FMPV_VIDEOOUT_MODE_MASK);
  tvmode = tvmode & (~FMPV_VIDEOOUT_COMPONENT_MASK);
  *ovl = tvmode;

  return FMPE_OK;
}

DWORD getComponentMode(DWORD *ovl)
{
  DWORD componentmode;
  if(ovl == NULL)
    return FMPE_ERROR;
  componentmode = FMPGet(FMPI_VIDEOOUT);
  componentmode = componentmode & (~FMPV_VIDEOOUT_MODE_MASK);
  componentmode = componentmode & (~FMPV_VIDEOOUT_STANDARDTV_MASK);
  *ovl = componentmode;
  return FMPE_OK;
}

DWORD setComponentMode(DWORD  newoutputmode) 
{
  DWORD outmode;
  outmode = FMPGet(FMPI_VIDEOOUT);
  outmode = outmode & (~FMPV_VIDEOOUT_COMPONENT_MASK); 
  outmode = outmode | newoutputmode;                  
  return FMPSet(FMPI_VIDEOOUT, outmode);
}

DWORD setOutputMode(DWORD newvgatv)
{
  DWORD vgatv;
  vgatv = FMPGet(FMPI_VIDEOOUT);
  vgatv = vgatv  & (~FMPV_VIDEOOUT_MODE_MASK);
  vgatv = vgatv | newvgatv;
  return FMPSet(FMPI_VIDEOOUT, vgatv);
}

DWORD getOutputMode(DWORD *ovl)
{
  DWORD vgatv;
  if(ovl == NULL)
    return FMPE_ERROR;
  vgatv = FMPGet(FMPI_VIDEOOUT);
  vgatv = vgatv  & (~FMPV_VIDEOOUT_COMPONENT_MASK);
  vgatv = vgatv  & (~FMPV_VIDEOOUT_STANDARDTV_MASK);
  *ovl = vgatv;
  return FMPE_OK;
}

DWORD setAudioChannelMode(DWORD mode)
{
  return FMPSet(FMPI_AUDIO_MODE, mode);
}

DWORD getAudioChannelMode(DWORD *ovl)
{
  if(ovl == NULL)
    return FMPE_ERROR;
  *ovl = FMPGet(FMPI_AUDIO_MODE);
  return FMPE_OK;
}

DWORD setAudioAC3DTS(DWORD spdif)
{
  /* spdif == 1 => AC3, DTS elsif spdif == 0 => PCM stereo */
  return FMPSet(FMPI_AUDIO_OUTPUT, spdif); 
}

DWORD getAudioAC3DTS(DWORD *ovl)
{
  if(ovl == NULL)
    return FMPE_ERROR;
  *ovl = FMPGet(FMPI_AUDIO_OUTPUT);
  return FMPE_OK;;
}

/* Some functions to avoid the direct use of FMPOpen()
 * and FMPClose()
 */

DWORD calibrationInit()
{
  return FMPOpen(FMPF_SYSTEM, 32*1024, 8, NULL, 0);
}

DWORD calibrationEnd()
{
  return FMPClose();
}

DWORD getFMPProperty(DWORD query, DWORD *property)
{
  if(property == NULL)
    return FMPE_ERROR;
  
  *property = FMPGet(query);
  
  return FMPE_OK;
}

DWORD setFMPProperty(DWORD query, DWORD property)
{
  return FMPSet(query, property);
}

DWORD convertSecondstoHhMmSs(DWORD time)
{
  BYTE h, m, s;
  DWORD hhmmss;
  
  h = time / 3600;
  m = (time % 3600) / 60;
  s = (time % 60);
  
  hhmmss = 
    (((h / 10) << 4) | (h % 10) |
     ((DWORD)(m / 10) << 12) | ((DWORD)(m % 10) << 8) |
     ((DWORD)(s / 10) << 20) | ((DWORD)(s % 10) << 16)) & 0x00ffffff;
  
  return hhmmss;

}

DWORD convertHhMmSstoSeconds(DWORD hhmmss)
{
  BYTE h, m, s;
  BYTE h10, m10, s10;
  
  h = hhmmss & 0xff;
  m = (hhmmss >> 8) & 0xff;
  s = (hhmmss >> 16) & 0xff; 
  h10 = 10*((h >> 4) & 0xf) + (h & 0xf);
  m10 = 10*((m >> 4) & 0xf) + (m & 0xf);
  s10 = 10*((s >> 4) & 0xf) + (s & 0xf);
  
  return (3600*h10 + 60*m10 + s10);
}
