summaryrefslogtreecommitdiff
path: root/diseqc.c
diff options
context:
space:
mode:
Diffstat (limited to 'diseqc.c')
-rw-r--r--diseqc.c182
1 files changed, 156 insertions, 26 deletions
diff --git a/diseqc.c b/diseqc.c
index d446299..54fb720 100644
--- a/diseqc.c
+++ b/diseqc.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: diseqc.c 2.5 2011/08/06 10:32:18 kls Exp $
+ * $Id: diseqc.c 2.9 2011/09/17 14:13:31 kls Exp $
*/
#include "diseqc.h"
@@ -12,6 +12,81 @@
#include "sources.h"
#include "thread.h"
+static bool ParseDeviceNumbers(const char *s, int &Devices)
+{
+ if (*s && s[strlen(s) - 1] == ':') {
+ const char *p = s;
+ while (*p && *p != ':') {
+ char *t = NULL;
+ int d = strtol(p, &t, 10);
+ p = t;
+ if (0 < d && d < 31)
+ Devices |= (1 << d - 1);
+ else {
+ esyslog("ERROR: invalid device number %d in '%s'", d, s);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+// --- cScr ------------------------------------------------------------------
+
+cScr::cScr(void)
+{
+ devices = 0;
+ channel = -1;
+ userBand = 0;
+ pin = -1;
+ used = false;
+}
+
+bool cScr::Parse(const char *s)
+{
+ if (!ParseDeviceNumbers(s, devices))
+ return false;
+ if (devices)
+ return true;
+ bool result = false;
+ int fields = sscanf(s, "%d %u %d", &channel, &userBand, &pin);
+ if (fields == 2 || fields == 3) {
+ if (channel >= 0 && channel < 8) {
+ result = true;
+ if (fields == 3 && (pin < 0 || pin > 255)) {
+ esyslog("Error: invalid SCR pin '%d'", pin);
+ result = false;
+ }
+ }
+ else
+ esyslog("Error: invalid SCR channel '%d'", channel);
+ }
+ return result;
+}
+
+// --- cScrs -----------------------------------------------------------------
+
+cScrs Scrs;
+
+cScr *cScrs::GetUnused(int Device)
+{
+ cMutexLock MutexLock(&mutex);
+ int Devices = 0;
+ for (cScr *p = First(); p; p = Next(p)) {
+ if (p->Devices()) {
+ Devices = p->Devices();
+ continue;
+ }
+ if (Devices && !(Devices & (1 << Device - 1)))
+ continue;
+ if (!p->Used()) {
+ p->SetUsed(true);
+ return p;
+ }
+ }
+ return NULL;
+}
+
// --- cDiseqc ---------------------------------------------------------------
cDiseqc::cDiseqc(void)
@@ -21,9 +96,9 @@ cDiseqc::cDiseqc(void)
slof = 0;
polarization = 0;
lof = 0;
+ scrBank = -1;
commands = NULL;
parsing = false;
- numCodes = 0;
}
cDiseqc::~cDiseqc()
@@ -33,23 +108,12 @@ cDiseqc::~cDiseqc()
bool cDiseqc::Parse(const char *s)
{
+ if (!ParseDeviceNumbers(s, devices))
+ return false;
+ if (devices)
+ return true;
bool result = false;
char *sourcebuf = NULL;
- if (*s && s[strlen(s) - 1] == ':') {
- const char *p = s;
- while (*p && *p != ':') {
- char *t = NULL;
- int d = strtol(p, &t, 10);
- p = t;
- if (0 < d && d < 32)
- devices |= (1 << d - 1);
- else {
- esyslog("ERROR: invalid device number %d in '%s'", d, s);
- return false;
- }
- }
- return true;
- }
int fields = sscanf(s, "%a[^ ] %d %c %d %a[^\n]", &sourcebuf, &slof, &polarization, &lof, &commands);
if (fields == 4)
commands = NULL; //XXX Apparently sscanf() doesn't work correctly if the last %a argument results in an empty string
@@ -60,7 +124,7 @@ bool cDiseqc::Parse(const char *s)
if (polarization == 'V' || polarization == 'H' || polarization == 'L' || polarization == 'R') {
parsing = true;
const char *CurrentAction = NULL;
- while (Execute(&CurrentAction) != daNone)
+ while (Execute(&CurrentAction, NULL, NULL, NULL, NULL) != daNone)
;
parsing = false;
result = !commands || !*CurrentAction;
@@ -75,6 +139,31 @@ bool cDiseqc::Parse(const char *s)
return result;
}
+uint cDiseqc::SetScrFrequency(uint SatFrequency, const cScr *Scr, uint8_t *Codes) const
+{
+ uint t = SatFrequency == 0 ? 0 : (SatFrequency + Scr->UserBand() + 2) / 4 - 350; // '+ 2' together with '/ 4' results in rounding!
+ if (t < 1024 && Scr->Channel() >= 0 && Scr->Channel() < 8) {
+ Codes[3] = t >> 8 | (t == 0 ? 0 : scrBank << 2) | Scr->Channel() << 5;
+ Codes[4] = t;
+ if (t)
+ return (t + 350) * 4 - SatFrequency;
+ }
+ return 0;
+}
+
+int cDiseqc::SetScrPin(const cScr *Scr, uint8_t *Codes) const
+{
+ if (Scr->Pin() >= 0 && Scr->Pin() <= 255) {
+ Codes[2] = 0x5C;
+ Codes[5] = Scr->Pin();
+ return 6;
+ }
+ else {
+ Codes[2] = 0x5A;
+ return 5;
+ }
+}
+
const char *cDiseqc::Wait(const char *s) const
{
char *p = NULL;
@@ -89,7 +178,25 @@ const char *cDiseqc::Wait(const char *s) const
return NULL;
}
-const char *cDiseqc::Codes(const char *s) const
+const char *cDiseqc::GetScrBank(const char *s) const
+{
+ char *p = NULL;
+ errno = 0;
+ int n = strtol(s, &p, 10);
+ if (!errno && p != s && n >= 0 && n < 8) {
+ if (parsing) {
+ if (scrBank < 0)
+ scrBank = n;
+ else
+ esyslog("ERROR: more than one scr bank in '%s'", s - 1);
+ }
+ return p;
+ }
+ esyslog("ERROR: more than one scr bank in '%s'", s - 1);
+ return NULL;
+}
+
+const char *cDiseqc::GetCodes(const char *s, uchar *Codes, uint8_t *MaxCodes) const
{
const char *e = strchr(s, ']');
if (e) {
@@ -101,9 +208,13 @@ const char *cDiseqc::Codes(const char *s) const
char *p;
int n = strtol(t, &p, 16);
if (!errno && p != t && 0 <= n && n <= 255) {
- if (!parsing) {
- codes[NumCodes++] = uchar(n);
- numCodes = NumCodes;
+ if (Codes) {
+ if (NumCodes < *MaxCodes)
+ Codes[NumCodes++] = uchar(n);
+ else {
+ esyslog("ERROR: too many codes in code sequence '%s'", s - 1);
+ return NULL;
+ }
}
t = skipspace(p);
}
@@ -117,6 +228,8 @@ const char *cDiseqc::Codes(const char *s) const
return NULL;
}
}
+ if (MaxCodes)
+ *MaxCodes = NumCodes;
return e + 1;
}
else
@@ -124,7 +237,7 @@ const char *cDiseqc::Codes(const char *s) const
return NULL;
}
-cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction) const
+cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const
{
if (!*CurrentAction)
*CurrentAction = commands;
@@ -138,7 +251,16 @@ cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction) const
case 'A': return daMiniA;
case 'B': return daMiniB;
case 'W': *CurrentAction = Wait(*CurrentAction); break;
- case '[': *CurrentAction = Codes(*CurrentAction); return *CurrentAction ? daCodes : daNone;
+ case 'S': *CurrentAction = GetScrBank(*CurrentAction); break;
+ case '[': *CurrentAction = GetCodes(*CurrentAction, Codes, MaxCodes);
+ if (*CurrentAction) {
+ if (Scr && Frequency) {
+ *Frequency = SetScrFrequency(*Frequency, Scr, Codes);
+ *MaxCodes = SetScrPin(Scr, Codes);
+ }
+ return daCodes;
+ }
+ break;
default: return daNone;
}
}
@@ -149,7 +271,7 @@ cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction) const
cDiseqcs Diseqcs;
-const cDiseqc *cDiseqcs::Get(int Device, int Source, int Frequency, char Polarization) const
+const cDiseqc *cDiseqcs::Get(int Device, int Source, int Frequency, char Polarization, const cScr **Scr) const
{
int Devices = 0;
for (const cDiseqc *p = First(); p; p = Next(p)) {
@@ -159,8 +281,16 @@ const cDiseqc *cDiseqcs::Get(int Device, int Source, int Frequency, char Polariz
}
if (Devices && !(Devices & (1 << Device - 1)))
continue;
- if (p->Source() == Source && p->Slof() > Frequency && p->Polarization() == toupper(Polarization))
+ if (p->Source() == Source && p->Slof() > Frequency && p->Polarization() == toupper(Polarization)) {
+ if (p->IsScr() && Scr && !*Scr) {
+ *Scr = Scrs.GetUnused(Device);
+ if (*Scr)
+ dsyslog("SCR %d assigned to device %d", (*Scr)->Channel(), Device);
+ else
+ esyslog("ERROR: no free SCR entry available for device %d", Device);
+ }
return p;
+ }
}
return NULL;
}