2002-10-06 10:25:42 +02:00
/*
* channels . c : Channel handling
*
* See the main source file ' vdr . c ' for copyright information and
* how to reach the author .
*
2004-12-19 16:33:34 +01:00
* $ Id : channels . c 1.32 2004 / 12 / 19 11 : 24 : 51 kls Exp $
2002-10-06 10:25:42 +02:00
*/
# include "channels.h"
# include <linux/dvb/frontend.h>
# 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 } ,
{ 999 , BANDWIDTH_AUTO } ,
{ - 1 }
} ;
const tChannelParameterMap CoderateValues [ ] = {
{ 0 , FEC_NONE } ,
{ 12 , FEC_1_2 } ,
{ 23 , FEC_2_3 } ,
{ 34 , FEC_3_4 } ,
{ 45 , FEC_4_5 } ,
{ 56 , FEC_5_6 } ,
{ 67 , FEC_6_7 } ,
{ 78 , FEC_7_8 } ,
{ 89 , FEC_8_9 } ,
{ 999 , FEC_AUTO } ,
{ - 1 }
} ;
const tChannelParameterMap ModulationValues [ ] = {
{ 0 , QPSK } ,
{ 16 , QAM_16 } ,
{ 32 , QAM_32 } ,
{ 64 , QAM_64 } ,
{ 128 , QAM_128 } ,
{ 256 , QAM_256 } ,
{ 999 , QAM_AUTO } ,
{ - 1 }
} ;
const tChannelParameterMap TransmissionValues [ ] = {
{ 2 , TRANSMISSION_MODE_2K } ,
{ 8 , TRANSMISSION_MODE_8K } ,
{ 999 , TRANSMISSION_MODE_AUTO } ,
{ - 1 }
} ;
const tChannelParameterMap GuardValues [ ] = {
{ 4 , GUARD_INTERVAL_1_4 } ,
{ 8 , GUARD_INTERVAL_1_8 } ,
{ 16 , GUARD_INTERVAL_1_16 } ,
{ 32 , GUARD_INTERVAL_1_32 } ,
{ 999 , GUARD_INTERVAL_AUTO } ,
{ - 1 }
} ;
const tChannelParameterMap HierarchyValues [ ] = {
{ 0 , HIERARCHY_NONE } ,
{ 1 , HIERARCHY_1 } ,
{ 2 , HIERARCHY_2 } ,
{ 4 , HIERARCHY_4 } ,
{ 999 , HIERARCHY_AUTO } ,
{ - 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 ;
}
2002-11-24 14:48:38 +01:00
// -- tChannelID -------------------------------------------------------------
const tChannelID tChannelID : : InvalidID ;
bool tChannelID : : operator = = ( const tChannelID & arg ) const
{
return source = = arg . source & & nid = = arg . nid & & tid = = arg . tid & & sid = = arg . sid & & rid = = arg . rid ;
}
tChannelID tChannelID : : FromString ( const char * s )
{
char * sourcebuf = NULL ;
int nid ;
int tid ;
int sid ;
int rid = 0 ;
int fields = sscanf ( s , " %a[^-]-%d-%d-%d-%d " , & sourcebuf , & nid , & tid , & sid , & rid ) ;
if ( fields = = 4 | | fields = = 5 ) {
int source = cSource : : FromString ( sourcebuf ) ;
free ( sourcebuf ) ;
if ( source > = 0 )
return tChannelID ( source , nid , tid , sid , rid ) ;
}
return tChannelID : : InvalidID ;
}
const char * tChannelID : : ToString ( void )
{
static char buffer [ 256 ] ;
snprintf ( buffer , sizeof ( buffer ) , rid ? " %s-%d-%d-%d-%d " : " %s-%d-%d-%d " , cSource : : ToString ( source ) , nid , tid , sid , rid ) ;
return buffer ;
}
2004-02-13 15:50:26 +01:00
tChannelID & tChannelID : : ClrPolarization ( void )
{
while ( tid > 100000 )
tid - = 100000 ;
return * this ;
}
2002-10-06 10:25:42 +02:00
// -- cChannel ---------------------------------------------------------------
char * cChannel : : buffer = NULL ;
cChannel : : cChannel ( void )
{
2004-10-31 12:53:00 +01:00
name = strdup ( " " ) ;
shortName = strdup ( " " ) ;
provider = strdup ( " " ) ;
2004-10-31 13:01:35 +01:00
portalName = strdup ( " " ) ;
2004-01-04 12:30:00 +01:00
memset ( & __BeginData__ , 0 , ( char * ) & __EndData__ - ( char * ) & __BeginData__ ) ;
2002-10-06 10:25:42 +02:00
inversion = INVERSION_AUTO ;
2002-11-01 10:26:45 +01:00
bandwidth = BANDWIDTH_AUTO ;
coderateH = FEC_AUTO ;
coderateL = FEC_AUTO ;
modulation = QAM_AUTO ;
transmission = TRANSMISSION_MODE_AUTO ;
guard = GUARD_INTERVAL_AUTO ;
hierarchy = HIERARCHY_AUTO ;
2004-01-04 12:30:00 +01:00
modification = CHANNELMOD_NONE ;
2004-02-08 11:05:22 +01:00
linkChannels = NULL ;
refChannel = NULL ;
2004-01-04 12:30:00 +01:00
}
2004-02-08 11:05:22 +01:00
cChannel : : cChannel ( const cChannel & Channel )
2004-01-04 12:30:00 +01:00
{
2004-10-31 12:53:00 +01:00
name = strdup ( " " ) ;
shortName = strdup ( " " ) ;
provider = strdup ( " " ) ;
2004-10-31 13:01:35 +01:00
portalName = strdup ( " " ) ;
2004-02-08 11:05:22 +01:00
* this = Channel ;
2004-01-04 12:30:00 +01:00
vpid = 0 ;
ppid = 0 ;
2004-01-25 15:32:08 +01:00
apids [ 0 ] = 0 ;
dpids [ 0 ] = 0 ;
2004-01-04 12:30:00 +01:00
tpid = 0 ;
caids [ 0 ] = 0 ;
nid = 0 ;
tid = 0 ;
sid = 0 ;
rid = 0 ;
number = 0 ;
groupSep = false ;
modification = CHANNELMOD_NONE ;
2004-02-08 11:05:22 +01:00
linkChannels = NULL ;
refChannel = NULL ;
}
cChannel : : ~ cChannel ( )
{
delete linkChannels ;
linkChannels = NULL ; // more than one channel can link to this one, so we need the following loop
for ( cChannel * Channel = Channels . First ( ) ; Channel ; Channel = Channels . Next ( Channel ) ) {
if ( Channel - > linkChannels ) {
for ( cLinkChannel * lc = Channel - > linkChannels - > First ( ) ; lc ; lc = Channel - > linkChannels - > Next ( lc ) ) {
if ( lc - > Channel ( ) = = this ) {
Channel - > linkChannels - > Del ( lc ) ;
break ;
}
}
if ( Channel - > linkChannels - > Count ( ) = = 0 ) {
delete Channel - > linkChannels ;
Channel - > linkChannels = NULL ;
}
}
}
2004-10-31 12:53:00 +01:00
free ( name ) ;
free ( shortName ) ;
free ( provider ) ;
2004-10-31 13:01:35 +01:00
free ( portalName ) ;
2002-10-06 10:25:42 +02:00
}
2002-11-10 15:50:21 +01:00
cChannel & cChannel : : operator = ( const cChannel & Channel )
2002-10-06 10:25:42 +02:00
{
2004-10-31 12:53:00 +01:00
name = strcpyrealloc ( name , Channel . name ) ;
shortName = strcpyrealloc ( shortName , Channel . shortName ) ;
provider = strcpyrealloc ( provider , Channel . provider ) ;
2004-10-31 13:01:35 +01:00
portalName = strcpyrealloc ( portalName , Channel . portalName ) ;
2002-11-10 15:50:21 +01:00
memcpy ( & __BeginData__ , & Channel . __BeginData__ , ( char * ) & Channel . __EndData__ - ( char * ) & Channel . __BeginData__ ) ;
return * this ;
}
2004-02-13 15:50:26 +01:00
int cChannel : : Transponder ( int Frequency , char Polarization )
{
// some satellites have transponders at the same frequency, just with different polarization:
switch ( tolower ( Polarization ) ) {
case ' h ' : Frequency + = 100000 ; break ;
case ' v ' : Frequency + = 200000 ; break ;
case ' l ' : Frequency + = 300000 ; break ;
case ' r ' : Frequency + = 400000 ; break ;
}
return Frequency ;
}
2004-01-04 12:30:00 +01:00
int cChannel : : Transponder ( void ) const
2002-11-10 15:50:21 +01:00
{
2004-01-04 12:30:00 +01:00
int tf = frequency ;
while ( tf > 20000 )
tf / = 1000 ;
2004-02-13 15:50:26 +01:00
if ( IsSat ( ) )
tf = Transponder ( tf , polarization ) ;
2004-01-04 12:30:00 +01:00
return tf ;
2002-11-10 15:50:21 +01:00
}
2002-11-24 14:48:38 +01:00
tChannelID cChannel : : GetChannelID ( void ) const
2002-11-10 15:50:21 +01:00
{
2004-01-05 12:55:07 +01:00
return tChannelID ( source , nid , ( nid | | tid ) ? tid : Transponder ( ) , sid , rid ) ;
2004-01-04 12:30:00 +01:00
}
int cChannel : : Modification ( int Mask )
{
int Result = modification & Mask ;
modification = CHANNELMOD_NONE ;
return Result ;
}
2004-10-17 12:22:56 +02:00
bool cChannel : : SetSatTransponderData ( int Source , int Frequency , char Polarization , int Srate , int CoderateH )
2004-01-11 15:54:37 +01:00
{
// Workarounds for broadcaster stupidity:
// Some providers broadcast the transponder frequency of their channels with two different
// values (like 12551 and 12552), so we need to allow for a little tolerance here
if ( abs ( frequency - Frequency ) < = 1 )
Frequency = frequency ;
// Sometimes the transponder frequency is set to 0, which is just wrong
if ( Frequency = = 0 )
return false ;
if ( source ! = Source | | frequency ! = Frequency | | polarization ! = Polarization | | srate ! = Srate | | coderateH ! = CoderateH ) {
2004-10-17 12:22:56 +02:00
if ( Number ( ) ) {
2004-01-11 15:54:37 +01:00
dsyslog ( " changing transponder data of channel %d from %s:%d:%c:%d:%d to %s:%d:%c:%d:%d " , Number ( ) , cSource : : ToString ( source ) , frequency , polarization , srate , coderateH , cSource : : ToString ( Source ) , Frequency , Polarization , Srate , CoderateH ) ;
2004-10-17 12:22:56 +02:00
modification | = CHANNELMOD_TRANSP ;
Channels . SetModified ( ) ;
}
2004-01-11 15:54:37 +01:00
source = Source ;
frequency = Frequency ;
polarization = Polarization ;
srate = Srate ;
coderateH = CoderateH ;
modulation = QPSK ;
}
return true ;
}
2004-10-17 12:22:56 +02:00
bool cChannel : : SetCableTransponderData ( int Source , int Frequency , int Modulation , int Srate , int CoderateH )
2004-01-11 15:54:37 +01:00
{
if ( source ! = Source | | frequency ! = Frequency | | modulation ! = Modulation | | srate ! = Srate | | coderateH ! = CoderateH ) {
2004-10-17 12:22:56 +02:00
if ( Number ( ) ) {
2004-01-11 15:54:37 +01:00
dsyslog ( " changing transponder data of channel %d from %s:%d:%d:%d:%d to %s:%d:%d:%d:%d " , Number ( ) , cSource : : ToString ( source ) , frequency , modulation , srate , coderateH , cSource : : ToString ( Source ) , Frequency , Modulation , Srate , CoderateH ) ;
2004-10-17 12:22:56 +02:00
modification | = CHANNELMOD_TRANSP ;
Channels . SetModified ( ) ;
}
2004-01-11 15:54:37 +01:00
source = Source ;
frequency = Frequency ;
modulation = Modulation ;
srate = Srate ;
coderateH = CoderateH ;
}
return true ;
}
2004-10-17 12:22:56 +02:00
bool cChannel : : SetTerrTransponderData ( int Source , int Frequency , int Bandwidth , int Modulation , int Hierarchy , int CoderateH , int CoderateL , int Guard , int Transmission )
2004-01-11 15:54:37 +01:00
{
if ( source ! = Source | | frequency ! = Frequency | | bandwidth ! = Bandwidth | | modulation ! = Modulation | | hierarchy ! = Hierarchy | | coderateH ! = CoderateH | | coderateL ! = CoderateL | | guard ! = Guard | | transmission ! = Transmission ) {
2004-10-17 12:22:56 +02:00
if ( Number ( ) ) {
2004-01-11 15:54:37 +01:00
dsyslog ( " changing transponder data of channel %d from %s:%d:%d:%d:%d:%d:%d:%d:%d to %s:%d:%d:%d:%d:%d:%d:%d:%d " , Number ( ) , cSource : : ToString ( source ) , frequency , bandwidth , modulation , hierarchy , coderateH , coderateL , guard , transmission , cSource : : ToString ( Source ) , Frequency , Bandwidth , Modulation , Hierarchy , CoderateH , CoderateL , Guard , Transmission ) ;
2004-10-17 12:22:56 +02:00
modification | = CHANNELMOD_TRANSP ;
Channels . SetModified ( ) ;
}
2004-01-11 15:54:37 +01:00
source = Source ;
frequency = Frequency ;
bandwidth = Bandwidth ;
modulation = Modulation ;
hierarchy = Hierarchy ;
coderateH = CoderateH ;
coderateL = CoderateL ;
guard = Guard ;
transmission = Transmission ;
}
return true ;
}
2004-10-17 12:22:56 +02:00
void cChannel : : SetId ( int Nid , int Tid , int Sid , int Rid )
2004-01-04 12:30:00 +01:00
{
if ( nid ! = Nid | | tid ! = Tid | | sid ! = Sid | | rid ! = Rid ) {
2004-10-17 12:22:56 +02:00
if ( Number ( ) ) {
2004-01-04 12:30:00 +01:00
dsyslog ( " changing id of channel %d from %d-%d-%d-%d to %d-%d-%d-%d " , Number ( ) , nid , tid , sid , rid , Nid , Tid , Sid , Rid ) ;
2004-10-17 12:22:56 +02:00
modification | = CHANNELMOD_ID ;
Channels . SetModified ( ) ;
}
2004-01-04 12:30:00 +01:00
nid = Nid ;
tid = Tid ;
sid = Sid ;
rid = Rid ;
}
}
2004-10-31 12:53:00 +01:00
void cChannel : : SetName ( const char * Name , const char * ShortName , const char * Provider )
2004-01-04 12:30:00 +01:00
{
2004-11-02 18:07:05 +01:00
if ( ! isempty ( Name ) ) {
bool nn = strcmp ( name , Name ) ! = 0 ;
bool ns = strcmp ( shortName , ShortName ) ! = 0 ;
bool np = strcmp ( provider , Provider ) ! = 0 ;
if ( nn | | ns | | np ) {
if ( Number ( ) ) {
dsyslog ( " changing name of channel %d from '%s,%s;%s' to '%s,%s;%s' " , Number ( ) , name , shortName , provider , Name , ShortName , Provider ) ;
modification | = CHANNELMOD_NAME ;
Channels . SetModified ( ) ;
}
if ( nn )
name = strcpyrealloc ( name , Name ) ;
if ( ns )
shortName = strcpyrealloc ( shortName , ShortName ) ;
if ( np )
provider = strcpyrealloc ( provider , Provider ) ;
2004-10-17 12:22:56 +02:00
}
2004-01-04 12:30:00 +01:00
}
}
2004-10-31 13:01:35 +01:00
void cChannel : : SetPortalName ( const char * PortalName )
{
if ( ! isempty ( PortalName ) & & strcmp ( portalName , PortalName ) ! = 0 ) {
if ( Number ( ) ) {
dsyslog ( " changing portal name of channel %d from '%s' to '%s' " , Number ( ) , portalName , PortalName ) ;
modification | = CHANNELMOD_NAME ;
Channels . SetModified ( ) ;
}
portalName = strcpyrealloc ( portalName , PortalName ) ;
}
}
2004-01-25 15:32:08 +01:00
static bool IntArraysDiffer ( const int * a , const int * b , const char na [ ] [ 4 ] = NULL , const char nb [ ] [ 4 ] = NULL )
2004-01-04 12:30:00 +01:00
{
2004-01-25 15:32:08 +01:00
int i = 0 ;
while ( a [ i ] & & b [ i ] ) {
if ( a [ i ] ! = b [ i ] | | na & & nb & & strcmp ( na [ i ] , nb [ i ] ) ! = 0 )
return true ;
i + + ;
}
return a [ i ] ! = b [ i ] | | a [ i ] & & na & & nb & & strcmp ( na [ i ] , nb [ i ] ) ! = 0 ;
}
static int IntArrayToString ( char * s , const int * a , int Base = 10 , const char n [ ] [ 4 ] = NULL )
{
char * q = s ;
int i = 0 ;
while ( a [ i ] | | i = = 0 ) {
q + = sprintf ( q , Base = = 16 ? " %s%X " : " %s%d " , i ? " , " : " " , a [ i ] ) ;
2004-01-25 16:10:04 +01:00
if ( a [ i ] & & n & & * n [ i ] )
2004-01-25 15:32:08 +01:00
q + = sprintf ( q , " =%s " , n [ i ] ) ;
2004-01-26 16:28:35 +01:00
if ( ! a [ i ] )
break ;
2004-01-25 15:32:08 +01:00
i + + ;
}
* q = 0 ;
return q - s ;
}
void cChannel : : SetPids ( int Vpid , int Ppid , int * Apids , char ALangs [ ] [ 4 ] , int * Dpids , char DLangs [ ] [ 4 ] , int Tpid )
{
bool modified = vpid ! = Vpid | | ppid ! = Ppid | | tpid ! = Tpid ;
if ( ! modified )
modified = IntArraysDiffer ( apids , Apids , alangs , ALangs ) | | IntArraysDiffer ( dpids , Dpids , dlangs , DLangs ) ;
if ( modified ) {
char OldApidsBuf [ MAXAPIDS * 2 * 10 + 10 ] ; // 2: Apids and Dpids, 10: 5 digits plus delimiting ',' or ';' plus optional '=cod', +10: paranoia
char NewApidsBuf [ MAXAPIDS * 2 * 10 + 10 ] ;
char * q = OldApidsBuf ;
q + = IntArrayToString ( q , apids , 10 , alangs ) ;
if ( dpids [ 0 ] ) {
* q + + = ' ; ' ;
q + = IntArrayToString ( q , dpids , 10 , dlangs ) ;
}
* q = 0 ;
q = NewApidsBuf ;
q + = IntArrayToString ( q , Apids , 10 , ALangs ) ;
if ( Dpids [ 0 ] ) {
* q + + = ' ; ' ;
q + = IntArrayToString ( q , Dpids , 10 , DLangs ) ;
}
* q = 0 ;
dsyslog ( " changing pids of channel %d from %d+%d:%s:%d to %d+%d:%s:%d " , Number ( ) , vpid , ppid , OldApidsBuf , tpid , Vpid , Ppid , NewApidsBuf , Tpid ) ;
2004-01-04 12:30:00 +01:00
vpid = Vpid ;
ppid = Ppid ;
2004-01-25 15:32:08 +01:00
for ( int i = 0 ; i < = MAXAPIDS ; i + + ) { // <= to copy the terminating 0
apids [ i ] = Apids [ i ] ;
strn0cpy ( alangs [ i ] , ALangs [ i ] , 4 ) ;
dpids [ i ] = Dpids [ i ] ;
strn0cpy ( dlangs [ i ] , DLangs [ i ] , 4 ) ;
}
2004-01-04 12:30:00 +01:00
tpid = Tpid ;
modification | = CHANNELMOD_PIDS ;
Channels . SetModified ( ) ;
}
}
void cChannel : : SetCaIds ( const int * CaIds )
{
if ( caids [ 0 ] & & caids [ 0 ] < = 0x00FF )
return ; // special values will not be overwritten
2004-01-25 15:32:08 +01:00
if ( IntArraysDiffer ( caids , CaIds ) ) {
2004-01-04 12:30:00 +01:00
char OldCaIdsBuf [ MAXCAIDS * 5 + 10 ] ; // 5: 4 digits plus delimiting ',', 10: paranoia
char NewCaIdsBuf [ MAXCAIDS * 5 + 10 ] ;
2004-01-25 15:32:08 +01:00
IntArrayToString ( OldCaIdsBuf , caids , 16 ) ;
IntArrayToString ( NewCaIdsBuf , CaIds , 16 ) ;
2004-01-04 12:30:00 +01:00
dsyslog ( " changing caids of channel %d from %s to %s " , Number ( ) , OldCaIdsBuf , NewCaIdsBuf ) ;
2004-01-26 16:28:35 +01:00
for ( int i = 0 ; i < = MAXCAIDS ; i + + ) { // <= to copy the terminating 0
2004-01-25 15:32:08 +01:00
caids [ i ] = CaIds [ i ] ;
2004-01-26 16:28:35 +01:00
if ( ! CaIds [ i ] )
break ;
}
2004-01-04 12:30:00 +01:00
modification | = CHANNELMOD_CA ;
Channels . SetModified ( ) ;
}
}
void cChannel : : SetCaDescriptors ( int Level )
{
if ( Level > 0 ) {
modification | = CHANNELMOD_CA ;
Channels . SetModified ( ) ;
if ( Level > 1 )
dsyslog ( " changing ca descriptors of channel %d " , Number ( ) ) ;
}
2002-10-06 10:25:42 +02:00
}
2004-02-08 11:05:22 +01:00
void cChannel : : SetLinkChannels ( cLinkChannels * LinkChannels )
{
if ( ! linkChannels & & ! LinkChannels )
return ;
if ( linkChannels & & LinkChannels ) {
cLinkChannel * lca = linkChannels - > First ( ) ;
cLinkChannel * lcb = LinkChannels - > First ( ) ;
while ( lca & & lcb ) {
if ( lca - > Channel ( ) ! = lcb - > Channel ( ) ) {
lca = NULL ;
break ;
}
lca = linkChannels - > Next ( lca ) ;
lcb = LinkChannels - > Next ( lcb ) ;
}
if ( ! lca & & ! lcb ) {
delete LinkChannels ;
return ; // linkage has not changed
}
}
char buffer [ ( ( linkChannels ? linkChannels - > Count ( ) : 0 ) + ( LinkChannels ? LinkChannels - > Count ( ) : 0 ) ) * 6 + 256 ] ; // 6: 5 digit channel number plus blank, 256: other texts (see below) plus reserve
char * q = buffer ;
q + = sprintf ( q , " linking channel %d from " , Number ( ) ) ;
if ( linkChannels ) {
for ( cLinkChannel * lc = linkChannels - > First ( ) ; lc ; lc = linkChannels - > Next ( lc ) ) {
lc - > Channel ( ) - > SetRefChannel ( NULL ) ;
q + = sprintf ( q , " %d " , lc - > Channel ( ) - > Number ( ) ) ;
}
delete linkChannels ;
}
else
q + = sprintf ( q , " none " ) ;
q + = sprintf ( q , " to " ) ;
linkChannels = LinkChannels ;
if ( linkChannels ) {
for ( cLinkChannel * lc = linkChannels - > First ( ) ; lc ; lc = linkChannels - > Next ( lc ) ) {
lc - > Channel ( ) - > SetRefChannel ( this ) ;
q + = sprintf ( q , " %d " , lc - > Channel ( ) - > Number ( ) ) ;
//dsyslog("link %4d -> %4d: %s", Number(), lc->Channel()->Number(), lc->Channel()->Name());
}
}
else
q + = sprintf ( q , " none " ) ;
dsyslog ( buffer ) ;
}
void cChannel : : SetRefChannel ( cChannel * RefChannel )
{
refChannel = RefChannel ;
}
2002-10-06 10:25:42 +02:00
static int PrintParameter ( char * p , char Name , int Value )
{
2002-11-01 10:26:45 +01:00
return Value > = 0 & & Value ! = 999 ? sprintf ( p , " %c%d " , Name , Value ) : 0 ;
2002-10-06 10:25:42 +02:00
}
2004-10-23 10:04:01 +02:00
const char * cChannel : : ParametersToString ( void ) const
2002-10-06 10:25:42 +02:00
{
char type = * cSource : : ToString ( source ) ;
2002-11-08 14:19:22 +01:00
if ( isdigit ( type ) )
type = ' S ' ;
2002-10-06 10:25:42 +02:00
# 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 ) {
2002-11-01 10:26:45 +01:00
Value = MapToDriver ( n , Map ) ;
if ( Value > = 0 )
2002-10-06 10:25:42 +02:00
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 ;
2004-01-11 15:54:37 +01:00
case ' L ' : polarization = * s + + ; break ;
2002-10-06 10:25:42 +02:00
case ' M ' : s = ParseParameter ( s , modulation , ModulationValues ) ; break ;
2004-01-11 15:54:37 +01:00
case ' R ' : polarization = * s + + ; break ;
2002-10-06 10:25:42 +02:00
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 ;
}
2004-10-23 10:04:01 +02:00
const char * cChannel : : ToText ( const cChannel * Channel )
2002-10-06 10:25:42 +02:00
{
2004-10-31 12:53:00 +01:00
char FullName [ strlen ( Channel - > name ) + 1 + strlen ( Channel - > shortName ) + 1 + strlen ( Channel - > provider ) + 1 + 10 ] ; // +10: paranoia
char * q = FullName ;
q + = sprintf ( q , " %s " , Channel - > name ) ;
if ( ! isempty ( Channel - > shortName ) )
q + = sprintf ( q , " ,%s " , Channel - > shortName ) ;
if ( ! isempty ( Channel - > provider ) )
q + = sprintf ( q , " ;%s " , Channel - > provider ) ;
* q = 0 ;
strreplace ( FullName , ' : ' , ' | ' ) ;
2002-10-06 10:25:42 +02:00
free ( buffer ) ;
2002-10-19 15:33:37 +02:00
if ( Channel - > groupSep ) {
if ( Channel - > number )
2004-10-31 12:53:00 +01:00
asprintf ( & buffer , " :@%d %s \n " , Channel - > number , FullName ) ;
2002-10-19 15:33:37 +02:00
else
2004-10-31 12:53:00 +01:00
asprintf ( & buffer , " :%s \n " , FullName ) ;
2002-10-19 15:33:37 +02:00
}
2002-10-06 10:25:42 +02:00
else {
2003-04-26 11:58:54 +02:00
char vpidbuf [ 32 ] ;
char * q = vpidbuf ;
q + = snprintf ( q , sizeof ( vpidbuf ) , " %d " , Channel - > vpid ) ;
2004-01-04 12:30:00 +01:00
if ( Channel - > ppid & & Channel - > ppid ! = Channel - > vpid )
2003-04-26 11:58:54 +02:00
q + = snprintf ( q , sizeof ( vpidbuf ) - ( q - vpidbuf ) , " +%d " , Channel - > ppid ) ;
* q = 0 ;
2004-01-25 15:32:08 +01:00
char apidbuf [ MAXAPIDS * 2 * 10 + 10 ] ; // 2: Apids and Dpids, 10: 5 digits plus delimiting ',' or ';' plus optional '=cod', +10: paranoia
2003-04-26 11:58:54 +02:00
q = apidbuf ;
2004-01-25 15:32:08 +01:00
q + = IntArrayToString ( q , Channel - > apids , 10 , Channel - > alangs ) ;
if ( Channel - > dpids [ 0 ] ) {
* q + + = ' ; ' ;
q + = IntArrayToString ( q , Channel - > dpids , 10 , Channel - > dlangs ) ;
}
2002-10-06 10:25:42 +02:00
* q = 0 ;
2004-01-04 12:30:00 +01:00
char caidbuf [ MAXCAIDS * 5 + 10 ] ; // 5: 4 digits plus delimiting ',', 10: paranoia
q = caidbuf ;
2004-01-25 15:32:08 +01:00
q + = IntArrayToString ( q , Channel - > caids , 16 ) ;
2004-01-04 12:30:00 +01:00
* q = 0 ;
2004-10-31 12:53:00 +01:00
asprintf ( & buffer , " %s:%d:%s:%s:%d:%s:%s:%d:%s:%d:%d:%d:%d \n " , FullName , Channel - > frequency , Channel - > ParametersToString ( ) , cSource : : ToString ( Channel - > source ) , Channel - > srate , vpidbuf , apidbuf , Channel - > tpid , caidbuf , Channel - > sid , Channel - > nid , Channel - > tid , Channel - > rid ) ;
2002-10-06 10:25:42 +02:00
}
return buffer ;
}
2004-10-23 10:04:01 +02:00
const char * cChannel : : ToText ( void ) const
2002-10-06 10:25:42 +02:00
{
return ToText ( this ) ;
}
2002-11-10 15:50:21 +01:00
bool cChannel : : Parse ( const char * s , bool AllowNonUniqueID )
2002-10-06 10:25:42 +02:00
{
2003-09-09 18:55:26 +02:00
bool ok = true ;
2002-10-06 10:25:42 +02:00
if ( * s = = ' : ' ) {
2002-10-19 15:33:37 +02:00
groupSep = true ;
if ( * + + s = = ' @ ' & & * + + s ) {
char * p = NULL ;
errno = 0 ;
int n = strtol ( s , & p , 10 ) ;
if ( ! errno & & p ! = s & & n > 0 ) {
number = n ;
s = p ;
}
2002-10-06 10:25:42 +02:00
}
2004-10-31 12:53:00 +01:00
name = strcpyrealloc ( name , skipspace ( s ) ) ;
strreplace ( name , ' | ' , ' : ' ) ;
2002-10-06 10:25:42 +02:00
}
else {
groupSep = false ;
char * namebuf = NULL ;
char * sourcebuf = NULL ;
char * parambuf = NULL ;
2003-04-26 11:58:54 +02:00
char * vpidbuf = NULL ;
2002-10-06 10:25:42 +02:00
char * apidbuf = NULL ;
2004-01-04 12:30:00 +01:00
char * caidbuf = NULL ;
int fields = sscanf ( s , " %a[^:]:%d :%a[^:]:%a[^:] :%d :%a[^:]:%a[^:]:%d :%a[^:]:%d :%d :%d :%d " , & namebuf , & frequency , & parambuf , & sourcebuf , & srate , & vpidbuf , & apidbuf , & tpid , & caidbuf , & sid , & nid , & tid , & rid ) ;
2002-10-06 10:25:42 +02:00
if ( fields > = 9 ) {
if ( fields = = 9 ) {
// allow reading of old format
2004-01-04 12:30:00 +01:00
sid = atoi ( caidbuf ) ;
delete caidbuf ;
caidbuf = NULL ;
caids [ 0 ] = tpid ;
caids [ 1 ] = 0 ;
2002-10-06 10:25:42 +02:00
tpid = 0 ;
}
2004-01-25 15:32:08 +01:00
vpid = ppid = 0 ;
apids [ 0 ] = 0 ;
dpids [ 0 ] = 0 ;
2003-09-09 18:55:26 +02:00
ok = false ;
2003-04-26 11:58:54 +02:00
if ( parambuf & & sourcebuf & & vpidbuf & & apidbuf ) {
2002-10-06 10:25:42 +02:00
ok = StringToParameters ( parambuf ) & & ( source = cSource : : FromString ( sourcebuf ) ) > = 0 ;
2004-01-04 12:30:00 +01:00
2003-04-26 11:58:54 +02:00
char * p = strchr ( vpidbuf , ' + ' ) ;
if ( p )
* p + + = 0 ;
sscanf ( vpidbuf , " %d " , & vpid ) ;
if ( p )
sscanf ( p , " %d " , & ppid ) ;
2004-01-04 12:30:00 +01:00
else
ppid = vpid ;
2004-01-25 15:32:08 +01:00
char * dpidbuf = strchr ( apidbuf , ' ; ' ) ;
if ( dpidbuf )
* dpidbuf + + = 0 ;
p = apidbuf ;
char * q ;
int NumApids = 0 ;
2004-12-19 16:33:34 +01:00
char * strtok_next ;
while ( ( q = strtok_r ( p , " , " , & strtok_next ) ) ! = NULL ) {
2004-01-25 15:32:08 +01:00
if ( NumApids < MAXAPIDS ) {
char * l = strchr ( q , ' = ' ) ;
if ( l ) {
* l + + = 0 ;
strn0cpy ( alangs [ NumApids ] , l , 4 ) ;
}
else
* alangs [ NumApids ] = 0 ;
apids [ NumApids + + ] = strtol ( q , NULL , 10 ) ;
}
else
esyslog ( " ERROR: too many APIDs! " ) ; // no need to set ok to 'false'
p = NULL ;
}
apids [ NumApids ] = 0 ;
if ( dpidbuf ) {
char * p = dpidbuf ;
char * q ;
int NumDpids = 0 ;
2004-12-19 16:33:34 +01:00
char * strtok_next ;
while ( ( q = strtok_r ( p , " , " , & strtok_next ) ) ! = NULL ) {
2004-01-25 15:32:08 +01:00
if ( NumDpids < MAXAPIDS ) {
char * l = strchr ( q , ' = ' ) ;
if ( l ) {
* l + + = 0 ;
strn0cpy ( dlangs [ NumDpids ] , l , 4 ) ;
}
else
* dlangs [ NumDpids ] = 0 ;
dpids [ NumDpids + + ] = strtol ( q , NULL , 10 ) ;
}
else
esyslog ( " ERROR: too many DPIDs! " ) ; // no need to set ok to 'false'
p = NULL ;
}
dpids [ NumDpids ] = 0 ;
}
2004-01-04 12:30:00 +01:00
if ( caidbuf ) {
char * p = caidbuf ;
char * q ;
int NumCaIds = 0 ;
2004-12-19 16:33:34 +01:00
char * strtok_next ;
while ( ( q = strtok_r ( p , " , " , & strtok_next ) ) ! = NULL ) {
2004-01-04 12:30:00 +01:00
if ( NumCaIds < MAXCAIDS ) {
caids [ NumCaIds + + ] = strtol ( q , NULL , 16 ) & 0xFFFF ;
if ( NumCaIds = = 1 & & caids [ 0 ] < = 0x00FF )
break ;
}
else
esyslog ( " ERROR: too many CA ids! " ) ; // no need to set ok to 'false'
p = NULL ;
}
caids [ NumCaIds ] = 0 ;
}
2002-10-06 10:25:42 +02:00
}
2004-10-31 12:53:00 +01:00
strreplace ( namebuf , ' | ' , ' : ' ) ;
char * p = strchr ( namebuf , ' ; ' ) ;
if ( p ) {
* p + + = 0 ;
provider = strcpyrealloc ( provider , p ) ;
}
p = strchr ( namebuf , ' , ' ) ;
if ( p ) {
* p + + = 0 ;
shortName = strcpyrealloc ( shortName , p ) ;
}
name = strcpyrealloc ( name , namebuf ) ;
2002-10-06 10:25:42 +02:00
free ( parambuf ) ;
free ( sourcebuf ) ;
2003-04-26 11:58:54 +02:00
free ( vpidbuf ) ;
2002-10-06 10:25:42 +02:00
free ( apidbuf ) ;
2004-01-04 12:30:00 +01:00
free ( caidbuf ) ;
2002-10-06 10:25:42 +02:00
free ( namebuf ) ;
2003-10-17 15:42:40 +02:00
if ( ! GetChannelID ( ) . Valid ( ) ) {
esyslog ( " ERROR: channel data results in invalid ID! " ) ;
return false ;
}
2002-11-10 15:50:21 +01:00
if ( ! AllowNonUniqueID & & Channels . GetByChannelID ( GetChannelID ( ) ) ) {
esyslog ( " ERROR: channel data not unique! " ) ;
return false ;
}
2002-10-06 10:25:42 +02:00
}
else
return false ;
}
2003-09-09 18:55:26 +02:00
return ok ;
2002-10-06 10:25:42 +02:00
}
bool cChannel : : Save ( FILE * f )
{
return fprintf ( f , ToText ( ) ) > 0 ;
}
// -- cChannels --------------------------------------------------------------
cChannels Channels ;
2004-01-04 12:30:00 +01:00
cChannels : : cChannels ( void )
{
maxNumber = 0 ;
2004-10-17 11:50:21 +02:00
modified = CHANNELSMOD_NONE ;
2004-01-04 12:30:00 +01:00
}
2003-08-16 09:18:52 +02:00
bool cChannels : : Load ( const char * FileName , bool AllowComments , bool MustExist )
2002-10-06 10:25:42 +02:00
{
2003-08-16 09:18:52 +02:00
if ( cConfig < cChannel > : : Load ( FileName , AllowComments , MustExist ) ) {
2002-10-06 10:25:42 +02:00
ReNumber ( ) ;
return true ;
}
return false ;
}
int cChannels : : GetNextGroup ( int Idx )
{
cChannel * channel = Get ( + + Idx ) ;
2002-11-29 14:19:08 +01:00
while ( channel & & ! ( channel - > GroupSep ( ) & & * channel - > Name ( ) ) )
2002-10-06 10:25:42 +02:00
channel = Get ( + + Idx ) ;
return channel ? Idx : - 1 ;
}
int cChannels : : GetPrevGroup ( int Idx )
{
cChannel * channel = Get ( - - Idx ) ;
2002-11-29 14:19:08 +01:00
while ( channel & & ! ( channel - > GroupSep ( ) & & * channel - > Name ( ) ) )
2002-10-06 10:25:42 +02:00
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 )
{
2002-10-19 15:33:37 +02:00
int Number = 1 ;
for ( cChannel * channel = First ( ) ; channel ; channel = Next ( channel ) ) {
if ( channel - > GroupSep ( ) ) {
if ( channel - > Number ( ) > Number )
Number = channel - > Number ( ) ;
}
2003-10-03 15:16:08 +02:00
else {
maxNumber = Number ;
2002-10-19 15:33:37 +02:00
channel - > SetNumber ( Number + + ) ;
2003-10-03 15:16:08 +02:00
}
2002-10-19 15:33:37 +02:00
}
2002-10-06 10:25:42 +02:00
}
2002-10-19 15:33:37 +02:00
cChannel * cChannels : : GetByNumber ( int Number , int SkipGap )
2002-10-06 10:25:42 +02:00
{
2002-10-19 15:33:37 +02:00
cChannel * previous = NULL ;
for ( cChannel * channel = First ( ) ; channel ; channel = Next ( channel ) ) {
if ( ! channel - > GroupSep ( ) ) {
if ( channel - > Number ( ) = = Number )
return channel ;
else if ( SkipGap & & channel - > Number ( ) > Number )
return SkipGap > 0 ? channel : previous ;
previous = channel ;
}
}
2002-10-06 10:25:42 +02:00
return NULL ;
}
2004-01-04 12:30:00 +01:00
cChannel * cChannels : : GetByServiceID ( int Source , int Transponder , unsigned short ServiceID )
2002-11-10 15:50:21 +01:00
{
for ( cChannel * channel = First ( ) ; channel ; channel = Next ( channel ) ) {
2004-01-04 12:30:00 +01:00
if ( ! channel - > GroupSep ( ) & & channel - > Source ( ) = = Source & & ISTRANSPONDER ( channel - > Transponder ( ) , Transponder ) & & channel - > Sid ( ) = = ServiceID )
2002-11-10 15:50:21 +01:00
return channel ;
}
return NULL ;
}
2004-02-13 15:50:26 +01:00
cChannel * cChannels : : GetByChannelID ( tChannelID ChannelID , bool TryWithoutRid , bool TryWithoutPolarization )
2002-10-06 10:25:42 +02:00
{
2002-10-19 15:33:37 +02:00
for ( cChannel * channel = First ( ) ; channel ; channel = Next ( channel ) ) {
2002-11-10 15:50:21 +01:00
if ( ! channel - > GroupSep ( ) & & channel - > GetChannelID ( ) = = ChannelID )
2002-10-19 15:33:37 +02:00
return channel ;
}
2002-11-24 14:48:38 +01:00
if ( TryWithoutRid ) {
ChannelID . ClrRid ( ) ;
for ( cChannel * channel = First ( ) ; channel ; channel = Next ( channel ) ) {
if ( ! channel - > GroupSep ( ) & & channel - > GetChannelID ( ) . ClrRid ( ) = = ChannelID )
return channel ;
}
}
2004-02-13 15:50:26 +01:00
if ( TryWithoutPolarization ) {
ChannelID . ClrPolarization ( ) ;
for ( cChannel * channel = First ( ) ; channel ; channel = Next ( channel ) ) {
if ( ! channel - > GroupSep ( ) & & channel - > GetChannelID ( ) . ClrPolarization ( ) = = ChannelID )
return channel ;
}
}
2002-10-06 10:25:42 +02:00
return NULL ;
}
2002-11-10 15:50:21 +01:00
bool cChannels : : HasUniqueChannelID ( cChannel * NewChannel , cChannel * OldChannel )
{
2002-11-24 14:48:38 +01:00
tChannelID NewChannelID = NewChannel - > GetChannelID ( ) ;
2002-11-10 15:50:21 +01:00
for ( cChannel * channel = First ( ) ; channel ; channel = Next ( channel ) ) {
if ( ! channel - > GroupSep ( ) & & channel ! = OldChannel & & channel - > GetChannelID ( ) = = NewChannelID )
return false ;
}
return true ;
}
2002-10-06 10:25:42 +02:00
bool cChannels : : SwitchTo ( int Number )
{
cChannel * channel = GetByNumber ( Number ) ;
return channel & & cDevice : : PrimaryDevice ( ) - > SwitchChannel ( channel , true ) ;
}
2004-01-04 12:30:00 +01:00
2004-10-17 11:50:21 +02:00
void cChannels : : SetModified ( bool ByUser )
2004-01-04 12:30:00 +01:00
{
2004-10-17 11:50:21 +02:00
modified = ByUser ? CHANNELSMOD_USER : ! modified ? CHANNELSMOD_AUTO : modified ;
2004-01-04 12:30:00 +01:00
}
2004-10-17 11:50:21 +02:00
int cChannels : : Modified ( void )
2004-01-04 12:30:00 +01:00
{
2004-10-17 11:50:21 +02:00
int Result = modified ;
modified = CHANNELSMOD_NONE ;
2004-01-04 12:30:00 +01:00
return Result ;
}
2004-10-31 12:53:00 +01:00
cChannel * cChannels : : NewChannel ( const cChannel * Transponder , const char * Name , const char * ShortName , const char * Provider , int Nid , int Tid , int Sid , int Rid )
2004-01-04 12:30:00 +01:00
{
2004-01-11 15:54:37 +01:00
if ( Transponder ) {
2004-10-31 12:53:00 +01:00
dsyslog ( " creating new channel '%s,%s;%s' on %s transponder %d with id %d-%d-%d-%d " , Name , ShortName , Provider , cSource : : ToString ( Transponder - > Source ( ) ) , Transponder - > Transponder ( ) , Nid , Tid , Sid , Rid ) ;
2004-02-08 11:05:22 +01:00
cChannel * NewChannel = new cChannel ( * Transponder ) ;
2004-10-17 12:22:56 +02:00
NewChannel - > SetId ( Nid , Tid , Sid , Rid ) ;
2004-10-31 12:53:00 +01:00
NewChannel - > SetName ( Name , ShortName , Provider ) ;
2004-01-11 15:54:37 +01:00
Add ( NewChannel ) ;
ReNumber ( ) ;
return NewChannel ;
}
2004-01-04 12:30:00 +01:00
return NULL ;
}
2004-05-16 10:35:36 +02:00
const char * ChannelString ( const cChannel * Channel , int Number )
{
static char buffer [ 256 ] ;
if ( Channel ) {
if ( Channel - > GroupSep ( ) )
snprintf ( buffer , sizeof ( buffer ) , " %s " , Channel - > Name ( ) ) ;
else
snprintf ( buffer , sizeof ( buffer ) , " %d%s %s " , Channel - > Number ( ) , Number ? " - " : " " , Channel - > Name ( ) ) ;
}
else if ( Number )
snprintf ( buffer , sizeof ( buffer ) , " %d- " , Number ) ;
else
snprintf ( buffer , sizeof ( buffer ) , " %s " , tr ( " *** Invalid Channel *** " ) ) ;
return buffer ;
}