2002-12-01 11:25:22 +01:00
|
|
|
/*
|
|
|
|
* sky.c: A plugin for the Video Disk Recorder
|
|
|
|
*
|
|
|
|
* See the README file for copyright information and how to reach the author.
|
|
|
|
*
|
2004-12-17 14:55:49 +01:00
|
|
|
* $Id: sky.c 1.8 2004/12/12 14:27:33 kls Exp $
|
2002-12-01 11:25:22 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <vdr/plugin.h>
|
|
|
|
#include <vdr/sources.h>
|
|
|
|
|
2004-12-17 14:55:49 +01:00
|
|
|
static const char *VERSION = "0.3.2";
|
2002-12-01 11:25:22 +01:00
|
|
|
static const char *DESCRIPTION = "Sky Digibox interface";
|
|
|
|
|
|
|
|
// --- cDigiboxDevice --------------------------------------------------------
|
|
|
|
|
2004-02-15 13:35:52 +01:00
|
|
|
#define DUMMYAPID 80
|
|
|
|
#define DUMMYVPID 160
|
|
|
|
|
|
|
|
class cSkyChannel : public cListObject {
|
|
|
|
public:
|
|
|
|
tChannelID channelID;
|
|
|
|
int digiboxChannelNumber;
|
|
|
|
bool Parse(const char *s);
|
|
|
|
};
|
|
|
|
|
|
|
|
bool cSkyChannel::Parse(const char *s)
|
|
|
|
{
|
|
|
|
char *id = NULL;
|
|
|
|
if (2 == sscanf(s, "%a[^:]:%d", &id, &digiboxChannelNumber))
|
|
|
|
channelID = tChannelID::FromString(id);
|
|
|
|
free(id);
|
|
|
|
return digiboxChannelNumber && channelID.Valid();
|
|
|
|
}
|
|
|
|
|
|
|
|
class cSkyChannels : public cConfig<cSkyChannel> {
|
|
|
|
public:
|
|
|
|
cSkyChannel *GetSkyChannel(const cChannel *Channel);
|
|
|
|
};
|
|
|
|
|
|
|
|
cSkyChannel *cSkyChannels::GetSkyChannel(const cChannel *Channel)
|
|
|
|
{
|
|
|
|
tChannelID ChannelID = Channel->GetChannelID();
|
|
|
|
for (cSkyChannel *sc = First(); sc; sc = Next(sc)) {
|
|
|
|
if (ChannelID == sc->channelID)
|
|
|
|
return sc;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cSkyChannels SkyChannels;
|
|
|
|
|
2002-12-01 11:25:22 +01:00
|
|
|
class cDigiboxDevice : public cDevice {
|
|
|
|
private:
|
|
|
|
int source;
|
|
|
|
int digiboxChannelNumber;
|
|
|
|
int fd_dvr;
|
2004-02-15 13:35:52 +01:00
|
|
|
int apid, vpid;
|
2002-12-01 11:25:22 +01:00
|
|
|
cTSBuffer *tsBuffer;
|
|
|
|
int fd_lirc;
|
|
|
|
void LircSend(const char *s);
|
|
|
|
void LircSend(int n);
|
|
|
|
protected:
|
|
|
|
virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
|
|
|
|
virtual bool OpenDvr(void);
|
|
|
|
virtual void CloseDvr(void);
|
|
|
|
virtual bool GetTSPacket(uchar *&Data);
|
|
|
|
public:
|
|
|
|
cDigiboxDevice(void);
|
|
|
|
virtual ~cDigiboxDevice();
|
|
|
|
virtual bool ProvidesSource(int Source) const;
|
2004-01-04 12:30:00 +01:00
|
|
|
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
2002-12-01 11:25:22 +01:00
|
|
|
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSetChannel = NULL) const;
|
|
|
|
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
|
|
|
};
|
|
|
|
|
|
|
|
cDigiboxDevice::cDigiboxDevice(void)
|
|
|
|
{
|
|
|
|
source = cSource::FromString("S28.2E");//XXX parameter???
|
|
|
|
digiboxChannelNumber = 0;
|
|
|
|
fd_dvr = -1;
|
2004-02-15 13:35:52 +01:00
|
|
|
apid = vpid = 0;
|
2002-12-01 11:25:22 +01:00
|
|
|
struct sockaddr_un addr;
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
strn0cpy(addr.sun_path, "/dev/lircd", sizeof(addr.sun_path));//XXX parameter???
|
|
|
|
fd_lirc = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
if (fd_lirc >= 0) {
|
|
|
|
if (connect(fd_lirc, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
|
|
LOG_ERROR;
|
|
|
|
close(fd_lirc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
LOG_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
cDigiboxDevice::~cDigiboxDevice()
|
|
|
|
{
|
|
|
|
if (fd_lirc >= 0)
|
|
|
|
close(fd_lirc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cDigiboxDevice::LircSend(const char *s)
|
|
|
|
{
|
|
|
|
const char *c = "SEND_ONCE SKY %s\n";
|
|
|
|
char buf[100];
|
|
|
|
sprintf(buf, c, s);
|
|
|
|
dsyslog(buf);//XXX
|
|
|
|
if (write(fd_lirc, buf, strlen(buf)) < 0)
|
|
|
|
LOG_ERROR;//XXX _STR
|
|
|
|
delay_ms(200);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cDigiboxDevice::LircSend(int n)
|
|
|
|
{
|
|
|
|
char buf[10];
|
|
|
|
snprintf(buf, sizeof(buf), "%d", n);
|
|
|
|
char *p = buf;
|
|
|
|
while (*p) {
|
|
|
|
char q[10];
|
|
|
|
sprintf(q, "%c", *p);
|
|
|
|
LircSend(q);
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cDigiboxDevice::SetPid(cPidHandle *Handle, int Type, bool On)
|
|
|
|
{
|
2004-02-15 13:35:52 +01:00
|
|
|
//dsyslog("SetPid %d %d", Handle->pid, On);
|
2002-12-01 11:25:22 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cDigiboxDevice::OpenDvr(void)
|
|
|
|
{
|
|
|
|
CloseDvr();
|
|
|
|
fd_dvr = open("/dev/video2", O_RDONLY | O_NONBLOCK);//XXX parameter???
|
|
|
|
if (fd_dvr >= 0)
|
2004-10-16 09:36:28 +02:00
|
|
|
tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(2), CardIndex() + 1);
|
2002-12-01 11:25:22 +01:00
|
|
|
return fd_dvr >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cDigiboxDevice::CloseDvr(void)
|
|
|
|
{
|
|
|
|
if (fd_dvr >= 0) {
|
|
|
|
close(fd_dvr);
|
|
|
|
fd_dvr = -1;
|
|
|
|
delete tsBuffer;
|
|
|
|
tsBuffer = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cDigiboxDevice::GetTSPacket(uchar *&Data)
|
|
|
|
{
|
|
|
|
if (tsBuffer) {
|
2004-10-16 09:36:28 +02:00
|
|
|
Data = tsBuffer->Get();
|
|
|
|
if (Data) {
|
|
|
|
// insert the actual PIDs:
|
|
|
|
int Pid = (((uint16_t)Data[1] & PID_MASK_HI) << 8) | Data[2];
|
|
|
|
if (Pid == DUMMYAPID)
|
|
|
|
Pid = apid;
|
|
|
|
else if (Pid == DUMMYVPID)
|
|
|
|
Pid = vpid;
|
|
|
|
Data[1] = ((Pid >> 8) & 0xFF) | (Data[1] & ~PID_MASK_HI);
|
|
|
|
Data[2] = Pid & 0xFF;
|
2002-12-01 11:25:22 +01:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cDigiboxDevice::ProvidesSource(int Source) const
|
|
|
|
{
|
|
|
|
return source == Source;
|
|
|
|
}
|
|
|
|
|
2004-01-04 12:30:00 +01:00
|
|
|
bool cDigiboxDevice::ProvidesTransponder(const cChannel *Channel) const
|
|
|
|
{
|
|
|
|
return false; // can't provide any actual transponder
|
|
|
|
}
|
|
|
|
|
2002-12-01 11:25:22 +01:00
|
|
|
bool cDigiboxDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
|
|
|
{
|
|
|
|
bool result = false;
|
|
|
|
bool hasPriority = Priority < 0 || Priority > this->Priority();
|
|
|
|
bool needsDetachReceivers = true;
|
|
|
|
|
2004-02-15 13:35:52 +01:00
|
|
|
cSkyChannel *SkyChannel = SkyChannels.GetSkyChannel(Channel);
|
|
|
|
if (SkyChannel) {
|
2004-02-15 15:07:27 +01:00
|
|
|
if (Receiving(true)) {
|
2004-02-15 13:35:52 +01:00
|
|
|
if (digiboxChannelNumber == SkyChannel->digiboxChannelNumber) {
|
2002-12-01 11:25:22 +01:00
|
|
|
needsDetachReceivers = false;
|
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result = hasPriority;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result = hasPriority;
|
|
|
|
}
|
|
|
|
if (NeedsDetachReceivers)
|
|
|
|
*NeedsDetachReceivers = needsDetachReceivers;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cDigiboxDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|
|
|
{
|
2004-02-15 15:07:27 +01:00
|
|
|
if (fd_lirc >= 0 && !Receiving(true)) { // if we are receiving the channel is already set!
|
2004-02-15 13:35:52 +01:00
|
|
|
cSkyChannel *SkyChannel = SkyChannels.GetSkyChannel(Channel);
|
|
|
|
if (SkyChannel) {
|
|
|
|
digiboxChannelNumber = SkyChannel->digiboxChannelNumber;
|
2004-12-17 14:55:49 +01:00
|
|
|
apid = Channel->Apid(0);
|
2004-02-15 13:35:52 +01:00
|
|
|
vpid = Channel->Vpid();
|
|
|
|
//XXX only when recording??? -> faster channel switching!
|
|
|
|
LircSend("SKY"); // makes sure the Digibox is "on"
|
|
|
|
//XXX lircprint(fd_lirc, "BACKUP");
|
|
|
|
//XXX lircprint(fd_lirc, "BACKUP");
|
|
|
|
//XXX lircprint(fd_lirc, "BACKUP");
|
|
|
|
LircSend(digiboxChannelNumber);
|
|
|
|
}
|
2002-12-01 11:25:22 +01:00
|
|
|
}
|
2004-02-15 13:35:52 +01:00
|
|
|
return true;
|
2002-12-01 11:25:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// --- cPluginSky ------------------------------------------------------------
|
|
|
|
|
|
|
|
class cPluginSky : public cPlugin {
|
|
|
|
private:
|
|
|
|
// Add any member variables or functions you may need here.
|
|
|
|
public:
|
|
|
|
cPluginSky(void);
|
|
|
|
virtual ~cPluginSky();
|
|
|
|
virtual const char *Version(void) { return VERSION; }
|
|
|
|
virtual const char *Description(void) { return DESCRIPTION; }
|
|
|
|
virtual const char *CommandLineHelp(void);
|
|
|
|
virtual bool ProcessArgs(int argc, char *argv[]);
|
2003-05-09 15:27:46 +02:00
|
|
|
virtual bool Initialize(void);
|
2002-12-01 11:25:22 +01:00
|
|
|
virtual void Housekeeping(void);
|
|
|
|
virtual cMenuSetupPage *SetupMenu(void);
|
|
|
|
virtual bool SetupParse(const char *Name, const char *Value);
|
|
|
|
};
|
|
|
|
|
|
|
|
cPluginSky::cPluginSky(void)
|
|
|
|
{
|
|
|
|
// Initialize any member variables here.
|
|
|
|
// DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
|
|
|
|
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
|
|
|
|
}
|
|
|
|
|
|
|
|
cPluginSky::~cPluginSky()
|
|
|
|
{
|
|
|
|
// Clean up after yourself!
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *cPluginSky::CommandLineHelp(void)
|
|
|
|
{
|
|
|
|
// Return a string that describes all known command line options.
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cPluginSky::ProcessArgs(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
// Implement command line argument processing here if applicable.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2003-05-09 15:27:46 +02:00
|
|
|
bool cPluginSky::Initialize(void)
|
2002-12-01 11:25:22 +01:00
|
|
|
{
|
2003-05-09 15:27:46 +02:00
|
|
|
// Initialize any background activities the plugin shall perform.
|
2004-02-15 13:35:52 +01:00
|
|
|
const char *ConfigDir = ConfigDirectory(Name());
|
|
|
|
if (ConfigDir) {
|
|
|
|
if (SkyChannels.Load(AddDirectory(ConfigDir, "channels.conf.sky"), true)) {
|
|
|
|
new cDigiboxDevice;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
esyslog("ERROR: can't get config directory");
|
|
|
|
return false;
|
2002-12-01 11:25:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void cPluginSky::Housekeeping(void)
|
|
|
|
{
|
|
|
|
// Perform any cleanup or other regular tasks.
|
|
|
|
}
|
|
|
|
|
|
|
|
cMenuSetupPage *cPluginSky::SetupMenu(void)
|
|
|
|
{
|
|
|
|
// Return a setup menu in case the plugin supports one.
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cPluginSky::SetupParse(const char *Name, const char *Value)
|
|
|
|
{
|
|
|
|
// Parse your own setup parameters and store their values.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
VDRPLUGINCREATOR(cPluginSky); // Don't touch this!
|