vdr
1.7.27
|
00001 /* 00002 * diseqc.c: DiSEqC handling 00003 * 00004 * See the main source file 'vdr.c' for copyright information and 00005 * how to reach the author. 00006 * 00007 * $Id: diseqc.c 2.9 2011/09/17 14:13:31 kls Exp $ 00008 */ 00009 00010 #include "diseqc.h" 00011 #include <ctype.h> 00012 #include "sources.h" 00013 #include "thread.h" 00014 00015 static bool ParseDeviceNumbers(const char *s, int &Devices) 00016 { 00017 if (*s && s[strlen(s) - 1] == ':') { 00018 const char *p = s; 00019 while (*p && *p != ':') { 00020 char *t = NULL; 00021 int d = strtol(p, &t, 10); 00022 p = t; 00023 if (0 < d && d < 31) 00024 Devices |= (1 << d - 1); 00025 else { 00026 esyslog("ERROR: invalid device number %d in '%s'", d, s); 00027 return false; 00028 } 00029 } 00030 } 00031 return true; 00032 } 00033 00034 // --- cScr ------------------------------------------------------------------ 00035 00036 cScr::cScr(void) 00037 { 00038 devices = 0; 00039 channel = -1; 00040 userBand = 0; 00041 pin = -1; 00042 used = false; 00043 } 00044 00045 bool cScr::Parse(const char *s) 00046 { 00047 if (!ParseDeviceNumbers(s, devices)) 00048 return false; 00049 if (devices) 00050 return true; 00051 bool result = false; 00052 int fields = sscanf(s, "%d %u %d", &channel, &userBand, &pin); 00053 if (fields == 2 || fields == 3) { 00054 if (channel >= 0 && channel < 8) { 00055 result = true; 00056 if (fields == 3 && (pin < 0 || pin > 255)) { 00057 esyslog("Error: invalid SCR pin '%d'", pin); 00058 result = false; 00059 } 00060 } 00061 else 00062 esyslog("Error: invalid SCR channel '%d'", channel); 00063 } 00064 return result; 00065 } 00066 00067 // --- cScrs ----------------------------------------------------------------- 00068 00069 cScrs Scrs; 00070 00071 cScr *cScrs::GetUnused(int Device) 00072 { 00073 cMutexLock MutexLock(&mutex); 00074 int Devices = 0; 00075 for (cScr *p = First(); p; p = Next(p)) { 00076 if (p->Devices()) { 00077 Devices = p->Devices(); 00078 continue; 00079 } 00080 if (Devices && !(Devices & (1 << Device - 1))) 00081 continue; 00082 if (!p->Used()) { 00083 p->SetUsed(true); 00084 return p; 00085 } 00086 } 00087 return NULL; 00088 } 00089 00090 // --- cDiseqc --------------------------------------------------------------- 00091 00092 cDiseqc::cDiseqc(void) 00093 { 00094 devices = 0; 00095 source = 0; 00096 slof = 0; 00097 polarization = 0; 00098 lof = 0; 00099 scrBank = -1; 00100 commands = NULL; 00101 parsing = false; 00102 } 00103 00104 cDiseqc::~cDiseqc() 00105 { 00106 free(commands); 00107 } 00108 00109 bool cDiseqc::Parse(const char *s) 00110 { 00111 if (!ParseDeviceNumbers(s, devices)) 00112 return false; 00113 if (devices) 00114 return true; 00115 bool result = false; 00116 char *sourcebuf = NULL; 00117 int fields = sscanf(s, "%a[^ ] %d %c %d %a[^\n]", &sourcebuf, &slof, &polarization, &lof, &commands); 00118 if (fields == 4) 00119 commands = NULL; //XXX Apparently sscanf() doesn't work correctly if the last %a argument results in an empty string 00120 if (4 <= fields && fields <= 5) { 00121 source = cSource::FromString(sourcebuf); 00122 if (Sources.Get(source)) { 00123 polarization = char(toupper(polarization)); 00124 if (polarization == 'V' || polarization == 'H' || polarization == 'L' || polarization == 'R') { 00125 parsing = true; 00126 const char *CurrentAction = NULL; 00127 while (Execute(&CurrentAction, NULL, NULL, NULL, NULL) != daNone) 00128 ; 00129 parsing = false; 00130 result = !commands || !*CurrentAction; 00131 } 00132 else 00133 esyslog("ERROR: unknown polarization '%c'", polarization); 00134 } 00135 else 00136 esyslog("ERROR: unknown source '%s'", sourcebuf); 00137 } 00138 free(sourcebuf); 00139 return result; 00140 } 00141 00142 uint cDiseqc::SetScrFrequency(uint SatFrequency, const cScr *Scr, uint8_t *Codes) const 00143 { 00144 uint t = SatFrequency == 0 ? 0 : (SatFrequency + Scr->UserBand() + 2) / 4 - 350; // '+ 2' together with '/ 4' results in rounding! 00145 if (t < 1024 && Scr->Channel() >= 0 && Scr->Channel() < 8) { 00146 Codes[3] = t >> 8 | (t == 0 ? 0 : scrBank << 2) | Scr->Channel() << 5; 00147 Codes[4] = t; 00148 if (t) 00149 return (t + 350) * 4 - SatFrequency; 00150 } 00151 return 0; 00152 } 00153 00154 int cDiseqc::SetScrPin(const cScr *Scr, uint8_t *Codes) const 00155 { 00156 if (Scr->Pin() >= 0 && Scr->Pin() <= 255) { 00157 Codes[2] = 0x5C; 00158 Codes[5] = Scr->Pin(); 00159 return 6; 00160 } 00161 else { 00162 Codes[2] = 0x5A; 00163 return 5; 00164 } 00165 } 00166 00167 const char *cDiseqc::Wait(const char *s) const 00168 { 00169 char *p = NULL; 00170 errno = 0; 00171 int n = strtol(s, &p, 10); 00172 if (!errno && p != s && n >= 0) { 00173 if (!parsing) 00174 cCondWait::SleepMs(n); 00175 return p; 00176 } 00177 esyslog("ERROR: invalid value for wait time in '%s'", s - 1); 00178 return NULL; 00179 } 00180 00181 const char *cDiseqc::GetScrBank(const char *s) const 00182 { 00183 char *p = NULL; 00184 errno = 0; 00185 int n = strtol(s, &p, 10); 00186 if (!errno && p != s && n >= 0 && n < 8) { 00187 if (parsing) { 00188 if (scrBank < 0) 00189 scrBank = n; 00190 else 00191 esyslog("ERROR: more than one scr bank in '%s'", s - 1); 00192 } 00193 return p; 00194 } 00195 esyslog("ERROR: more than one scr bank in '%s'", s - 1); 00196 return NULL; 00197 } 00198 00199 const char *cDiseqc::GetCodes(const char *s, uchar *Codes, uint8_t *MaxCodes) const 00200 { 00201 const char *e = strchr(s, ']'); 00202 if (e) { 00203 int NumCodes = 0; 00204 const char *t = s; 00205 while (t < e) { 00206 if (NumCodes < MaxDiseqcCodes) { 00207 errno = 0; 00208 char *p; 00209 int n = strtol(t, &p, 16); 00210 if (!errno && p != t && 0 <= n && n <= 255) { 00211 if (Codes) { 00212 if (NumCodes < *MaxCodes) 00213 Codes[NumCodes++] = uchar(n); 00214 else { 00215 esyslog("ERROR: too many codes in code sequence '%s'", s - 1); 00216 return NULL; 00217 } 00218 } 00219 t = skipspace(p); 00220 } 00221 else { 00222 esyslog("ERROR: invalid code at '%s'", t); 00223 return NULL; 00224 } 00225 } 00226 else { 00227 esyslog("ERROR: too many codes in code sequence '%s'", s - 1); 00228 return NULL; 00229 } 00230 } 00231 if (MaxCodes) 00232 *MaxCodes = NumCodes; 00233 return e + 1; 00234 } 00235 else 00236 esyslog("ERROR: missing closing ']' in code sequence '%s'", s - 1); 00237 return NULL; 00238 } 00239 00240 cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const 00241 { 00242 if (!*CurrentAction) 00243 *CurrentAction = commands; 00244 while (*CurrentAction && **CurrentAction) { 00245 switch (*(*CurrentAction)++) { 00246 case ' ': break; 00247 case 't': return daToneOff; 00248 case 'T': return daToneOn; 00249 case 'v': return daVoltage13; 00250 case 'V': return daVoltage18; 00251 case 'A': return daMiniA; 00252 case 'B': return daMiniB; 00253 case 'W': *CurrentAction = Wait(*CurrentAction); break; 00254 case 'S': *CurrentAction = GetScrBank(*CurrentAction); break; 00255 case '[': *CurrentAction = GetCodes(*CurrentAction, Codes, MaxCodes); 00256 if (*CurrentAction) { 00257 if (Scr && Frequency) { 00258 *Frequency = SetScrFrequency(*Frequency, Scr, Codes); 00259 *MaxCodes = SetScrPin(Scr, Codes); 00260 } 00261 return daCodes; 00262 } 00263 break; 00264 default: return daNone; 00265 } 00266 } 00267 return daNone; 00268 } 00269 00270 // --- cDiseqcs -------------------------------------------------------------- 00271 00272 cDiseqcs Diseqcs; 00273 00274 const cDiseqc *cDiseqcs::Get(int Device, int Source, int Frequency, char Polarization, const cScr **Scr) const 00275 { 00276 int Devices = 0; 00277 for (const cDiseqc *p = First(); p; p = Next(p)) { 00278 if (p->Devices()) { 00279 Devices = p->Devices(); 00280 continue; 00281 } 00282 if (Devices && !(Devices & (1 << Device - 1))) 00283 continue; 00284 if (p->Source() == Source && p->Slof() > Frequency && p->Polarization() == toupper(Polarization)) { 00285 if (p->IsScr() && Scr && !*Scr) { 00286 *Scr = Scrs.GetUnused(Device); 00287 if (*Scr) 00288 dsyslog("SCR %d assigned to device %d", (*Scr)->Channel(), Device); 00289 else 00290 esyslog("ERROR: no free SCR entry available for device %d", Device); 00291 } 00292 return p; 00293 } 00294 } 00295 return NULL; 00296 }