vdr  2.7.6
eitscan.c
Go to the documentation of this file.
1 /*
2  * eitscan.c: EIT scanner
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: eitscan.c 5.8 2025/03/02 11:03:35 kls Exp $
8  */
9 
10 #include "eitscan.h"
11 #include <stdlib.h>
12 #include "channels.h"
13 #include "dvbdevice.h"
14 #include "skins.h"
15 #include "transfer.h"
16 
17 // --- cScanData -------------------------------------------------------------
18 
19 class cScanData : public cListObject {
20 private:
22 public:
23  cScanData(const cChannel *Channel);
24  virtual int Compare(const cListObject &ListObject) const override;
25  int Source(void) const { return channel.Source(); }
26  int Transponder(void) const { return channel.Transponder(); }
27  const cChannel *GetChannel(void) const { return &channel; }
28  };
29 
31 {
32  channel = *Channel;
33 }
34 
35 int cScanData::Compare(const cListObject &ListObject) const
36 {
37  const cScanData *sd = (const cScanData *)&ListObject;
38  int r = Source() - sd->Source();
39  if (r == 0)
40  r = Transponder() - sd->Transponder();
41  return r;
42 }
43 
44 // --- cScanList -------------------------------------------------------------
45 
46 class cScanList : public cList<cScanData> {
47 private:
48  bool HasDeviceForChannelEIT(const cChannel *Channel) const;
49 public:
50  void AddTransponders(const cList<cChannel> *Channels);
51  void AddTransponder(const cChannel *Channel);
52  };
53 
54 bool cScanList::HasDeviceForChannelEIT(const cChannel *Channel) const
55 {
56  for (int i = 0; i < cDevice::NumDevices(); i++) {
57  cDevice *Device = cDevice::GetDevice(i);
58  if (Device && Device->ProvidesEIT() && Device->ProvidesTransponder(Channel))
59  return true;
60  }
61  return false;
62 }
63 
65 {
66  for (const cChannel *ch = Channels->First(); ch; ch = Channels->Next(ch))
67  AddTransponder(ch);
68  Sort();
69 }
70 
71 void cScanList::AddTransponder(const cChannel *Channel)
72 {
73  if (Channel->Source() && Channel->Transponder() && (Setup.EPGScanMaxChannel <= 0 || Channel->Number() < Setup.EPGScanMaxChannel)) {
74  if (!HasDeviceForChannelEIT(Channel))
75  return;
76  for (cScanData *sd = First(); sd; sd = Next(sd)) {
77  if (sd->Source() == Channel->Source() && ISTRANSPONDER(sd->Transponder(), Channel->Transponder()))
78  return;
79  }
80  Add(new cScanData(Channel));
81  }
82 }
83 
84 // --- cTransponderList ------------------------------------------------------
85 
86 class cTransponderList : public cList<cChannel> {
87 public:
88  void AddTransponder(cChannel *Channel);
89  };
90 
92 {
93  for (cChannel *ch = First(); ch; ch = Next(ch)) {
94  if (ch->Source() == Channel->Source() && ch->Transponder() == Channel->Transponder()) {
95  delete Channel;
96  return;
97  }
98  }
99  Add(Channel);
100 }
101 
102 // --- cEITScanner -----------------------------------------------------------
103 
105 
107 {
108  paused = false;
109  lastScan = 0;
110  lastActivity = time(NULL);
111  currentChannel = 0;
112  scanList = new cScanList;
113  transponderList = NULL;
114 }
115 
117 {
118  delete scanList;
119  delete transponderList;
120 }
121 
123 {
124  if (!transponderList)
127 }
128 
130 {
131  lastActivity = 0;
132 }
133 
135 {
136  if (currentChannel) {
138  Channels->SwitchTo(currentChannel);
139  currentChannel = 0;
140  }
141  lastActivity = time(NULL);
142 }
143 
145 {
146  if (Setup.EPGScanTimeout || !lastActivity) { // !lastActivity means a scan was forced
147  time_t now = time(NULL);
148  if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
149  if (Setup.EPGPauseAfterScan && scanList->Count() == 0 && lastActivity && lastScan && now - lastScan < Setup.EPGScanTimeout * 3600) {
150  if (!paused) {
151  dsyslog("pause EPG scan");
152  paused = true;
153  }
154  // Allow unused devices to go into power save mode:
155  if ((now - lastScan) % 10 == 0) { // let's not do this too often
156  for (int i = 0; i < cDevice::NumDevices(); i++) {
157  if (cDevice *Device = cDevice::GetDevice(i))
158  Device->SetPowerSaveIfUnused();
159  }
160  }
161  return; // pause for Setup.EPGScanTimeout hours
162  }
163  else if (paused) {
164  dsyslog("start EPG scan");
165  paused = false;
166  }
167  cStateKey StateKey;
168  if (const cChannels *Channels = cChannels::GetChannelsRead(StateKey, 10)) {
169  if (scanList->Count() == 0) {
170  if (transponderList) {
172  delete transponderList;
173  transponderList = NULL;
174  }
175  scanList->AddTransponders(Channels);
176  //dsyslog("EIT scan: %d scanList entries", scanList->Count());
177  }
178  for (int i = 0; i < cDevice::NumDevices(); i++) {
179  cDevice *Device = cDevice::GetDevice(i);
180  if (Device && Device->ProvidesEIT()) {
181  cScanData *Next = NULL;
182  for (cScanData *ScanData = scanList->First(); ScanData; ScanData = Next) {
183  Next = scanList->Next(ScanData);
184  const cChannel *Channel = ScanData->GetChannel();
185  if (Channel) {
186  if (Device->IsTunedToTransponder(Channel))
187  scanList->Del(ScanData);
188  else if (!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= CA_ENCRYPTED_MIN) {
189  if (Device->ProvidesTransponder(Channel)) {
190  if (Device->Priority() < 0) {
191  if (const cPositioner *Positioner = Device->Positioner()) {
192  if (Positioner->LastLongitude() != cSource::Position(Channel->Source()))
193  continue;
194  }
195  bool MaySwitchTransponder = Device->MaySwitchTransponder(Channel);
196  if (MaySwitchTransponder || Device->ProvidesTransponderExclusively(Channel) && now - lastActivity > Setup.EPGScanTimeout * 3600) {
197  if (!MaySwitchTransponder) {
198  if (Device == cDevice::ActualDevice() && !currentChannel) {
199  cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode
200  currentChannel = Device->CurrentChannel();
201  Skins.Message(mtInfo, tr("Starting EPG scan"));
202  }
203  }
204  //dsyslog("EIT scan: %d device %d source %-8s tp %5d", scanList->Count(), Device->DeviceNumber() + 1, *cSource::ToString(Channel->Source()), Channel->Transponder());
205  Device->SwitchChannel(Channel, false);
206  scanList->Del(ScanData);
207  break;
208  }
209  }
210  }
211  }
212  }
213  }
214  }
215  }
216  if (scanList->Count() == 0) {
217  if (lastActivity == 0) // this was a triggered scan
218  Activity();
219  }
220  StateKey.Remove();
221  }
222  lastScan = time(NULL);
223  }
224  }
225 }
#define CA_ENCRYPTED_MIN
Definition: channels.h:44
#define LOCK_CHANNELS_READ
Definition: channels.h:273
#define ISTRANSPONDER(f1, f2)
Definition: channels.h:18
int Source(void) const
Definition: channels.h:154
int Number(void) const
Definition: channels.h:181
int Ca(int Index=0) const
Definition: channels.h:175
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition: channels.c:155
static const cChannels * GetChannelsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for read access.
Definition: channels.c:857
int Priority(bool IgnoreOccupied=false) const
Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY),...
Definition: device.c:1714
virtual const cPositioner * Positioner(void) const
Returns a pointer to the positioner (if any) this device has used to move the satellite dish to the r...
Definition: device.c:780
static cDevice * ActualDevice(void)
Returns the actual receiving device in case of Transfer Mode, or the primary device otherwise.
Definition: device.c:222
virtual bool MaySwitchTransponder(const cChannel *Channel) const
Returns true if it is ok to switch to the Channel's transponder on this device, without disturbing an...
Definition: device.c:810
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition: device.c:230
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition: device.c:825
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition: device.c:167
virtual bool ProvidesEIT(void) const
Returns true if this device provides EIT data and thus wants to be tuned to the channels it can recei...
Definition: device.c:770
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition: device.h:371
void StopReplay(void)
Stops the current replay session (if any).
Definition: device.c:1434
virtual bool ProvidesTransponderExclusively(const cChannel *Channel) const
Returns true if this is the only device that is able to provide the given channel's transponder.
Definition: device.c:756
static int NumDevices(void)
Returns the total number of devices.
Definition: device.h:129
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
Definition: device.c:805
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:148
virtual bool ProvidesTransponder(const cChannel *Channel) const
Returns true if this device can provide the transponder of the given Channel (which implies that it c...
Definition: device.c:751
int currentChannel
Definition: eitscan.h:28
cEITScanner(void)
Definition: eitscan.c:106
void AddTransponder(cChannel *Channel)
Definition: eitscan.c:122
@ ScanTimeout
Definition: eitscan.h:24
@ ActivityTimeout
Definition: eitscan.h:23
bool paused
Definition: eitscan.h:26
void ForceScan(void)
Definition: eitscan.c:129
void Process(void)
Definition: eitscan.c:144
cScanList * scanList
Definition: eitscan.h:29
time_t lastActivity
Definition: eitscan.h:27
~cEITScanner()
Definition: eitscan.c:116
cTransponderList * transponderList
Definition: eitscan.h:30
void Activity(void)
Definition: eitscan.c:134
time_t lastScan
Definition: eitscan.h:27
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:2209
int Count(void) const
Definition: tools.h:627
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2177
void Sort(void)
Definition: tools.c:2301
Definition: tools.h:631
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition: tools.h:650
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition: tools.h:643
A steerable satellite dish generally points to the south on the northern hemisphere,...
Definition: positioner.h:31
const cChannel * GetChannel(void) const
Definition: eitscan.c:27
int Transponder(void) const
Definition: eitscan.c:26
int Source(void) const
Definition: eitscan.c:25
cChannel channel
Definition: eitscan.c:21
cScanData(const cChannel *Channel)
Definition: eitscan.c:30
virtual int Compare(const cListObject &ListObject) const override
Must return 0 if this object is equal to ListObject, a positive value if it is "greater",...
Definition: eitscan.c:35
bool HasDeviceForChannelEIT(const cChannel *Channel) const
Definition: eitscan.c:54
void AddTransponder(const cChannel *Channel)
Definition: eitscan.c:71
void AddTransponders(const cList< cChannel > *Channels)
Definition: eitscan.c:64
int EPGPauseAfterScan
Definition: config.h:307
int EPGScanMaxChannel
Definition: config.h:306
int EPGScanTimeout
Definition: config.h:308
eKeys Message(eMessageType Type, const char *s, int Seconds=0)
Displays the given message, either through a currently visible display object that is capable of doin...
Definition: skins.c:284
int Position(void)
Returns the orbital position of the satellite in case this is a DVB-S source (zero otherwise).
Definition: sources.h:35
void Remove(bool IncState=true)
Removes this key from the lock it was previously used with.
Definition: thread.c:869
void AddTransponder(cChannel *Channel)
Definition: eitscan.c:91
cSetup Setup
Definition: config.c:372
cEITScanner EITScanner
Definition: eitscan.c:104
#define tr(s)
Definition: i18n.h:85
cSkins Skins
Definition: skins.c:253
@ mtInfo
Definition: skins.h:37
#define dsyslog(a...)
Definition: tools.h:37