diff -rup a/config.c b/config.c --- a/config.c 2010-06-06 12:06:43.000000000 +0200 +++ b/config.c 2011-01-28 14:44:30.888676207 +0100 @@ -326,6 +326,12 @@ cSetup::cSetup(void) LnbFrequLo = 9750; LnbFrequHi = 10600; DiSEqC = 0; + UseGotox = 0; + GotoxSpeed = 100; + GotoxRepeat = 0; + GotoxSN = 0; GotoxLat = 613; GotoxEW = 1; GotoxLong = 236; // Somewhere at Tampere, Finland :^) + GotoxMaxSwing = 60; + GotoxPrevSource = 0; SetSystemTime = 0; TimeSource = 0; TimeTransponder = 0; @@ -517,6 +523,15 @@ bool cSetup::Parse(const char *Name, con else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value); else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value); else if (!strcasecmp(Name, "DiSEqC")) DiSEqC = atoi(Value); + else if (!strcasecmp(Name, "UseGotox")) UseGotox = atoi(Value); + else if (!strcasecmp(Name, "GotoxSpeed")) GotoxSpeed = atoi(Value); + else if (!strcasecmp(Name, "GotoxRepeat")) GotoxRepeat = atoi(Value); + else if (!strcasecmp(Name, "GotoxSN")) GotoxSN = atoi(Value); + else if (!strcasecmp(Name, "GotoxLat")) GotoxLat = atoi(Value); + else if (!strcasecmp(Name, "GotoxEW")) GotoxEW = atoi(Value); + else if (!strcasecmp(Name, "GotoxLong")) GotoxLong = atoi(Value); + else if (!strcasecmp(Name, "GotoxMaxSwing")) GotoxMaxSwing = atoi(Value); + else if (!strcasecmp(Name, "GotoxPrevSource")) GotoxPrevSource = atoi(Value); else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); else if (!strcasecmp(Name, "TimeSource")) TimeSource = cSource::FromString(Value); else if (!strcasecmp(Name, "TimeTransponder")) TimeTransponder = atoi(Value); @@ -613,6 +628,15 @@ bool cSetup::Save(void) Store("LnbFrequLo", LnbFrequLo); Store("LnbFrequHi", LnbFrequHi); Store("DiSEqC", DiSEqC); + Store("UseGotox", UseGotox); + Store("GotoxSpeed", GotoxSpeed); + Store("GotoxRepeat", GotoxRepeat); + Store("GotoxSN", GotoxSN); + Store("GotoxLat", GotoxLat); + Store("GotoxEW", GotoxEW); + Store("GotoxLong", GotoxLong); + Store("GotoxMaxSwing", GotoxMaxSwing); + Store("GotoxPrevSource", GotoxPrevSource); Store("SetSystemTime", SetSystemTime); Store("TimeSource", cSource::ToString(TimeSource)); Store("TimeTransponder", TimeTransponder); diff -rup a/config.h b/config.h --- a/config.h 2010-09-12 13:31:21.000000000 +0200 +++ b/config.h 2011-01-28 14:45:10.882778898 +0100 @@ -229,6 +229,15 @@ public: int LnbFrequLo; int LnbFrequHi; int DiSEqC; + int GotoxRepeat; + int GotoxSN; + int GotoxEW; + int GotoxSpeed; + int GotoxLat; + int GotoxLong; + int GotoxMaxSwing; + int UseGotox; + int GotoxPrevSource; int SetSystemTime; int TimeSource; int TimeTransponder; diff -rup a/diseqc.c b/diseqc.c --- a/diseqc.c 2010-02-06 16:43:31.000000000 +0100 +++ b/diseqc.c 2011-01-28 14:46:03.418659831 +0100 @@ -134,6 +134,7 @@ cDiseqc::eDiseqcActions cDiseqc::Execute case 'V': return daVoltage18; case 'A': return daMiniA; case 'B': return daMiniB; + case 'G': return daGotoX; case 'W': *CurrentAction = Wait(*CurrentAction); break; case '[': *CurrentAction = Codes(*CurrentAction); return *CurrentAction ? daCodes : daNone; default: return daNone; diff -rup a/diseqc.h b/diseqc.h --- a/diseqc.h 2010-02-06 16:14:42.000000000 +0100 +++ b/diseqc.h 2011-01-28 14:46:10.495659376 +0100 @@ -22,6 +22,7 @@ public: daVoltage18, daMiniA, daMiniB, + daGotoX, daCodes, }; enum { MaxDiseqcCodes = 6 }; diff -rup a/dvbdevice.c b/dvbdevice.c --- a/dvbdevice.c 2010-05-01 11:47:13.000000000 +0200 +++ b/dvbdevice.c 2011-01-28 14:47:30.655659479 +0100 @@ -15,9 +15,11 @@ #include #include #include +#include #include "channels.h" #include "diseqc.h" #include "dvbci.h" +#include "skins.h" #include "menuitems.h" #include "sourceparams.h" @@ -265,6 +267,7 @@ private: fe_delivery_system frontendType; cChannel channel; const char *diseqcCommands; + int lastSource; eTunerStatus tunerStatus; cMutex mutex; cCondVar locked; @@ -292,6 +295,7 @@ cDvbTuner::cDvbTuner(int Device, int Fd_ lockTimeout = 0; lastTimeoutReport = 0; diseqcCommands = NULL; + lastSource = 0; tunerStatus = tsIdle; if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power @@ -365,6 +369,99 @@ static unsigned int FrequencyToHz(unsign return f; } +void HandleGotox(int fd_frontend, int new_source) +{ + + int gotoXTable[10] = { 0x00, 0x02, 0x03, 0x05, 0x06, 0x08, 0x0A, 0x0B, 0x0D, 0x0E }; + int satlong; + int satprev; + float waitseconds = 0; + float waitmaximum = 60; + + if (Setup.UseGotox == 0) + return; + + // Check if zapped into new source position? + if (new_source != Setup.GotoxPrevSource) { + if ((new_source & 0xFF000000) != 0x53000000) + return; // Fail, not S type source + satlong = (new_source & 0x00000FFFF); + satprev = (Setup.GotoxPrevSource & 0x0000FFFF); + if (new_source & 0x00008000) { + satlong ^= 0x0000FFFF; satlong++; satlong *= (-1); + } + if (Setup.GotoxPrevSource & 0x00008000) { + satprev ^= 0x0000FFFF; satprev++; satprev *= (-1); + } + if (Setup.GotoxSpeed > 0) { + waitseconds = fabs(satlong-satprev)/(float)(Setup.GotoxSpeed); + waitmaximum = 10*(float)(Setup.GotoxMaxSwing)/(float)(Setup.GotoxSpeed); + if (waitseconds < 0.0) waitseconds = 0.0; // Should not happen but ... + if (waitseconds > waitmaximum) waitseconds = 2 + waitmaximum; // Limit wait time to +2s over dish max. move + } + int Long=Setup.GotoxEW ? -Setup.GotoxLong : Setup.GotoxLong; + int Lat=Setup.GotoxSN ? -Setup.GotoxLat : Setup.GotoxLat; + double azimuth=M_PI+atan(tan((satlong-Long)*M_PI/1800)/sin(Lat*M_PI/1800)); + double x=acos(cos((satlong-Long)*M_PI/1800)*cos(Lat*M_PI/1800)); + double elevation=atan((cos(x)-0.1513)/sin(x)); + double SatHourangle=180+atan((-cos(elevation)*sin(azimuth))/(sin(elevation)*cos(Lat*M_PI/1800) + -cos(elevation)*sin(Lat*M_PI/1800)*cos(azimuth)))*180/M_PI; + int tmp=(int)(fabs(180-SatHourangle)*10); + tmp=(tmp/10)*0x10 + gotoXTable[ tmp % 10 ]; + int p2=(tmp%0x0100); + int p1=(tmp/0x0100); + if (SatHourangle < 180) + p1 |= 0xe0; + else + p1 |= 0xd0; + + dsyslog("DiSEqC GotoX %d (%d) -> %d (%d), wait time %4.1fs", + satprev, Setup.GotoxPrevSource, satlong, new_source, waitseconds); + +#if 1 + // Set high LNB voltage and tone off, then wait > 15ms + CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); + CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); + usleep(20000); + + // Send 1st GotoX command, then wait > 15ms + uchar gotox_bytes[5] = { 0xe0, 0x31, 0x6e, p1, p2}; + struct dvb_diseqc_master_cmd gotox_cmd; + memcpy(gotox_cmd.msg, gotox_bytes, 5); + gotox_cmd.msg_len = 5; + CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &gotox_cmd)); + usleep(20000); + + // Send repeated GotoX command, then wait > 15ms + if (Setup.GotoxRepeat) { + gotox_bytes[0] = 0xe1; + memcpy(gotox_cmd.msg, gotox_bytes, 5); + CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &gotox_cmd)); + usleep(20000); + } + + { + char mess_move[60]; + snprintf(mess_move,sizeof(mess_move),"Moving dish to %d.%d%s - %ds", \ + (new_source & 0x0800)?-satlong/10:satlong/10, \ + (new_source & 0x0800)?-satlong%10:satlong%10, \ + (new_source & 0x0800)?"E":"W", (int)waitseconds); + // Wait for dish movement and display message approx. for that time + Skins.QueueMessage(mtWarning, mess_move, int(1 + waitseconds - Setup.ChannelInfoTime), 0); + while (waitseconds > 0.0) { + usleep(100000); // 100ms + waitseconds = waitseconds - 100e-3; + } + } + +#endif + + Setup.GotoxPrevSource = new_source; + dsyslog("DiSEqC GotoX done."); + } +} + + bool cDvbTuner::SetFrontend(void) { #define MAXFRONTENDCMDS 16 @@ -394,7 +491,9 @@ bool cDvbTuner::SetFrontend(void) if (Setup.DiSEqC) { cDiseqc *diseqc = Diseqcs.Get(device, channel.Source(), channel.Frequency(), dtp.Polarization()); if (diseqc) { - if (diseqc->Commands() && (!diseqcCommands || strcmp(diseqcCommands, diseqc->Commands()) != 0)) { + if (diseqc->Commands() && (!diseqcCommands || \ + (strcmp(diseqcCommands, diseqc->Commands())) || \ + (strrchr(diseqc->Commands(),'G') && (channel.Source() != lastSource )))) { cDiseqc::eDiseqcActions da; for (char *CurrentAction = NULL; (da = diseqc->Execute(&CurrentAction)) != cDiseqc::daNone; ) { switch (da) { @@ -405,6 +504,7 @@ bool cDvbTuner::SetFrontend(void) case cDiseqc::daVoltage18: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); break; case cDiseqc::daMiniA: CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)); break; case cDiseqc::daMiniB: CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)); break; + case cDiseqc::daGotoX: HandleGotox(fd_frontend, channel.Source()); break; case cDiseqc::daCodes: { int n = 0; uchar *codes = diseqc->Codes(n); @@ -420,6 +520,7 @@ bool cDvbTuner::SetFrontend(void) } } diseqcCommands = diseqc->Commands(); + lastSource = channel.Source(); } frequency -= diseqc->Lof(); } @@ -429,6 +530,10 @@ bool cDvbTuner::SetFrontend(void) } } else { + // Send GotoX DiSEqC command if activated in vdr setup. Then wait with high LNB voltage + // estimated time for dish movement + HandleGotox(fd_frontend, channel.Source()); + int tone = SEC_TONE_OFF; if (frequency < (unsigned int)Setup.LnbSLOF) { frequency -= Setup.LnbFrequLo; @@ -541,6 +646,7 @@ void cDvbTuner::Action(void) if (Timer.TimedOut()) { tunerStatus = tsSet; diseqcCommands = NULL; + lastSource = 0; if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these isyslog("frontend %d/%d timed out while tuning to channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder()); lastTimeoutReport = time(NULL); @@ -551,6 +657,7 @@ void cDvbTuner::Action(void) if (Status & FE_REINIT) { tunerStatus = tsSet; diseqcCommands = NULL; + lastSource = 0; isyslog("frontend %d/%d was reinitialized", adapter, frontend); lastTimeoutReport = 0; continue; diff -rup a/menu.c b/menu.c --- a/menu.c 2010-06-06 11:56:16.000000000 +0200 +++ b/menu.c 2011-01-28 14:50:08.625533824 +0100 @@ -2890,8 +2890,15 @@ void cMenuSetupLNB::Setup(void) Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo)); Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi)); - } - + } + Add(new cMenuEditBoolItem(tr("Setup.LNB$Use GotoX dish positioning"), &data.UseGotox)); + if (data.UseGotox) { + Add(new cMenuEditBoolItem(tr("Setup.LNB$Repeat GotoX commands"), &data.GotoxRepeat)); + Add(new cMenuEditIntpItem(tr("Setup.LNB$Latitude"), &data.GotoxLat,0,900,&data.GotoxSN,tr("North"),tr("South"))); + Add(new cMenuEditIntpItem(tr("Setup.LNB$Longitude"), &data.GotoxLong,0,1800,&data.GotoxEW,tr("West"),tr("East"))); + Add(new cMenuEditIntItem(tr("Setup.LNB$GotoxMaxSwing"), &data.GotoxMaxSwing,0,180)); + Add(new cMenuEditIntdItem(tr("Setup.LNB$Rotor speed (deg/s)"), &data.GotoxSpeed, 1, 100)); + } SetCurrent(Get(current)); Display(); } @@ -2899,10 +2906,15 @@ void cMenuSetupLNB::Setup(void) eOSState cMenuSetupLNB::ProcessKey(eKeys Key) { int oldDiSEqC = data.DiSEqC; + int oldUseGotox = data.UseGotox; eOSState state = cMenuSetupBase::ProcessKey(Key); if (Key != kNone && data.DiSEqC != oldDiSEqC) Setup(); + + if (Key != kNone && data.UseGotox != oldUseGotox) + Setup(); + return state; } diff -rup a/menuitems.c b/menuitems.c --- a/menuitems.c 2010-06-06 12:37:08.000000000 +0200 +++ b/menuitems.c 2011-01-28 14:50:21.357534700 +0100 @@ -1113,3 +1113,121 @@ void cMenuSetupPage::SetupStore(const ch if (plugin) plugin->SetupStore(Name, Value); } + +// cMenuEditIntpItem & cMenuEditIntdItem for GotoX function + +void cMenuEditIntpItem::Set(void) +{ + char buf[16]; + snprintf(buf, sizeof(buf), "%d.%d %s", *value/10, *value % 10, *value2 ? trueString : falseString); + SetValue(buf); +} + +void cMenuEditIntdItem::Set(void) +{ + char buf[16]; + snprintf(buf, sizeof(buf), "%d.%d", *value/10, *value % 10); + SetValue(buf); +} + + +cMenuEditIntpItem::cMenuEditIntpItem(const char *Name, int *Value, int Min, int Max,int *Value2, const char *FalseString,const char *TrueString):cMenuEditIntItem(Name, Value, Min, Max) +{ + value = Value; + value2= Value2; + trueString = TrueString; + falseString = FalseString; + min = Min; + max = Max; + Set(); +} + +cMenuEditIntdItem::cMenuEditIntdItem(const char *Name, int *Value, int Min, int Max):cMenuEditIntItem(Name, Value, Min, Max) +{ + value = Value; + min = Min; + max = Max; + Set(); +} + +eOSState cMenuEditIntpItem::ProcessKey(eKeys Key) +{ + eOSState state = cMenuEditItem::ProcessKey(Key); + if (state == osUnknown) + { + int newValue = *value; + int newValue2= *value2; + Key = NORMALKEY(Key); + switch (Key) { + case kNone : break; + case k0...k9: + if (fresh) + { + *value = 0; + fresh = false; + } + newValue = *value * 10 + (Key - k0); + break; + case kLeft : + newValue2 = 0; + fresh = true; + break; + case kRight : + newValue2 = 1; + fresh = true; + break; + default : + if (*value < min) { *value = min; Set(); } + if (*value > max) { *value = max; Set(); } + return state; + } + if ((!fresh || min <= newValue) && newValue <= max) + { + *value = newValue; + *value2 = newValue2; + Set(); + } + state = osContinue; + } + return state; +} + +eOSState cMenuEditIntdItem::ProcessKey(eKeys Key) +{ + eOSState state = cMenuEditItem::ProcessKey(Key); + if (state == osUnknown) + { + int newValue = *value; + Key = NORMALKEY(Key); + switch (Key) { + case kNone : break; + case k0...k9: + if (fresh) + { + *value = 0; + fresh = false; + } + newValue = *value * 10 + (Key - k0); + break; + case kLeft : + newValue = *value - 1; + fresh = true; + break; + case kRight : + newValue = *value + 1; + fresh = true; + break; + default : + if (*value < min) { *value = min; Set(); } + if (*value > max) { *value = max; Set(); } + return state; + } + if ((!fresh || min <= newValue) && newValue <= max) + { + *value = newValue; + Set(); + } + state = osContinue; + } + return state; +} diff -rup a/menuitems.h b/menuitems.h --- a/menuitems.h 2010-06-06 12:32:38.000000000 +0200 +++ b/menuitems.h 2011-01-28 14:50:36.217533731 +0100 @@ -201,4 +201,22 @@ public: void SetPlugin(cPlugin *Plugin); }; +class cMenuEditIntpItem : public cMenuEditIntItem { +protected: + virtual void Set(void); + const char *falseString, *trueString; + int *value2; +public: + cMenuEditIntpItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX, int *Value2=0, const char *FalseString = "", const char *TrueSting = NULL); + virtual eOSState ProcessKey(eKeys Key); +}; + +class cMenuEditIntdItem : public cMenuEditIntItem { +protected: + virtual void Set(void); +public: + cMenuEditIntdItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX); + virtual eOSState ProcessKey(eKeys Key); +}; + #endif //__MENUITEMS_H