vdr  2.0.5
diseqc.c
Go to the documentation of this file.
1 /*
2  * diseqc.c: DiSEqC handling
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: diseqc.c 2.9.1.1 2013/05/02 09:33:12 kls Exp $
8  */
9 
10 #include "diseqc.h"
11 #include <ctype.h>
12 #include "sources.h"
13 #include "thread.h"
14 
15 static bool ParseDeviceNumbers(const char *s, int &Devices)
16 {
17  if (*s && s[strlen(s) - 1] == ':') {
18  const char *p = s;
19  while (*p && *p != ':') {
20  char *t = NULL;
21  int d = strtol(p, &t, 10);
22  p = t;
23  if (0 < d && d < 31)
24  Devices |= (1 << d - 1);
25  else {
26  esyslog("ERROR: invalid device number %d in '%s'", d, s);
27  return false;
28  }
29  }
30  }
31  return true;
32 }
33 
34 // --- cScr ------------------------------------------------------------------
35 
37 {
38  devices = 0;
39  channel = -1;
40  userBand = 0;
41  pin = -1;
42  used = false;
43 }
44 
45 bool cScr::Parse(const char *s)
46 {
47  if (!ParseDeviceNumbers(s, devices))
48  return false;
49  if (devices)
50  return true;
51  bool result = false;
52  int fields = sscanf(s, "%d %u %d", &channel, &userBand, &pin);
53  if (fields == 2 || fields == 3) {
54  if (channel >= 0 && channel < 8) {
55  result = true;
56  if (fields == 3 && (pin < 0 || pin > 255)) {
57  esyslog("Error: invalid SCR pin '%d'", pin);
58  result = false;
59  }
60  }
61  else
62  esyslog("Error: invalid SCR channel '%d'", channel);
63  }
64  return result;
65 }
66 
67 // --- cScrs -----------------------------------------------------------------
68 
70 
71 cScr *cScrs::GetUnused(int Device)
72 {
73  cMutexLock MutexLock(&mutex);
74  int Devices = 0;
75  for (cScr *p = First(); p; p = Next(p)) {
76  if (p->Devices()) {
77  Devices = p->Devices();
78  continue;
79  }
80  if (Devices && !(Devices & (1 << Device - 1)))
81  continue;
82  if (!p->Used()) {
83  p->SetUsed(true);
84  return p;
85  }
86  }
87  return NULL;
88 }
89 
90 // --- cDiseqc ---------------------------------------------------------------
91 
93 {
94  devices = 0;
95  source = 0;
96  slof = 0;
97  polarization = 0;
98  lof = 0;
99  scrBank = -1;
100  commands = NULL;
101  parsing = false;
102 }
103 
105 {
106  free(commands);
107 }
108 
109 bool cDiseqc::Parse(const char *s)
110 {
111  if (!ParseDeviceNumbers(s, devices))
112  return false;
113  if (devices)
114  return true;
115  bool result = false;
116  char *sourcebuf = NULL;
117  int fields = sscanf(s, "%a[^ ] %d %c %d %a[^\n]", &sourcebuf, &slof, &polarization, &lof, &commands);
118  if (fields == 4)
119  commands = NULL; //XXX Apparently sscanf() doesn't work correctly if the last %a argument results in an empty string
120  if (4 <= fields && fields <= 5) {
121  source = cSource::FromString(sourcebuf);
122  if (Sources.Get(source)) {
123  polarization = char(toupper(polarization));
124  if (polarization == 'V' || polarization == 'H' || polarization == 'L' || polarization == 'R') {
125  parsing = true;
126  const char *CurrentAction = NULL;
127  while (Execute(&CurrentAction, NULL, NULL, NULL, NULL) != daNone)
128  ;
129  parsing = false;
130  result = !commands || !*CurrentAction;
131  }
132  else
133  esyslog("ERROR: unknown polarization '%c'", polarization);
134  }
135  else
136  esyslog("ERROR: unknown source '%s'", sourcebuf);
137  }
138  free(sourcebuf);
139  return result;
140 }
141 
142 uint cDiseqc::SetScrFrequency(uint SatFrequency, const cScr *Scr, uint8_t *Codes) const
143 {
144  uint t = SatFrequency == 0 ? 0 : (SatFrequency + Scr->UserBand() + 2) / 4 - 350; // '+ 2' together with '/ 4' results in rounding!
145  if (t < 1024 && Scr->Channel() >= 0 && Scr->Channel() < 8) {
146  Codes[3] = t >> 8 | (t == 0 ? 0 : scrBank << 2) | Scr->Channel() << 5;
147  Codes[4] = t;
148  if (t)
149  return (t + 350) * 4 - SatFrequency;
150  }
151  return 0;
152 }
153 
154 int cDiseqc::SetScrPin(const cScr *Scr, uint8_t *Codes) const
155 {
156  if (Scr->Pin() >= 0 && Scr->Pin() <= 255) {
157  Codes[2] = 0x5C;
158  Codes[5] = Scr->Pin();
159  return 6;
160  }
161  else {
162  Codes[2] = 0x5A;
163  return 5;
164  }
165 }
166 
167 const char *cDiseqc::Wait(const char *s) const
168 {
169  char *p = NULL;
170  errno = 0;
171  int n = strtol(s, &p, 10);
172  if (!errno && p != s && n >= 0) {
173  if (!parsing)
175  return p;
176  }
177  esyslog("ERROR: invalid value for wait time in '%s'", s - 1);
178  return NULL;
179 }
180 
181 const char *cDiseqc::GetScrBank(const char *s) const
182 {
183  char *p = NULL;
184  errno = 0;
185  int n = strtol(s, &p, 10);
186  if (!errno && p != s && n >= 0 && n < 8) {
187  if (parsing) {
188  if (scrBank < 0)
189  scrBank = n;
190  else
191  esyslog("ERROR: more than one scr bank in '%s'", s - 1);
192  }
193  return p;
194  }
195  esyslog("ERROR: invalid value for scr bank in '%s'", s - 1);
196  return NULL;
197 }
198 
199 const char *cDiseqc::GetCodes(const char *s, uchar *Codes, uint8_t *MaxCodes) const
200 {
201  const char *e = strchr(s, ']');
202  if (e) {
203  int NumCodes = 0;
204  const char *t = s;
205  while (t < e) {
206  if (NumCodes < MaxDiseqcCodes) {
207  errno = 0;
208  char *p;
209  int n = strtol(t, &p, 16);
210  if (!errno && p != t && 0 <= n && n <= 255) {
211  if (Codes) {
212  if (NumCodes < *MaxCodes)
213  Codes[NumCodes++] = uchar(n);
214  else {
215  esyslog("ERROR: too many codes in code sequence '%s'", s - 1);
216  return NULL;
217  }
218  }
219  t = skipspace(p);
220  }
221  else {
222  esyslog("ERROR: invalid code at '%s'", t);
223  return NULL;
224  }
225  }
226  else {
227  esyslog("ERROR: too many codes in code sequence '%s'", s - 1);
228  return NULL;
229  }
230  }
231  if (MaxCodes)
232  *MaxCodes = NumCodes;
233  return e + 1;
234  }
235  else
236  esyslog("ERROR: missing closing ']' in code sequence '%s'", s - 1);
237  return NULL;
238 }
239 
240 cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const
241 {
242  if (!*CurrentAction)
243  *CurrentAction = commands;
244  while (*CurrentAction && **CurrentAction) {
245  switch (*(*CurrentAction)++) {
246  case ' ': break;
247  case 't': return daToneOff;
248  case 'T': return daToneOn;
249  case 'v': return daVoltage13;
250  case 'V': return daVoltage18;
251  case 'A': return daMiniA;
252  case 'B': return daMiniB;
253  case 'W': *CurrentAction = Wait(*CurrentAction); break;
254  case 'S': *CurrentAction = GetScrBank(*CurrentAction); break;
255  case '[': *CurrentAction = GetCodes(*CurrentAction, Codes, MaxCodes);
256  if (*CurrentAction) {
257  if (Scr && Frequency) {
258  *Frequency = SetScrFrequency(*Frequency, Scr, Codes);
259  *MaxCodes = SetScrPin(Scr, Codes);
260  }
261  return daCodes;
262  }
263  break;
264  default: return daNone;
265  }
266  }
267  return daNone;
268 }
269 
270 // --- cDiseqcs --------------------------------------------------------------
271 
273 
274 const cDiseqc *cDiseqcs::Get(int Device, int Source, int Frequency, char Polarization, const cScr **Scr) const
275 {
276  int Devices = 0;
277  for (const cDiseqc *p = First(); p; p = Next(p)) {
278  if (p->Devices()) {
279  Devices = p->Devices();
280  continue;
281  }
282  if (Devices && !(Devices & (1 << Device - 1)))
283  continue;
284  if (p->Source() == Source && p->Slof() > Frequency && p->Polarization() == toupper(Polarization)) {
285  if (p->IsScr() && Scr && !*Scr) {
286  *Scr = Scrs.GetUnused(Device);
287  if (*Scr)
288  dsyslog("SCR %d assigned to device %d", (*Scr)->Channel(), Device);
289  else
290  esyslog("ERROR: no free SCR entry available for device %d", Device);
291  }
292  return p;
293  }
294  }
295  return NULL;
296 }
uint userBand
Definition: diseqc.h:20
cDiseqcs Diseqcs
Definition: diseqc.c:272
unsigned char uchar
Definition: tools.h:30
const char * Wait(const char *s) const
Definition: diseqc.c:167
~cDiseqc()
Definition: diseqc.c:104
bool parsing
Definition: diseqc.h:65
#define dsyslog(a...)
Definition: tools.h:36
uint UserBand(void) const
Definition: diseqc.h:28
bool Parse(const char *s)
Definition: diseqc.c:45
int lof
Definition: diseqc.h:62
int pin
Definition: diseqc.h:21
Definition: diseqc.h:34
#define esyslog(a...)
Definition: tools.h:34
eDiseqcActions Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const
Parses the DiSEqC commands and returns the appropriate action code with every call.
Definition: diseqc.c:240
int devices
Definition: diseqc.h:58
int source
Definition: diseqc.h:59
Definition: diseqc.h:43
int Pin(void) const
Definition: diseqc.h:29
cScr(void)
Definition: diseqc.c:36
cScr * Next(const cScr *object) const
Definition: tools.h:485
uint SetScrFrequency(uint SatFrequency, const cScr *Scr, uint8_t *Codes) const
Definition: diseqc.c:142
int Devices(void) const
Definition: diseqc.h:91
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition: thread.c:57
cSources Sources
Definition: sources.c:105
const char * GetScrBank(const char *s) const
Definition: diseqc.c:181
bool used
Definition: diseqc.h:22
cMutex mutex
Definition: diseqc.h:36
static bool ParseDeviceNumbers(const char *s, int &Devices)
Definition: diseqc.c:15
const char * GetCodes(const char *s, uchar *Codes=NULL, uint8_t *MaxCodes=NULL) const
Definition: diseqc.c:199
cScr * First(void) const
Definition: tools.h:482
int channel
Definition: diseqc.h:19
cScr * GetUnused(int Device)
Definition: diseqc.c:71
static int FromString(const char *s)
Definition: sources.c:56
Definition: diseqc.h:16
cScrs Scrs
Definition: diseqc.c:69
char * skipspace(const char *s)
Definition: tools.h:194
eDiseqcActions
Definition: diseqc.h:45
const cDiseqc * Get(int Device, int Source, int Frequency, char Polarization, const cScr **Scr) const
Selects a DiSEqC entry suitable for the given Device and tuning parameters.
Definition: diseqc.c:274
int SetScrPin(const cScr *Scr, uint8_t *Codes) const
Definition: diseqc.c:154
char polarization
Definition: diseqc.h:61
cSource * Get(int Code)
Definition: sources.c:107
int Channel(void) const
Definition: diseqc.h:27
int devices
Definition: diseqc.h:18
char * commands
Definition: diseqc.h:64
int slof
Definition: diseqc.h:60
cDiseqc(void)
Definition: diseqc.c:92
bool Parse(const char *s)
Definition: diseqc.c:109
int scrBank
Definition: diseqc.h:63