/* * infosatepg.cpp: A plugin for the Video Disk Recorder * * See the README file for copyright information and how to reach the author. * * $Id$ */ #include #include #include #include #include #include #include #include "infosatepg.h" #include "setup.h" #include "process.h" #define UNUSED(v) UNUSED_ ## v __attribute__((unused)) extern char *strcatrealloc(char *dest, const char *src); // --- cPluginInfosatepg cPluginInfosatepg::cPluginInfosatepg(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! statusMonitor=NULL; global=new cGlobalInfosatepg; process=new cProcessInfosatepg(); pmac=EPG_FIRST_DAY_MAC; } cPluginInfosatepg::~cPluginInfosatepg() { // Clean up after yourself! if (statusMonitor) delete statusMonitor; delete process; delete global; } const char *cPluginInfosatepg::CommandLineHelp(void) { // Return a string that describes all known command line options. return " -d DIR, --dir=DIR use DIR as infosat data directory\n" " (default: /tmp)\n"; } bool cPluginInfosatepg::ProcessArgs(int argc, char *argv[]) { // Command line argument processing static struct option long_options[] = { { "dir", required_argument, NULL, 'd' }, { 0,0,0,0 } }; int c; while ((c = getopt_long(argc, argv, "d:", long_options, NULL)) != -1) { switch (c) { case 'd': if (global->SetDirectory(optarg)) { isyslog("infosatepg: using directory '%s' for data",optarg); } else { fprintf(stderr,"infosatepg: can't access data directory: %s\n", optarg); return false; } break; default: return false; } } return true; } bool cPluginInfosatepg::Initialize(void) { // Initialize plugin - check channellist tChannelID ChannelID; for (int i=0; iInfosatChannels(); i++) { ChannelID=global->GetChannelID(i); if (!Channels.GetByChannelID(ChannelID)) { dsyslog("infosatepg: remove %s",*ChannelID.ToString()); global->RemoveChannel(i); // Removing entries from setup.conf is not possible! } } if (!global->FindReceiverChannel()) esyslog("infosatepg: found no channel to receive, check setup"); return true; } bool cPluginInfosatepg::Start(void) { // Start any background activities the plugin shall perform if (global->Load()==-1) { isyslog("infosatepg: failed to load plugin status"); } statusMonitor = new cStatusInfosatepg(global); return true; } void cPluginInfosatepg::Stop(void) { // Stop any background activities the plugin is performing. process->Stop(); if (global->Save()==-1) { isyslog("infosatepg: failed to save plugin status"); } } void cPluginInfosatepg::Housekeeping(void) { // Perform any cleanup or other regular tasks. } void cPluginInfosatepg::MainThreadHook(void) { // Perform actions in the context of the main program thread. if (!global->WaitOk()) return; if ((global->Infosatdata[pmac].ReceivedAll()) && (!global->ProcessedAll())) { if (!global->Infosatdata[pmac].Processed) { if (!process->Active()) { isyslog ("infosatepg: found data to be processed: day=%i month=%i", global->Infosatdata[pmac].Day(),global->Infosatdata[pmac].Month()); process->SetInfo(pmac,global); process->Start(); } } else { pmac++; } global->SetWaitTimer(); } else { pmac=EPG_FIRST_DAY_MAC; } if ((global->Switched()) || (global->ReceivedAll()) || (global->Channel()==-1)) return; cChannel *chan=Channels.GetByNumber(global->Channel()); if (!chan) return; if (ShutdownHandler.IsUserInactive()) { // only switch primary device if we are not recording if (!cDevice::PrimaryDevice()->Receiving()) { // first keep the current channel in "mind" if (global->LastCurrentChannel==-1) global->LastCurrentChannel= cDevice::PrimaryDevice()->CurrentChannel(); // we are idle -> try to use live device if we can if (cDevice::PrimaryDevice()->SwitchChannel(chan,true)) { global->SetWaitTimer(); return; } } } if (global->LastCurrentChannel!=-1) global->LastCurrentChannel=-1; // Cannot use live device try another (if possible) for (int i=0; iProvidesTransponder(chan)) continue; // device cannot provide transponder -> skip if (EITScanner.UsesDevice(dev)) continue; // EITScanner is updating EPG -> skip if (dev->Receiving()) continue; // device is recording -> skip if (dev->IsPrimaryDevice()) continue; // device is primary -> skip if (cDevice::ActualDevice()->CardIndex()==i) continue; // device is live viewing -> skip if (dev->IsTunedToTransponder(chan)) { // we already have a device which is tuned (maybe switched manually?) // the filter will be added in status.cpp global->SetWaitTimer(); return; } // ok -> use this device dsyslog("infosatepg: found free device %i",dev->DeviceNumber()+1); dev->SwitchChannel(chan,false); global->SetWaitTimer(); return; } } } cString cPluginInfosatepg::Active(void) { // Returns a message string if we are not ready if (global->NoDeferredShutdown) return NULL; // if we cannot receive, we shouldn't wait if (global->Channel()==-1) return NULL; if (!global->ProcessedAll()) return tr("Infosat plugin still working"); // we are done if (global->LastCurrentChannel!=-1) { // we switched from users last channel if (cDevice::PrimaryDevice()->CurrentChannel()==global->Channel()) { // we are still on infosatepg channel cChannel *chan=Channels.GetByNumber(global->LastCurrentChannel); if (chan) { // switch back to users last viewed channel cDevice::PrimaryDevice()->SwitchChannel(chan,true); global->LastCurrentChannel=-1; } } } return NULL; } time_t cPluginInfosatepg::WakeupTime(void) { // Returns custom wakeup time for shutdown script if (global->NoWakeup) return 0; // user option set -> don't wake up if (global->Channel()==-1) return 0; // we cannot receive, so we don't need to wake up if (global->WakeupTime()==-1) { // no wakeup? set wakeup to 03:00 global->SetWakeupTime(cTimer::SetTime(time(NULL),cTimer::TimeToInt(300))); } time_t Now = time(NULL); time_t Time = global->WakeupTime(); if (difftime(Time,Now)<0) { // wakeup time is in the past -> add a day Time = cTimer::IncDay(Time,1); } return Time; } const char *cPluginInfosatepg::MainMenuEntry(void) { if (global->HideMainMenu) return NULL; double overall=0; for (int mac=EPG_FIRST_DAY_MAC; mac<=EPG_LAST_DAY_MAC; mac++) { overall+=global->Infosatdata[mac].ReceivedPercent()*0.9; if (global->Infosatdata[mac].Processed) overall+=10; } overall/=EPG_LAST_DAY_MAC; static char buffer[1024]; snprintf(buffer,sizeof(buffer)-1,"%s (%0.f%%)", tr("Menu$infosatepg"), overall); return buffer; } cOsdObject *cPluginInfosatepg::MainMenuAction(void) { // Perform the action when selected from the main VDR menu. return NULL; } cMenuSetupPage *cPluginInfosatepg::SetupMenu(void) { // Return the setup menu. return new cMenuSetupInfosatepg(global); } bool cPluginInfosatepg::SetupParse(const char *Name, const char *Value) { // Parse your own setup parameters and store their values. if (!strcasecmp(Name,"Pid")) global->Pid=atoi(Value); else if (!strcasecmp(Name,"Frequency")) global->Frequency=atoi(Value); else if (!strcasecmp(Name,"Polarization")) global->Polarization=atoi(Value); else if (!strcasecmp(Name,"Srate")) global->Srate=atoi(Value); else if (!strcasecmp(Name,"NoWakeup")) global->NoWakeup=atoi(Value); else if (!strcasecmp(Name,"NoDeferredShutdown")) global->NoDeferredShutdown=atoi(Value); else if (!strcasecmp(Name,"HideMainMenu")) global->HideMainMenu=atoi(Value); else if (!strcasecmp(Name,"WaitTime")) global->WaitTime=atoi(Value); else if (!strncasecmp(Name,"Channel",7)) { if (strlen(Name)<10) return false; tChannelID ChannelID=tChannelID::FromString(&Name[8]); if (ChannelID==tChannelID::InvalidID) return false; int val=atoi(Value); global->AddChannel(ChannelID,(val & 0xFFFF),(val & 0xF0000)>>16); } else return false; return true; } bool cPluginInfosatepg::Service(const char *UNUSED(Id), void *UNUSED(Data)) { // Handle custom service requests from other plugins return false; } const char **cPluginInfosatepg::SVDRPHelpPages(void) { // Returns help text for SVDRP static const char *HelpPages[] = { "STAT\n" " Return actual state of the plugin", "RESR\n" " Reset received all", "REPR\n" " Reprocess again", "SAVE\n", " Save state of plugin", NULL }; return HelpPages; } cString cPluginInfosatepg::SVDRPCommand(const char *Command, const char *UNUSED(Option), int &UNUSED(ReplyCode)) { // Process SVDRP commands cString output; if (!strcasecmp(Command,"RESR")) { global->ResetReceivedAll(); pmac=EPG_FIRST_DAY_MAC; output="Restarted receiver\n"; } if (!strcasecmp(Command,"REPR")) { global->ResetProcessed(); pmac=EPG_FIRST_DAY_MAC; output="Reprocess files\n"; } if (!strcasecmp(Command,"SAVE")) { global->Save(); output="State saved\n"; } if (!strcasecmp(Command,"STAT")) { int day,month; cString head=cString::sprintf("InfosatEPG state:\n Switched: %s",global->Switched() ? "yes" : "no"); cString lcc; if (global->LastCurrentChannel!=-1) { lcc=cString::sprintf(" Switchback to: %i\n", global->LastCurrentChannel); } else { lcc=" Switchback to: unset\n"; } cString rall; if (global->ReceivedAll(&day,&month)) rall=cString::sprintf(" Received all: yes (%02i.%02i.)",day,month); else rall=" Received all: no"; cString pall; pall=cString::sprintf(" Processed all: %s\n Prevent shutdown until ready: %s\n", global->ProcessedAll() ? "yes" : "no", global->NoDeferredShutdown ? "no" : "yes"); cString wut; if (global->WakeupTime()!=-1) { time_t wakeup = global->WakeupTime(); wut=cString::sprintf(" WakeupTime: %s %s",ctime(&wakeup),global->NoWakeup ? "(blocked)" : ""); } else { wut="%s WakeupTime: unset\n"; } cString head2; head2="\n" \ " | | missed | | | unlocated\n" \ " Day | Date | Packets | Received %% | Processed | Events\n" \ "------+--------+---------+------------+------------+----------\n"; cString mstr; char *fmstr=NULL; for (int mac=EPG_FIRST_DAY_MAC; mac<=EPG_LAST_DAY_MAC; mac++) { mstr=cString::sprintf("%c %i | %02i.%02i. | %3i | %3i | %s | %3i\n", (global->ActualMac==mac) ? '*' : ' ', mac,global->Infosatdata[mac].Day(), global->Infosatdata[mac].Month(), global->Infosatdata[mac].Missed(), global->Infosatdata[mac].ReceivedPercent(), global->Infosatdata[mac].Processed ? "yes" : " no", global->Infosatdata[mac].Unlocated); fmstr=strcatrealloc(fmstr,mstr); } output=cString::sprintf("%s%s%s%s%s%s%s",*head,*lcc,*rall,*pall,*wut,*head2,fmstr); } return output; } VDRPLUGINCREATOR(cPluginInfosatepg); // Don't touch this!