diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/channels.c b/channels.c new file mode 100644 index 0000000..f86f8ef --- /dev/null +++ b/channels.c @@ -0,0 +1,445 @@ +/* + * channels.c: Channel handling + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: channels.c 1.3 2002/10/06 12:41:49 kls Exp $ + */ + +#include "channels.h" +#ifdef NEWSTRUCT +#include <linux/dvb/frontend.h> +#else +#include <ost/frontend.h> +#endif +#include <ctype.h> + +// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' +// format characters in order to allow any number of blanks after a numeric +// value! + +// -- Channel Parameter Maps ------------------------------------------------- + +const tChannelParameterMap InversionValues[] = { + { 0, INVERSION_OFF }, + { 1, INVERSION_ON }, + { 999, INVERSION_AUTO }, + { -1 } + }; + +const tChannelParameterMap BandwidthValues[] = { + { 6, BANDWIDTH_6_MHZ }, + { 7, BANDWIDTH_7_MHZ }, + { 8, BANDWIDTH_8_MHZ }, +#ifdef NEWSTRUCT + { 999, BANDWIDTH_AUTO }, +#endif + { -1 } + }; + +const tChannelParameterMap CoderateValues[] = { + { 0, FEC_NONE }, + { 12, FEC_1_2 }, + { 23, FEC_2_3 }, + { 34, FEC_3_4 }, +#ifdef NEWSTRUCT + { 45, FEC_4_5 }, +#endif + { 56, FEC_5_6 }, +#ifdef NEWSTRUCT + { 67, FEC_6_7 }, +#endif + { 78, FEC_7_8 }, +#ifdef NEWSTRUCT + { 89, FEC_8_9 }, +#endif + { 999, FEC_AUTO }, + { -1 } + }; + +const tChannelParameterMap ModulationValues[] = { + { 0, QPSK }, + { 16, QAM_16 }, + { 32, QAM_32 }, + { 64, QAM_64 }, + { 128, QAM_128 }, + { 256, QAM_256 }, +#ifdef NEWSTRUCT + { 999, QAM_AUTO }, +#endif + { -1 } + }; + +const tChannelParameterMap TransmissionValues[] = { + { 2, TRANSMISSION_MODE_2K }, + { 8, TRANSMISSION_MODE_8K }, +#ifdef NEWSTRUCT + { 999, TRANSMISSION_MODE_AUTO }, +#endif + { -1 } + }; + +const tChannelParameterMap GuardValues[] = { + { 4, GUARD_INTERVAL_1_4 }, + { 8, GUARD_INTERVAL_1_8 }, + { 16, GUARD_INTERVAL_1_16 }, + { 32, GUARD_INTERVAL_1_32 }, +#ifdef NEWSTRUCT + { 999, GUARD_INTERVAL_AUTO }, +#endif + { -1 } + }; + +const tChannelParameterMap HierarchyValues[] = { + { 0, HIERARCHY_NONE }, + { 1, HIERARCHY_1 }, + { 2, HIERARCHY_2 }, + { 4, HIERARCHY_4 }, +#ifdef NEWSTRUCT + { 999, HIERARCHY_AUTO }, +#endif + { -1 } + }; + +int UserIndex(int Value, const tChannelParameterMap *Map) +{ + const tChannelParameterMap *map = Map; + while (map && map->userValue != -1) { + if (map->userValue == Value) + return map - Map; + map++; + } + return -1; +} + +int DriverIndex(int Value, const tChannelParameterMap *Map) +{ + const tChannelParameterMap *map = Map; + while (map && map->userValue != -1) { + if (map->driverValue == Value) + return map - Map; + map++; + } + return -1; +} + +int MapToUser(int Value, const tChannelParameterMap *Map) +{ + int n = DriverIndex(Value, Map); + if (n >= 0) + return Map[n].userValue; + return -1; +} + +int MapToDriver(int Value, const tChannelParameterMap *Map) +{ + int n = UserIndex(Value, Map); + if (n >= 0) + return Map[n].driverValue; + return -1; +} + +// -- cChannel --------------------------------------------------------------- + +char *cChannel::buffer = NULL; + +cChannel::cChannel(void) +{ + *name = 0; + frequency = 0; + source = 0; + srate = 0; + vpid = 0; + apid1 = 0; + apid2 = 0; + dpid1 = 0; + dpid2 = 0; + tpid = 0; + ca = 0; + sid = 0; + groupSep = false; + //XXX + polarization = 'v'; + inversion = INVERSION_AUTO; + bandwidth = BANDWIDTH_8_MHZ; + coderateH = FEC_AUTO;//XXX FEC_2_3 + coderateL = FEC_1_2;//XXX + modulation = QAM_64; + transmission = TRANSMISSION_MODE_2K; + guard = GUARD_INTERVAL_1_32; + hierarchy = HIERARCHY_NONE; +} + +cChannel::cChannel(const cChannel *Channel) +{ + strcpy(name, Channel ? Channel->name : "Pro7"); + frequency = Channel ? Channel->frequency : 12480; + source = Channel ? Channel->source : 0; + srate = Channel ? Channel->srate : 27500; + vpid = Channel ? Channel->vpid : 255; + apid1 = Channel ? Channel->apid1 : 256; + apid2 = Channel ? Channel->apid2 : 0; + dpid1 = Channel ? Channel->dpid1 : 257; + dpid2 = Channel ? Channel->dpid2 : 0; + tpid = Channel ? Channel->tpid : 32; + ca = Channel ? Channel->ca : 0; + sid = Channel ? Channel->sid : 0; + groupSep = Channel ? Channel->groupSep : false; + //XXX + polarization = Channel ? Channel->polarization : 'v'; + inversion = Channel ? Channel->inversion : INVERSION_AUTO; + bandwidth = Channel ? Channel->bandwidth : BANDWIDTH_8_MHZ; + coderateH = Channel ? Channel->coderateH : FEC_AUTO;//XXX FEC_2_3 + coderateL = Channel ? Channel->coderateL : FEC_1_2;//XXX + modulation = Channel ? Channel->modulation : QAM_64; + transmission = Channel ? Channel->transmission : TRANSMISSION_MODE_2K; + guard = Channel ? Channel->guard : GUARD_INTERVAL_1_32; + hierarchy = Channel ? Channel->hierarchy : HIERARCHY_NONE; +} + +static int PrintParameter(char *p, char Name, int Value) +{ + //XXX return Value >= 0 && Value != 999 ? sprintf(p, "%c%d", Name, Value) : 0; + //XXX let's store 999 for the moment, until we generally switch to the NEWSTRUCT + //XXX driver (where the defaults will all be AUTO) + return Value >= 0 && (Value != 999 || (Name != 'I' && Name != 'C')) ? sprintf(p, "%c%d", Name, Value) : 0; +} + +const char *cChannel::ParametersToString(void) +{ + char type = *cSource::ToString(source); +#define ST(s) if (strchr(s, type)) + static char buffer[64]; + char *q = buffer; + *q = 0; + ST(" S ") q += sprintf(q, "%c", polarization); + ST("CST") q += PrintParameter(q, 'I', MapToUser(inversion, InversionValues)); + ST("CST") q += PrintParameter(q, 'C', MapToUser(coderateH, CoderateValues)); + ST(" T") q += PrintParameter(q, 'D', MapToUser(coderateL, CoderateValues)); + ST("C T") q += PrintParameter(q, 'M', MapToUser(modulation, ModulationValues)); + ST(" T") q += PrintParameter(q, 'B', MapToUser(bandwidth, BandwidthValues)); + ST(" T") q += PrintParameter(q, 'T', MapToUser(transmission, TransmissionValues)); + ST(" T") q += PrintParameter(q, 'G', MapToUser(guard, GuardValues)); + ST(" T") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues)); + return buffer; +} + +static const char *ParseParameter(const char *s, int &Value, const tChannelParameterMap *Map) +{ + if (*++s) { + char *p = NULL; + errno = 0; + int n = strtol(s, &p, 10); + if (!errno && p != s) { + //XXX let's tolerate 999 for the moment, until we generally switch to the NEWSTRUCT + //XXX driver (where the defaults will all be AUTO) + //XXX Value = MapToDriver(n, Map); + //XXX if (Value >= 0) + //XXX return p; + int v = MapToDriver(n, Map); + if (v >= 0) { + Value = v; + return p; + } + else if (v == 999) + return p; + } + } + esyslog("ERROR: illegal value for parameter '%c'", *(s - 1)); + return NULL; +} + +bool cChannel::StringToParameters(const char *s) +{ + while (s && *s) { + switch (toupper(*s)) { + case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break; + case 'C': s = ParseParameter(s, coderateH, CoderateValues); break; + case 'D': s = ParseParameter(s, coderateL, CoderateValues); break; + case 'G': s = ParseParameter(s, guard, GuardValues); break; + case 'H': polarization = *s++; break; + case 'I': s = ParseParameter(s, inversion, InversionValues); break; + // 'L' reserved for possible circular polarization + case 'M': s = ParseParameter(s, modulation, ModulationValues); break; + // 'R' reserved for possible circular polarization + case 'T': s = ParseParameter(s, transmission, TransmissionValues); break; + case 'V': polarization = *s++; break; + case 'Y': s = ParseParameter(s, hierarchy, HierarchyValues); break; + default: esyslog("ERROR: unknown parameter key '%c'", *s); + return false; + } + } + return true; +} + +const char *cChannel::ToText(cChannel *Channel) +{ + char buf[MaxChannelName * 2]; + char *s = Channel->name; + if (strchr(s, ':')) { + s = strcpy(buf, s); + strreplace(s, ':', '|'); + } + free(buffer); + if (Channel->groupSep) + asprintf(&buffer, ":%s\n", s); + else { + char apidbuf[32]; + char *q = apidbuf; + q += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1); + if (Channel->apid2) + q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->apid2); + if (Channel->dpid1 || Channel->dpid2) + q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ";%d", Channel->dpid1); + if (Channel->dpid2) + q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->dpid2); + *q = 0; + asprintf(&buffer, "%s:%d:%s:%s:%d:%d:%s:%d:%d:%d\n", s, Channel->frequency, Channel->ParametersToString(), cSource::ToString(Channel->source), Channel->srate, Channel->vpid, apidbuf, Channel->tpid, Channel->ca, Channel->sid); + } + return buffer; +} + +const char *cChannel::ToText(void) +{ + return ToText(this); +} + +bool cChannel::Parse(const char *s) +{ + if (*s == ':') { + if (*++s) { + strn0cpy(name, s, MaxChannelName); + groupSep = true; + number = 0; + } + else + return false; + } + else { + groupSep = false; + char *namebuf = NULL; + char *sourcebuf = NULL; + char *parambuf = NULL; + char *apidbuf = NULL; + int fields = sscanf(s, "%a[^:]:%d :%a[^:]:%a[^:] :%d :%d :%a[^:]:%d :%d :%d ", &namebuf, &frequency, ¶mbuf, &sourcebuf, &srate, &vpid, &apidbuf, &tpid, &ca, &sid); + if (fields >= 9) { + if (fields == 9) { + // allow reading of old format + sid = ca; + ca = tpid; + tpid = 0; + } + apid1 = apid2 = 0; + dpid1 = dpid2 = 0; + bool ok = false; + if (parambuf && sourcebuf && apidbuf) { + ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0; + char *p = strchr(apidbuf, ';'); + if (p) + *p++ = 0; + sscanf(apidbuf, "%d ,%d ", &apid1, &apid2); + if (p) + sscanf(p, "%d ,%d ", &dpid1, &dpid2); + } + strn0cpy(name, namebuf, MaxChannelName); + free(parambuf); + free(sourcebuf); + free(apidbuf); + free(namebuf); + return ok; + } + else + return false; + } + strreplace(name, '|', ':'); + return true; +} + +bool cChannel::Save(FILE *f) +{ + return fprintf(f, ToText()) > 0; +} + +// -- cChannels -------------------------------------------------------------- + +cChannels Channels; + +bool cChannels::Load(const char *FileName, bool AllowComments) +{ + if (cConfig<cChannel>::Load(FileName, AllowComments)) { + ReNumber(); + return true; + } + return false; +} + +int cChannels::GetNextGroup(int Idx) +{ + cChannel *channel = Get(++Idx); + while (channel && !channel->GroupSep()) + channel = Get(++Idx); + return channel ? Idx : -1; +} + +int cChannels::GetPrevGroup(int Idx) +{ + cChannel *channel = Get(--Idx); + while (channel && !channel->GroupSep()) + channel = Get(--Idx); + return channel ? Idx : -1; +} + +int cChannels::GetNextNormal(int Idx) +{ + cChannel *channel = Get(++Idx); + while (channel && channel->GroupSep()) + channel = Get(++Idx); + return channel ? Idx : -1; +} + +void cChannels::ReNumber( void ) +{ + int Number = 0; + cChannel *ch = (cChannel *)First(); + while (ch) { + if (!ch->GroupSep()) + ch->SetNumber(++Number); + ch = (cChannel *)ch->Next(); + } + maxNumber = Number; +} + +cChannel *cChannels::GetByNumber(int Number) +{ + cChannel *channel = (cChannel *)First(); + while (channel) { + if (!channel->GroupSep() && channel->Number() == Number) + return channel; + channel = (cChannel *)channel->Next(); + } + return NULL; +} + +cChannel *cChannels::GetByServiceID(unsigned short ServiceId) +{ + cChannel *channel = (cChannel *)First(); + while (channel) { + if (!channel->GroupSep() && channel->Sid() == ServiceId) + return channel; + channel = (cChannel *)channel->Next(); + } + return NULL; +} + +bool cChannels::SwitchTo(int Number) +{ + cChannel *channel = GetByNumber(Number); + return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true); +} + +const char *cChannels::GetChannelNameByNumber(int Number) +{ + cChannel *channel = GetByNumber(Number); + return channel ? channel->Name() : NULL; +} |