#include "diseqc.h"
#include "menu.h"
#include "menuitems.h"
#include <sys/ioctl.h>
#include <linux/dvb/frontend.h>
#include <math.h>
#include <vdr/interface.h>

cMenuSetupRotor::cMenuSetupRotor(void)
{
  newDvbCard=data.DvbCard+1;
//  newAByte=data.AByte-18;
  newrepeat=data.repeat;
  newLat=data.Lat;
  newLong=data.Long;
  newSN=data.SN;
  newEW=data.EW;
  newSLOF=data.SLOF;
  newFrequLo=data.FrequLo;
  newFrequHi=data.FrequHi;
  newUseGotoX=data.UseGotoX;
  newShowInfo=data.ShowInfo;
  Add(new cMenuEditIntItem (tr("Card, connected with motor"), &newDvbCard,1,cDevice::NumDevices()));
  Add(new cMenuEditBoolItem(tr("Repeat DiSEqC-Commands?"), &newrepeat));
//  Add(new cMenuEditIntItem (tr("Address-Byte"), &newAByte,30,31));
  Add(new cMenuEditIntpItem(tr("Latitude"), &newLat,0,900,&newSN,tr("North"),tr("South")));
  Add(new cMenuEditIntpItem(tr("Longitude"), &newLong,0,1800,&newEW,tr("West"),tr("East")));
  Add(new cMenuEditIntItem (tr("Setup.LNB$SLOF (MHz)"), &newSLOF));
  Add(new cMenuEditIntItem (tr("Setup.LNB$Low LNB frequency (MHz)"), &newFrequLo));
  Add(new cMenuEditIntItem (tr("Setup.LNB$High LNB frequency (MHz)"), &newFrequHi));
  Add(new cMenuEditBoolItem(tr("Use GotoX on channel switch"), &newUseGotoX));
//  Add(new cMenuEditBoolItem(tr("Setup.OSD$Info on channel switch"), &newShowInfo));
}

void cMenuSetupRotor::Store(void)
{
  if (data.DvbCard!=newDvbCard-1)
  {
    static char buffer[PATH_MAX];
    snprintf(buffer, sizeof(buffer), "%s%d/%s%d", "/dev/dvb/adapter",newDvbCard-1,"frontend",0);
    close(data.fd_frontend);
    data.fd_frontend = open(buffer,0);
  }
  SetupStore("DVB-Karte", data.DvbCard=newDvbCard-1);
//  SetupStore("AdressByte", data.AByte=newAByte+18);
  SetupStore("Wiederholen", data.repeat=newrepeat);
  SetupStore("Latitude", data.Lat=newLat);
  SetupStore("SouthNorth", data.SN=newSN);
  SetupStore("Longitude", data.Long=newLong);
  SetupStore("EastWest", data.EW=newEW);
  SetupStore("SLOF",data.SLOF=newSLOF);
  SetupStore("FrequLo",data.FrequLo=newFrequLo);
  SetupStore("FrequHi",data.FrequHi=newFrequHi);
  SetupStore("UseGotoX",data.UseGotoX=newUseGotoX);
  SetupStore("ShowInfo",data.ShowInfo=newShowInfo);
}

cMainMenuRotor::cMainMenuRotor(void):cOsdMenu("Rotor-Plugin"), cThread("Rotor-Plugin")
{
  edw=cSkinDisplay::Current()->EditableWidth();
  oldupdate=Setup.UpdateChannels;
  Setup.UpdateChannels=0;
  SetHelp(tr("Store"),tr("Goto"),tr("Recalc"),tr("Limits off"));
  OldChannel=Channels.GetByNumber(cDevice::GetDevice(data.DvbCard)->CurrentChannel());
  HasSwitched=false;
  Nr=List.GetfromSource(OldChannel->Source());
  Position=List.Pos(Nr);
  Frequenz=(*OldChannel).Frequency();
  if ((*OldChannel).Polarization() == 'v' || (*OldChannel).Polarization() == 'V')
    Pol='V';
  else
    Pol='H';
  Symbolrate=(*OldChannel).Srate();
  m_Active = false;

  enum { NUMCHARS = cFont::NUMCHARS } ;
  const cFont::tCharData *data;
  
    
  for (int i = 32, n=0; i < NUMCHARS; i++) {
    data = cFont::GetFont(fontSml)->CharData(i);
    CharData[n++]=data->width;
    CharData[n++]=data->height;
    for (ulong j=0; j<data->height; j++) {
      CharData[n++]=data->lines[j];
    }
  }
  CharData[(127-32)*(cFont::GetFont(fontSml)->Height()+2)]=1;
  CharData[(128-32)*(cFont::GetFont(fontSml)->Height()+2)]=1;
  for (int i=6; i<=cFont::GetFont(fontSml)->Height()-3 ;i++)
    CharData[(128-32)*(cFont::GetFont(fontSml)->Height()+2)+i]=0x00000001;
  cFont::SetFont(fontSml, CharData);
  cFont::SetFont(fontOsd, CharData);
  
  cOsdItem* n[5];
  for (int i=0; i<5; i++)
  {
    n[i]=new cOsdItem("");
    n[i]->SetSelectable(false);
  }
  Add(n[0]);
  Add(n[1]);
  Add(n[2]);
  Add(new cMenuEditEWItem(ThreeItems(tr("Drive East"),tr("Halt"),tr("Drive West"),edw)));
  Add(new cMenuEditStepsEWItem());
  Add(new cMenuEditLimitsItem(ThreeItems(tr("Set East Limit"),tr("Enable Limits"),tr("Set West Limit"),edw)));
  Add(n[3]);
  Add(new cMenuEditSatItem(Nr,Position));
  Add(n[4]);
  Add(new cMenuEditFreqItem(tr("Frequency"),&Frequenz,&Pol,osUser1));
  Add(new cMenuEditSymbItem(tr("Symbolrate"),&Symbolrate,0,50000,osUser1));
  Add(new cOsdItem(CenterText(tr("Scan Transponder"),edw),osUser2));
  CursorDown();
  Start();
}

cMainMenuRotor::~cMainMenuRotor()
{
  Setup.UpdateChannels=oldupdate;
  if (HasSwitched)
    cDevice::GetDevice(data.DvbCard)->SwitchChannel(OldChannel,true);

  cFont::SetFont(fontSml);
  cFont::SetFont(fontOsd);


  if (m_Active)
  {
    m_Active = false;
    Cancel(3);
  }
}

void cMainMenuRotor::Action(void)
{
  unsigned int SNRChip=0,SSChip=0,i;
  char buf[700];
  m_Active = true;
  while (m_Active)
  {
    CHECK(ioctl(Fd_Frontend, FE_READ_SNR, &SNRChip));
    usleep(15);
    for (i=0; i<=(SNRChip*(edw-Width("SNR:  99% = -99.9dB"))/65536);i++) 
      buf[i]='\x80';
    buf[i]='\0';
    sprintf(SNR,"SNR:\t%s\t%d%% = %.1fdB",buf,SNRChip/655,SNRChip>57000 ? (logf((double)SNRChip/6553.5)*10.0):(-3/(logf(SNRChip/65535.0))));
    CHECK(ioctl(Fd_Frontend, FE_READ_SIGNAL_STRENGTH, &SSChip));
    usleep(15);
    for (i=0; i<=(SSChip*(edw-Width("SNR:  99% = -99.9dB"))/65535);i++)
      buf[i]='\x80';
    buf[i]='\0';
    sprintf(SS,"SS:\t%s\t%d%% = %.1fdB",buf,SSChip/655,(logf((double)SSChip/65535)*10.8));
    DisplayMenu()->SetTabs((Width("SNR: ")+6)/12,(edw-Width("99% = -99.9dB"))/12-Width("SNR: ")/12,0,0);
    DisplayMenu()->SetItem(SNR,0,false,false);
    DisplayMenu()->SetItem(SS,1,false,false);
    usleep(500000);
  }
}

bool cMainMenuRotor::Signal(int Frequenz, char Pol, int Symbolrate)
{
  dvb_frontend_parameters Frontend;
  memset(&Frontend, 0, sizeof(Frontend));
  if (Frequenz < data.SLOF)
  {
    Frontend.frequency=abs(Frequenz-data.FrequLo) * 1000UL;
    CHECK(ioctl(Fd_Frontend, FE_SET_TONE, SEC_TONE_OFF));
  }
  else
  {
    Frontend.frequency=abs(Frequenz-data.FrequHi) * 1000UL;
    CHECK(ioctl(Fd_Frontend, FE_SET_TONE, SEC_TONE_ON));
  }
  if (Pol=='H')
  {
    CHECK(ioctl(Fd_Frontend,FE_SET_VOLTAGE,SEC_VOLTAGE_18));
  }
  else
    CHECK(ioctl(Fd_Frontend,FE_SET_VOLTAGE,SEC_VOLTAGE_13));
  Frontend.inversion=INVERSION_AUTO;
  Frontend.u.qpsk.symbol_rate=Symbolrate * 1000UL;
  Frontend.u.qpsk.fec_inner=FEC_AUTO;
  CHECK(ioctl(Fd_Frontend,FE_SET_FRONTEND,&Frontend));
  fe_status_t  status = fe_status_t(0);
  usleep(15);
  CHECK(ioctl(Fd_Frontend,FE_READ_STATUS, &status));
  if (status & FE_HAS_SYNC)
    return true;
  else
    return false;
}

eOSState cMainMenuRotor::ProcessKey(eKeys Key)
{
  eOSState state = cOsdMenu::ProcessKey(Key);
  if (state == osUser1)
  {
    Setup.UpdateChannels=0;
    Signal(Frequenz,Pol,Symbolrate);
  }
  if (state == osUser2)
  {
    Setup.UpdateChannels=4;
    cChannel *SChannel= new cChannel;
    int tmp[1]={0};
    char tmp2[][MAXLANGCODE2]={""};
    SChannel->SetPids(OldChannel->Vpid(),OldChannel->Ppid(),tmp,tmp2,tmp,tmp2,OldChannel->Tpid());
    SChannel->cChannel::SetSatTransponderData(List.Code(Nr),Frequenz,Pol,Symbolrate,FEC_AUTO);
    if (cDevice::GetDevice(data.DvbCard)==cDevice::ActualDevice())
      HasSwitched=true;
    data.ActualSource=List.Code(Nr);
    cDevice::GetDevice(data.DvbCard)->SwitchChannel(SChannel,HasSwitched);
  }
  if (state == osUnknown)
  {
    Key = NORMALKEY(Key);
    switch (Key) {
      case kRed   :
                    if (Interface->Confirm(tr("Are you sure?"),10))
                      DiseqcCommand(Store,List.Pos(Nr));
                    break;
      case kGreen : Setup.UpdateChannels=0;
                    DiseqcCommand(Goto,List.Pos(Nr));
                    break;
      case kYellow:
                    if (Interface->Confirm(tr("Are you sure?")))
                      DiseqcCommand(Recalc,List.Pos(Nr));
                    break;
      case kBlue  :
                    if (Interface->Confirm(tr("Are you sure?")))
                      DiseqcCommand(LimitsOff);
                    break;
      default     : return state;
                 }
    state=osContinue;
  }
  return state;
}

config data;
