Implemented 'Link Layer' based CAM support

This commit is contained in:
Klaus Schmidinger 2003-01-06 14:44:27 +01:00
parent 43b582a04d
commit 4e15f6d658
15 changed files with 2111 additions and 24 deletions

View File

@ -1899,7 +1899,7 @@ Video Disk Recorder Revision History
See INSTALL for information how to do this. Some function descriptions have
already been adapted to Doxygen, more will follow.
2002-12-23: Version 1.1.21
2003-01-06: Version 1.1.21
- Fixed the 'channels.conf' entries for "Studio Universal" and "Disney Channel".
- Fixed handling channels in the "Channels" menu in case there are ':@nnn' group
@ -1908,3 +1908,6 @@ Video Disk Recorder Revision History
- Increased the timeout until an index file is considerd no longer to be written
(sometimes in time shift with heavy system load the index file was closed too
early by the replay thread).
- Implemented "Link Layer" based CAM support, which hopefully will solve the
problems with CAMs we had in the past. To use this you need the driver version
2002-01-06 or higher (with the new firmware supporting the "Link Layer" protocol).

View File

@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
# $Id: Makefile 1.55 2002/12/15 15:15:55 kls Exp $
# $Id: Makefile 1.56 2003/01/06 12:28:09 kls Exp $
.DELETE_ON_ERROR:
@ -32,7 +32,7 @@ INCLUDES = -I$(DVBDIR)/include
DTVLIB = $(DTVDIR)/libdtv.a
OBJS = audio.o channels.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbosd.o\
OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbosd.o\
dvbplayer.o dvbspu.o eit.o eitscan.o font.o i18n.o interface.o keys.o\
lirc.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o rcu.o\
receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sources.o\

1449
ci.c Normal file

File diff suppressed because it is too large Load Diff

105
ci.h Normal file
View File

@ -0,0 +1,105 @@
/*
* ci.h: Common Interface
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: ci.h 1.1 2003/01/06 12:31:09 kls Exp $
*/
#ifndef __CI_H
#define __CI_H
#include <stdint.h>
#include <stdio.h>
#include "thread.h"
class cCiMMI;
class cCiMenu {
friend class cCiMMI;
private:
enum { MAX_CIMENU_ENTRIES = 64 }; ///< XXX is there a specified maximum?
cCiMMI *mmi;
bool selectable;
char *titleText;
char *subTitleText;
char *bottomText;
char *entries[MAX_CIMENU_ENTRIES];
int numEntries;
bool AddEntry(char *s);
cCiMenu(cCiMMI *MMI, bool Selectable);
public:
~cCiMenu();
const char *TitleText(void) { return titleText; }
const char *SubTitleText(void) { return subTitleText; }
const char *BottomText(void) { return bottomText; }
const char *Entry(int n) { return n < numEntries ? entries[n] : NULL; }
int NumEntries(void) { return numEntries; }
bool Selectable(void) { return selectable; }
bool Select(int Index);
bool Cancel(void);
};
class cCiEnquiry {
friend class cCiMMI;
private:
cCiMMI *mmi;
char *text;
bool blind;
int expectedLength;
cCiEnquiry(cCiMMI *MMI);
public:
~cCiEnquiry();
const char *Text(void) { return text; }
bool Blind(void) { return blind; }
int ExpectedLength(void) { return expectedLength; }
bool Reply(const char *s);
bool Cancel(void);
};
class cCiCaPmt {
friend class cCiConditionalAccessSupport;
private:
int length;
int esInfoLengthPos;
uint8_t capmt[2048]; ///< XXX is there a specified maximum?
public:
cCiCaPmt(int ProgramNumber);
void AddPid(int Pid);
void AddCaDescriptor(int Length, uint8_t *Data);
};
#define MAX_CI_SESSION 16 //XXX
class cCiSession;
class cCiTransportLayer;
class cCiTransportConnection;
class cCiHandler {
private:
cMutex mutex;
int numSlots;
cCiSession *sessions[MAX_CI_SESSION];
cCiTransportLayer *tpl;
cCiTransportConnection *tc;
int ResourceIdToInt(const uint8_t *Data);
bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1);
cCiSession *GetSessionBySessionId(int SessionId);
cCiSession *GetSessionByResourceId(int ResourceId);
cCiSession *CreateSession(int ResourceId);
bool OpenSession(int Length, const uint8_t *Data);
bool CloseSession(int SessionId);
cCiHandler(int Fd, int NumSlots);
public:
~cCiHandler();
static cCiHandler *CreateCiHandler(const char *FileName);
bool Process(void);
bool EnterMenu(void);
cCiMenu *GetMenu(void);
cCiEnquiry *GetEnquiry(void);
bool SetCaPmt(cCiCaPmt &CaPmt);
bool Reset(void);
};
#endif //__CI_H

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: device.c 1.35 2002/11/10 10:17:57 kls Exp $
* $Id: device.c 1.36 2003/01/03 15:41:14 kls Exp $
*/
#include "device.h"
@ -47,6 +47,7 @@ cDevice::cDevice(void)
mute = false;
volume = Setup.CurrentVolume;
ciHandler = NULL;
player = NULL;
playerDetached = false;
@ -67,6 +68,7 @@ cDevice::~cDevice()
Detach(player);
for (int i = 0; i < MAXRECEIVERS; i++)
Detach(receiver[i]);
delete ciHandler;
}
void cDevice::SetUseDevice(int n)

View File

@ -4,12 +4,13 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: device.h 1.28 2002/12/15 14:40:11 kls Exp $
* $Id: device.h 1.29 2003/01/03 15:43:48 kls Exp $
*/
#ifndef __DEVICE_H
#define __DEVICE_H
#include "ci.h"
#include "thread.h"
#include "tools.h"
@ -211,6 +212,13 @@ protected:
///< Type indicates some special types of PIDs, which the device may
///< need to set in a specific way.
// Common Interface facilities:
protected:
cCiHandler *ciHandler;
public:
cCiHandler *CiHandler(void) { return ciHandler; }
// Image Grab facilities
public:

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbdevice.c 1.40 2002/12/14 10:52:13 kls Exp $
* $Id: dvbdevice.c 1.41 2003/01/06 14:44:27 kls Exp $
*/
#include "dvbdevice.h"
@ -43,6 +43,7 @@ extern "C" {
#define DEV_DVB_DEMUX "demux"
#define DEV_DVB_VIDEO "video"
#define DEV_DVB_AUDIO "audio"
#define DEV_DVB_CA "ca"
static const char *DvbName(const char *Name, int n)
{
@ -68,30 +69,34 @@ private:
int fd_frontend;
int cardIndex;
fe_type_t frontendType;
cCiHandler *ciHandler;
cChannel channel;
const char *diseqcCommands;
bool active;
eTunerStatus tunerStatus;
bool caSet;
cMutex mutex;
cCondVar newSet;
bool SetFrontend(void);
virtual void Action(void);
public:
cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType);
cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCiHandler *CiHandler);
virtual ~cDvbTuner();
bool IsTunedTo(const cChannel *Channel) const;
void Set(const cChannel *Channel);
void Set(const cChannel *Channel, bool Tune);
bool Locked(void) { return tunerStatus == tsLocked; }
};
cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType)
cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCiHandler *CiHandler)
{
fd_frontend = Fd_Frontend;
cardIndex = CardIndex;
frontendType = FrontendType;
ciHandler = CiHandler;
diseqcCommands = NULL;
active = false;
tunerStatus = tsIdle;
caSet = false;
Start();
}
@ -108,11 +113,13 @@ bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
return tunerStatus != tsIdle && channel.Source() == Channel->Source() && channel.Frequency() == Channel->Frequency();
}
void cDvbTuner::Set(const cChannel *Channel)
void cDvbTuner::Set(const cChannel *Channel, bool Tune)
{
cMutexLock MutexLock(&mutex);
channel = *Channel;
tunerStatus = tsSet;
if (Tune)
tunerStatus = tsSet;
caSet = false;
newSet.Broadcast();
}
@ -251,6 +258,30 @@ void cDvbTuner::Action(void)
continue;
}
}
if (ciHandler && !caSet) {//XXX TODO update in case the CA descriptors have changed
uchar buffer[2048];
int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), sizeof(buffer), buffer);
if (length > 0) {
cCiCaPmt CaPmt(channel.Sid());
if (channel.Vpid()) {
CaPmt.AddPid(channel.Vpid());
CaPmt.AddCaDescriptor(length, buffer);
}
if (channel.Apid1()) {
CaPmt.AddPid(channel.Apid1());
CaPmt.AddCaDescriptor(length, buffer);
}
if (channel.Apid2()) {
CaPmt.AddPid(channel.Apid2());
CaPmt.AddCaDescriptor(length, buffer);
}
if (channel.Dpid1()) {
CaPmt.AddPid(channel.Dpid1());
CaPmt.AddCaDescriptor(length, buffer);
}
caSet = ciHandler->SetCaPmt(CaPmt);
}
}
newSet.TimedWait(mutex, 1000);
}
dsyslog("tuner thread ended on device %d (pid=%d)", cardIndex + 1, getpid());
@ -291,7 +322,8 @@ cDvbDevice::cDvbDevice(int n)
siProcessor = new cSIProcessor(DvbName(DEV_DVB_DEMUX, n));
if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0) {
frontendType = feinfo.type;
dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType);
ciHandler = cCiHandler::CreateCiHandler(DvbName(DEV_DVB_CA, n));
dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType, ciHandler);
}
else
LOG_ERROR;
@ -616,8 +648,8 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
DelPid(pidHandles[ptDolby].pid);
}
dvbTuner->Set(Channel, DoTune);
if (DoTune) {
dvbTuner->Set(Channel);
/*XXX do we still need this???
if (!(status & FE_HAS_LOCK)) {
esyslog("ERROR: channel %d not locked on DVB card %d!", Channel->Number(), CardIndex() + 1);

177
eit.c
View File

@ -16,7 +16,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: eit.c 1.61 2002/11/24 14:37:38 kls Exp $
* $Id: eit.c 1.62 2003/01/06 14:10:37 kls Exp $
***************************************************************************/
#include "eit.h"
@ -985,6 +985,68 @@ bool cEIT::IsPresentFollowing()
return false;
}
// --- cCaDescriptor ---------------------------------------------------------
class cCaDescriptor : public cListObject {
friend class cCaDescriptors;
private:
int source;
int transponder;
int serviceId;
int caSystem;
int length;
uchar *data;
public:
cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, int Length, uchar *Data);
virtual ~cCaDescriptor();
int Length(void) const { return length; }
const uchar *Data(void) const { return data; }
};
cCaDescriptor::cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, int Length, uchar *Data)
{
source = Source;
transponder = Transponder;
serviceId = ServiceId;
caSystem = CaSystem;
length = Length;
data = MALLOC(uchar, length);
memcpy(data, Data, length);
/*//XXX just while debugging...
char buffer[1024];
char *q = buffer;
q += sprintf(q, "CAM: %04X %5d %4d", source, transponder, serviceId);
for (int i = 0; i < length; i++)
q += sprintf(q, " %02X", data[i]);
dsyslog(buffer);
*///XXX
}
cCaDescriptor::~cCaDescriptor()
{
free(data);
}
// --- cCaDescriptors --------------------------------------------------------
class cCaDescriptors : public cList<cCaDescriptor> {
public:
const cCaDescriptor *Get(int Source, int Transponder, int ServiceId, int CaSystem);
};
const cCaDescriptor *cCaDescriptors::Get(int Source, int Transponder, int ServiceId, int CaSystem)
{
for (cCaDescriptor *ca = First(); ca; ca = Next(ca)) {
if (ca->source == Source && ca->transponder == Transponder && ca->serviceId == ServiceId) {
if (CaSystem == -1 || ca->caSystem == CaSystem)
return ca;
if (CaSystem < 0)
CaSystem++;
}
}
return NULL;
}
// --- cSIProcessor ----------------------------------------------------------
#define MAX_FILTERS 20
@ -993,6 +1055,8 @@ bool cEIT::IsPresentFollowing()
int cSIProcessor::numSIProcessors = 0;
cSchedules *cSIProcessor::schedules = NULL;
cMutex cSIProcessor::schedulesMutex;
cCaDescriptors *cSIProcessor::caDescriptors = NULL;
cMutex cSIProcessor::caDescriptorsMutex;
const char *cSIProcessor::epgDataFileName = EPGDATAFILENAME;
time_t cSIProcessor::lastDump = time(NULL);
@ -1003,9 +1067,13 @@ cSIProcessor::cSIProcessor(const char *FileName)
masterSIProcessor = numSIProcessors == 0; // the first one becomes the 'master'
currentSource = 0;
currentTransponder = 0;
pmtIndex = 0;
pmtPid = 0;
filters = NULL;
if (!numSIProcessors++) // the first one creates it
if (!numSIProcessors++) { // the first one creates them
schedules = new cSchedules;
caDescriptors = new cCaDescriptors;
}
filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER));
SetStatus(true);
Start();
@ -1019,8 +1087,10 @@ cSIProcessor::~cSIProcessor()
Cancel(3);
ShutDownFilters();
free(filters);
if (!--numSIProcessors) // the last one deletes it
if (!--numSIProcessors) { // the last one deletes them
delete schedules;
delete caDescriptors;
}
free(fileName);
}
@ -1075,9 +1145,13 @@ const char *cSIProcessor::GetEpgDataFileName(void)
void cSIProcessor::SetStatus(bool On)
{
LOCK_THREAD;
ShutDownFilters();
pmtIndex = 0;
pmtPid = 0;
if (On)
{
AddFilter(0x00, 0x00); // PAT
AddFilter(0x14, 0x70); // TDT
AddFilter(0x14, 0x73); // TOT
AddFilter(0x12, 0x4e); // event info, actual TS, present/following
@ -1089,6 +1163,8 @@ void cSIProcessor::SetStatus(bool On)
}
}
#define PMT_SCAN_TIMEOUT 10 // seconds
/** use the vbi device to parse all relevant SI
information and let the classes corresponding
to the tables write their information to the disk */
@ -1097,6 +1173,7 @@ void cSIProcessor::Action()
dsyslog("EIT processing thread started (pid=%d)%s", getpid(), masterSIProcessor ? " - master" : "");
time_t lastCleanup = time(NULL);
time_t lastPmtScan = time(NULL);
active = true;
@ -1162,6 +1239,37 @@ void cSIProcessor::Action()
//dsyslog("Received pid 0x%02x with table ID 0x%02x and length of %04d\n", pid, buf[0], seclen);
switch (pid)
{
case 0x00:
if (buf[0] == 0x00)
{
LOCK_THREAD;
if (pmtPid && time(NULL) - lastPmtScan > PMT_SCAN_TIMEOUT) {
DelFilter(pmtPid, 0x02);
pmtPid = 0;
pmtIndex++;
lastPmtScan = time(NULL);
}
if (!pmtPid) {
cMutexLock MutexLock(&schedulesMutex); // since the xMem... stuff is not thread safe, we need to use a "global" mutex
struct LIST *pat = siParsePAT(buf);
if (pat) {
int Index = 0;
for (struct Program *prg = (struct Program *)pat->Head; prg; prg = (struct Program *)xSucc(prg)) {
if (prg->ProgramID) {
if (Index++ == pmtIndex) {
pmtPid = prg->NetworkPID;
AddFilter(pmtPid, 0x02);
break;
}
}
}
if (!pmtPid)
pmtIndex = 0;
}
xMemFreeAll(NULL);
}
}
break;
case 0x14:
if (buf[0] == 0x70)
{
@ -1188,7 +1296,28 @@ void cSIProcessor::Action()
dsyslog("Received stuffing section in EIT\n");
break;
default:
default: {
LOCK_THREAD;
if (pid == pmtPid && buf[0] == 0x02 && currentSource && currentTransponder) {
cMutexLock MutexLock(&schedulesMutex); // since the xMem... stuff is not thread safe, we need to use a "global" mutex
struct Pid *pi = siParsePMT(buf);
if (pi) {
for (struct LIST *d = (struct LIST *)pi->Descriptors; d; d = (struct LIST *)xSucc(d)) {
if (DescriptorTag(d) == DESCR_CA) {
uchar *Data = ((ConditionalAccessDescriptor *)d)->Data;
int CaSystem = (Data[2] << 8) | Data[3];
if (!caDescriptors->Get(currentSource, currentTransponder, pi->ProgramID, CaSystem)) {
cMutexLock MutexLock(&caDescriptorsMutex);
caDescriptors->Add(new cCaDescriptor(currentSource, currentTransponder, pi->ProgramID, CaSystem, ((ConditionalAccessDescriptor *)d)->Amount, Data));
}
//XXX update???
}
}
}
xMemFreeAll(NULL);
lastPmtScan = 0; // this triggers the next scan
}
}
break;
}
}
@ -1229,7 +1358,7 @@ bool cSIProcessor::AddFilter(u_char pid, u_char tid)
filters[a].inuse = true;
else
{
esyslog("ERROR: can't set filter");
esyslog("ERROR: can't set filter (pid=%d, tid=%02X)", pid, tid);
close(filters[a].handle);
return false;
}
@ -1248,6 +1377,21 @@ bool cSIProcessor::AddFilter(u_char pid, u_char tid)
return false;
}
bool cSIProcessor::DelFilter(u_char pid, u_char tid)
{
for (int a = 0; a < MAX_FILTERS; a++)
{
if (filters[a].inuse && filters[a].pid == pid && filters[a].tid == tid)
{
close(filters[a].handle);
// dsyslog("Deregistered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid);
filters[a].inuse = false;
return true;
}
}
return false;
}
/** */
bool cSIProcessor::ShutDownFilters(void)
{
@ -1283,3 +1427,26 @@ void cSIProcessor::TriggerDump(void)
cMutexLock MutexLock(&schedulesMutex);
lastDump = 0;
}
int cSIProcessor::GetCaDescriptors(int Source, int Transponder, int ServiceId, int BufSize, uchar *Data)
{
if (BufSize > 0 && Data) {
cMutexLock MutexLock(&caDescriptorsMutex);
int length = 0;
for (int i = -1; ; i--) {
const cCaDescriptor *d = caDescriptors->Get(Source, Transponder, ServiceId, i);
if (d) {
if (length + d->Length() <= BufSize) {
memcpy(Data + length, d->Data(), d->Length());
length += d->Length();
}
else
return -1;
}
else
break;
}
return length;
}
return -1;
}

16
eit.h
View File

@ -16,7 +16,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: eit.h 1.22 2002/11/24 12:45:55 kls Exp $
* $Id: eit.h 1.23 2003/01/04 10:12:54 kls Exp $
***************************************************************************/
#ifndef __EIT_H
@ -134,21 +134,29 @@ typedef struct sip_filter {
}SIP_FILTER;
class cCaDescriptor;
class cCaDescriptors;
class cSIProcessor : public cThread {
private:
static int numSIProcessors;
static cSchedules *schedules;
static cMutex schedulesMutex;
static cCaDescriptors *caDescriptors;
static cMutex caDescriptorsMutex;
static const char *epgDataFileName;
static time_t lastDump;
bool masterSIProcessor;
int currentSource;
int currentTransponder;
int pmtIndex;
int pmtPid;
SIP_FILTER *filters;
char *fileName;
bool active;
void Action(void);
bool AddFilter(u_char pid, u_char tid);
bool DelFilter(u_char pid, u_char tid);
bool ShutDownFilters(void);
public:
cSIProcessor(const char *FileName);
@ -159,6 +167,12 @@ public:
// Caller must provide a cMutexLock which has to survive the entire
// time the returned cSchedules is accessed. Once the cSchedules is no
// longer used, the cMutexLock must be destroyed.
static int GetCaDescriptors(int Source, int Transponder, int ServiceId, int BufSize, uchar *Data);
///< Gets all CA descriptors for a given channel.
///< Copies all available CA descriptors for the given Source, Transponder and ServiceId
///< into the provided buffer at Data (at most BufSize bytes).
///< \return Returns the number of bytes copied into Data (0 if no CA descriptors are
///< available), or -1 if BufSize was too small to hold all CA descriptors.
static bool Read(FILE *f = NULL);
static void Clear(void);
void SetStatus(bool On);

82
i18n.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: i18n.c 1.100 2002/11/10 12:32:30 kls Exp $
* $Id: i18n.c 1.101 2003/01/06 12:16:28 kls Exp $
*
* Translations provided by:
*
@ -664,6 +664,38 @@ const tI18nPhrase Phrases[] = {
"Suprascrie",
"Átírni",
},
{ "Menu",
"Menü",
"Meni",
"Menu",
"Menu",
"Menu",
"Menu",
"Meny",
"Valikko",
"Menu",
"Menu",
"Menou",
"Meny",
"Meniu",
"Menü",
},
{ "Reset",
"Reset",
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
},
// Confirmations:
{ "Delete channel?",
"Kanal löschen?",
@ -1580,6 +1612,54 @@ const tI18nPhrase Phrases[] = {
"Spatiu scazut pe disc!",
"A merev lemez majdnem tele!",
},
{ "Can't open CAM menu!",
"CAM-Menü kann nicht geöffnet werden!",
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
},
{ "Can't reset CAM!",
"CAM-Reset fehlgeschlagen!",
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
},
{ "CAM has been reset",
"CAM wurde zurückgesetzt!",
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
"",//TODO
},
// Setup pages:
{ "OSD",
"OSD",

View File

@ -315,6 +315,29 @@ struct Descriptor {
};
/* ConditionalAccessDescriptor */
struct ConditionalAccessDescriptor {
struct NODE Node;
unsigned short Tag;
unsigned short Amount; /* Data */
unsigned char *Data;
};
#define CreateConditionalAccessDescriptor(descr, amount, data) \
do \
{ \
unsigned char *tmpptr; \
\
xMemAlloc (amount, &tmpptr); \
memcpy (tmpptr, data, amount); \
xCreateNode (((struct ConditionalAccessDescriptor *)descr), NULL); \
((struct ConditionalAccessDescriptor *)descr)->Tag = DESCR_CA; \
((struct ConditionalAccessDescriptor *)descr)->Amount = amount; \
((struct ConditionalAccessDescriptor *)descr)->Data = tmpptr; \
} while (0)
/* Iso639LanguageDescriptor */
struct Iso639LanguageDescriptor {

View File

@ -705,6 +705,12 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer)
HILO (CastTimeShiftedEventDescriptor(Ptr)->reference_event_id));
break;
case DESCR_CA:
CreateConditionalAccessDescriptor (Descriptor,
*(Ptr + 1) + 2, // we'll need the entire raw data!
Ptr);
break;
case DESCR_ISO_639_LANGUAGE:
CreateIso639LanguageDescriptor (Descriptor,
CastIso639LanguageDescriptor(Buffer)->lang_code1,
@ -790,7 +796,6 @@ void siParseDescriptor (struct LIST *Descriptors, u_char *Buffer)
case DESCR_DATA_STREAM_ALIGN:
case DESCR_TARGET_BACKGRID:
case DESCR_VIDEO_WINDOW:
case DESCR_CA:
case DESCR_SYSTEM_CLOCK:
case DESCR_MULTIPLEX_BUFFER_UTIL:
case DESCR_COPYRIGHT:

173
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 1.229 2002/12/22 12:40:43 kls Exp $
* $Id: menu.c 1.230 2003/01/06 13:35:38 kls Exp $
*/
#include "menu.h"
@ -1521,6 +1521,117 @@ eOSState cMenuCommands::ProcessKey(eKeys Key)
return state;
}
// --- cMenuCam --------------------------------------------------------------
cMenuCam::cMenuCam(cCiMenu *CiMenu)
:cOsdMenu("")
{
ciMenu = CiMenu;
selected = false;
if (ciMenu->Selectable())
SetHasHotkeys();
SetTitle(ciMenu->TitleText() ? ciMenu->TitleText() : "CAM");
for (int i = 0; i < ciMenu->NumEntries(); i++)
Add(new cOsdItem(hk(ciMenu->Entry(i))));
//XXX implement a clean way of displaying this:
Add(new cOsdItem(ciMenu->SubTitleText()));
Add(new cOsdItem(ciMenu->BottomText()));
Display();
}
cMenuCam::~cMenuCam()
{
if (!selected)
ciMenu->Cancel();
delete ciMenu;
}
eOSState cMenuCam::Select(void)
{
if (ciMenu->Selectable()) {
ciMenu->Select(Current());
selected = true;
return osEnd;
}
return osContinue;
}
eOSState cMenuCam::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
case kOk: return Select();
default: break;
}
}
return state;
}
// --- cMenuCamEnquiry -------------------------------------------------------
//XXX this is just quick and dirty - make this a separate display object
cMenuCamEnquiry::cMenuCamEnquiry(cCiEnquiry *CiEnquiry)
:cOsdMenu("")
{
ciEnquiry = CiEnquiry;
replied = false;
SetTitle(ciEnquiry->Text() ? ciEnquiry->Text() : "CAM");
Display();
}
cMenuCamEnquiry::~cMenuCamEnquiry()
{
if (!replied)
ciEnquiry->Cancel();
delete ciEnquiry;
}
eOSState cMenuCamEnquiry::Reply(void)
{
ciEnquiry->Reply("1234");//XXX implement actual user input
replied = true;
return osEnd;
}
eOSState cMenuCamEnquiry::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
case kOk: return Reply();
default: break;
}
}
return state;
}
// --- CamControl ------------------------------------------------------------
cOsdObject *CamControl(void)
{
for (int d = 0; d < cDevice::NumDevices(); d++) {
cDevice *Device = cDevice::GetDevice(d);
if (Device) {
cCiHandler *CiHandler = Device->CiHandler();
if (CiHandler) {
CiHandler->Process();
cCiMenu *CiMenu = CiHandler->GetMenu();
if (CiMenu)
return new cMenuCam(CiMenu);
else {
cCiEnquiry *CiEnquiry = CiHandler->GetEnquiry();
if (CiEnquiry)
return new cMenuCamEnquiry(CiEnquiry);
}
}
}
}
return NULL;
}
// --- cMenuRecordingItem ----------------------------------------------------
class cMenuRecordingItem : public cOsdItem {
@ -1950,6 +2061,12 @@ eOSState cMenuSetupLNB::ProcessKey(eKeys Key)
// --- cMenuSetupCICAM -------------------------------------------------------
class cMenuSetupCICAM : public cMenuSetupBase {
private:
int helpKeys;
void SetHelpKeys(void);
cCiHandler *GetCurrentCiHandler(void);
eOSState Menu(void);
eOSState Reset(void);
public:
cMenuSetupCICAM(void);
virtual eOSState ProcessKey(eKeys Key);
@ -1957,6 +2074,7 @@ public:
cMenuSetupCICAM::cMenuSetupCICAM(void)
{
helpKeys = -1;
SetSection(tr("CICAM"));
for (int d = 0; d < cDevice::NumDevices(); d++) {
for (int i = 0; i < 2; i++) {
@ -1965,6 +2083,46 @@ cMenuSetupCICAM::cMenuSetupCICAM(void)
Add(new cMenuEditCaItem(buffer, &data.CaCaps[d][i]));
}
}
SetHelpKeys();
}
cCiHandler *cMenuSetupCICAM::GetCurrentCiHandler(void)
{
cDevice *Device = cDevice::GetDevice(Current() / 2);
return Device ? Device->CiHandler() : NULL;
}
void cMenuSetupCICAM::SetHelpKeys(void)
{
int NewHelpKeys = helpKeys;
NewHelpKeys = GetCurrentCiHandler() ? 1 : 0;
if (NewHelpKeys != helpKeys) {
switch (NewHelpKeys) {
case 0: SetHelp(NULL); break;
case 1: SetHelp(tr("Menu"), tr("Reset"));
}
helpKeys = NewHelpKeys;
}
}
eOSState cMenuSetupCICAM::Menu(void)
{
cCiHandler *CiHandler = GetCurrentCiHandler();
if (CiHandler && CiHandler->EnterMenu())
return osEnd; // the CAM menu will be executed explicitly from the main loop
else
Interface->Error(tr("Can't open CAM menu!"));
return osContinue;
}
eOSState cMenuSetupCICAM::Reset(void)
{
cCiHandler *CiHandler = GetCurrentCiHandler();
if (CiHandler && CiHandler->Reset())
Interface->Info(tr("CAM has been reset"));
else
Interface->Error(tr("Can't reset CAM!"));
return osContinue;
}
eOSState cMenuSetupCICAM::ProcessKey(eKeys Key)
@ -1973,6 +2131,19 @@ eOSState cMenuSetupCICAM::ProcessKey(eKeys Key)
if (state == osBack && Key == kOk)
cDevice::SetCaCaps();
else if (state == osUnknown) {
switch (Key) {
case kRed: if (helpKeys == 1)
return Menu();
break;
case kGreen: if (helpKeys == 1)
return Reset();
break;
default: break;
}
}
if (Key != kNone)
SetHelpKeys();
return state;
}

27
menu.h
View File

@ -4,12 +4,13 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.h 1.51 2002/11/30 15:55:39 kls Exp $
* $Id: menu.h 1.52 2003/01/06 10:04:05 kls Exp $
*/
#ifndef __MENU_H
#define __MENU_H
#include "ci.h"
#include "device.h"
#include "osd.h"
#include "dvbplayer.h"
@ -58,6 +59,30 @@ public:
eOSState ProcessKey(eKeys Key);
};
class cMenuCam : public cOsdMenu {
private:
cCiMenu *ciMenu;
bool selected;
eOSState Select(void);
public:
cMenuCam(cCiMenu *CiMenu);
virtual ~cMenuCam();
virtual eOSState ProcessKey(eKeys Key);
};
class cMenuCamEnquiry : public cOsdMenu {
private:
cCiEnquiry *ciEnquiry;
bool replied;
eOSState Reply(void);
public:
cMenuCamEnquiry(cCiEnquiry *CiEnquiry);
virtual ~cMenuCamEnquiry();
virtual eOSState ProcessKey(eKeys Key);
};
cOsdObject *CamControl(void);
class cMenuRecordingItem;
class cMenuRecordings : public cOsdMenu {

5
vdr.c
View File

@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
* $Id: vdr.c 1.139 2002/12/13 14:30:00 kls Exp $
* $Id: vdr.c 1.140 2003/01/06 11:14:50 kls Exp $
*/
#include <getopt.h>
@ -468,6 +468,9 @@ int main(int argc, char *argv[])
Timer->SetPending(true);
}
}
// CAM control:
if (!Menu)
Menu = CamControl();
// User Input:
cOsdObject *Interact = Menu ? Menu : cControl::Control();
eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse());