MythTV  0.28pre
cardutil.cpp
Go to the documentation of this file.
1 // Standard UNIX C headers
2 #include <fcntl.h>
3 #include <unistd.h>
4 
5 #include <algorithm>
6 
7 #if defined(USING_V4L2) || defined(USING_DVB)
8 #include <sys/ioctl.h>
9 #endif
10 
11 // Qt headers
12 #include <QMap>
13 #include <QDir>
14 
15 // MythTV headers
16 #include "mythconfig.h"
17 #include "cardutil.h"
18 #include "videosource.h"
19 #include "dvbchannel.h"
20 #include "diseqcsettings.h"
21 #include "sourceutil.h"
22 #include "mythdb.h"
23 #include "mythlogging.h"
24 
25 #ifdef USING_DVB
26 #include "dvbtypes.h"
27 #endif
28 
29 #ifdef USING_V4L1
30 #include <linux/videodev.h>
31 #endif
32 
33 #ifdef USING_V4L2
34 #include <linux/videodev2.h>
35 #endif
36 
37 #ifdef USING_HDHOMERUN
38 #include "hdhomerun.h"
39 #endif
40 
41 #ifdef USING_VBOX
42 #include "vboxutils.h"
43 #endif
44 
45 #ifdef USING_ASI
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <dveo/asi.h>
49 #include <dveo/master.h>
50 #endif
51 
52 #define LOC QString("CardUtil: ")
53 
55 {
56  QString cardTypes = "";
57 
58 #ifdef USING_DVB
59  cardTypes += "'DVB'";
60 #endif // USING_DVB
61 
62 #ifdef USING_V4L2
63  if (!cardTypes.isEmpty())
64  cardTypes += ",";
65  cardTypes += "'V4L'";
66 # ifdef USING_IVTV
67  cardTypes += ",'MPEG'";
68 # endif // USING_IVTV
69 #endif // USING_V4L2
70 
71 #ifdef USING_IPTV
72  if (!cardTypes.isEmpty())
73  cardTypes += ",";
74  cardTypes += "'FREEBOX'";
75 #endif // USING_IPTV
76 
77 #ifdef USING_VBOX
78  if (!cardTypes.isEmpty())
79  cardTypes += ",";
80  cardTypes += "'VBOX'";
81 #endif // USING_VBOX
82 
83 #ifdef USING_HDHOMERUN
84  if (!cardTypes.isEmpty())
85  cardTypes += ",";
86  cardTypes += "'HDHOMERUN'";
87 #endif // USING_HDHOMERUN
88 
89 #ifdef USING_ASI
90  if (!cardTypes.isEmpty())
91  cardTypes += ",";
92  cardTypes += "'ASI'";
93 #endif
94 
95 #ifdef USING_CETON
96  if (!cardTypes.isEmpty())
97  cardTypes += ",";
98  cardTypes += "'CETON'";
99 #endif // USING_CETON
100 
101 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
102  if (!cardTypes.isEmpty())
103  cardTypes += ",";
104  cardTypes += "'EXTERNAL'";
105 #endif
106 
107  if (cardTypes.isEmpty())
108  cardTypes = "'DUMMY'";
109 
110  return QString("(%1)").arg(cardTypes);
111 }
112 
114  const QString &cardType)
115 {
116  if (cardType == "HDHOMERUN")
117  {
118 #ifdef USING_HDHOMERUN
119  hdhomerun_device_t *hdhr;
120  hdhomerun_tuner_status_t status;
121  QString device = GetVideoDevice(cardid);
122  hdhr = hdhomerun_device_create_from_str(device.toLatin1(), NULL);
123  if (!hdhr)
124  return false;
125 
126  int oob = -1;
127  oob = hdhomerun_device_get_oob_status(hdhr, NULL, &status);
128 
129  // if no OOB tuner, oob will be < 1. If no CC present, OOB
130  // status will be "none."
131  if (oob > 0 && (strncmp(status.channel, "none", 4) != 0))
132  {
133  LOG(VB_GENERAL, LOG_INFO, "Cardutil: HDHomeRun Cablecard Present.");
134  hdhomerun_device_destroy(hdhr);
135  return true;
136  }
137 
138  hdhomerun_device_destroy(hdhr);
139 
140 #endif
141  return false;
142  }
143  else if (cardType == "CETON")
144  {
145 #ifdef USING_CETON
146  // TODO FIXME implement detection of Cablecard presence
147  LOG(VB_GENERAL, LOG_INFO, "Cardutil: TODO Ceton Is Cablecard Present?");
148  return true;
149 #else
150  return false;
151 #endif
152  }
153  else
154  return false;
155 }
156 
157 bool CardUtil::IsTunerShared(uint cardidA, uint cardidB)
158 {
159  LOG(VB_GENERAL, LOG_DEBUG, QString("IsTunerShared(%1,%2)")
160  .arg(cardidA).arg(cardidB));
161 
162  MSqlQuery query(MSqlQuery::InitCon());
163  query.prepare("SELECT videodevice, hostname, cardtype "
164  "FROM capturecard "
165  "WHERE ( (cardid = :CARDID_A) OR "
166  " (cardid = :CARDID_B) )");
167  query.bindValue(":CARDID_A", cardidA);
168  query.bindValue(":CARDID_B", cardidB);
169 
170  if (!query.exec())
171  {
172  MythDB::DBError("CardUtil::is_tuner_shared", query);
173  return false;
174  }
175 
176  if (!query.next())
177  return false;
178 
179  const QString vdevice = query.value(0).toString();
180  const QString hostname = query.value(1).toString();
181  const QString cardtype = query.value(2).toString();
182 
183  if (!IsTunerSharingCapable(cardtype.toUpper()))
184  return false;
185 
186  if (!query.next())
187  return false;
188 
189  bool ret = ((vdevice == query.value(0).toString()) &&
190  (hostname == query.value(1).toString()) &&
191  (cardtype == query.value(2).toString()));
192 
193  LOG(VB_RECORD, LOG_DEBUG, QString("IsTunerShared(%1,%2) -> %3")
194  .arg(cardidA).arg(cardidB).arg(ret));
195 
196  return ret;
197 }
198 
204 bool CardUtil::IsCardTypePresent(const QString &rawtype, QString hostname)
205 {
206  if (hostname.isEmpty())
207  hostname = gCoreContext->GetHostName();
208 
209  MSqlQuery query(MSqlQuery::InitCon());
210  QString qstr =
211  "SELECT count(cardtype) "
212  "FROM capturecard "
213  "WHERE capturecard.hostname = :HOSTNAME ";
214 
215  if (!rawtype.isEmpty())
216  qstr += " AND capturecard.cardtype = :CARDTYPE";
217 
218  query.prepare(qstr);
219 
220  if (!rawtype.isEmpty())
221  query.bindValue(":CARDTYPE", rawtype.toUpper());
222 
223  query.bindValue(":HOSTNAME", hostname);
224 
225  if (!query.exec())
226  {
227  MythDB::DBError("CardUtil::IsCardTypePresent", query);
228  return false;
229  }
230 
231  uint count = 0;
232  if (query.next())
233  count = query.value(0).toUInt();
234 
235  return count > 0;
236 }
237 
238 QStringList CardUtil::GetCardTypes(void)
239 {
240  QStringList cardtypes;
241 
242  MSqlQuery query(MSqlQuery::InitCon());
243  query.prepare("SELECT DISTINCT cardtype "
244  "FROM capturecard");
245 
246  if (!query.exec())
247  {
248  MythDB::DBError("CardUtil::GetCardTypes()", query);
249  }
250  else
251  {
252  while (query.next())
253  cardtypes.push_back(query.value(0).toString());
254  }
255 
256  return cardtypes;
257 }
258 
264 QStringList CardUtil::GetVideoDevices(const QString &rawtype, QString hostname)
265 {
266  QStringList list;
267 
268  if (hostname.isEmpty())
269  hostname = gCoreContext->GetHostName();
270 
271  MSqlQuery query(MSqlQuery::InitCon());
272  QString qstr =
273  "SELECT videodevice "
274  "FROM capturecard "
275  "WHERE hostname = :HOSTNAME";
276 
277  if (!rawtype.isEmpty())
278  qstr += " AND cardtype = :CARDTYPE";
279 
280  query.prepare(qstr);
281 
282  if (!rawtype.isEmpty())
283  query.bindValue(":CARDTYPE", rawtype.toUpper());
284 
285  query.bindValue(":HOSTNAME", hostname);
286 
287  if (!query.exec())
288  {
289  MythDB::DBError("CardUtil::GetVideoDevices", query);
290  return list;
291  }
292 
293  QMap<QString,bool> dup;
294  while (query.next())
295  {
296  QString videodevice = query.value(0).toString();
297  if (dup[videodevice])
298  continue;
299 
300  list.push_back(videodevice);
301  dup[videodevice] = true;
302  }
303 
304  return list;
305 }
306 
307 QStringList CardUtil::ProbeVideoDevices(const QString &rawtype)
308 {
309  QStringList devs;
310 
311  if (rawtype.toUpper() == "DVB")
312  {
313  QDir dir("/dev/dvb", "adapter*", QDir::Name, QDir::Dirs);
314  const QFileInfoList il = dir.entryInfoList();
315  if (il.isEmpty())
316  return devs;
317 
318  QFileInfoList::const_iterator it = il.begin();
319 
320  for (; it != il.end(); ++it)
321  {
322  QDir subdir(it->filePath(), "frontend*", QDir::Name, QDir::Files | QDir::System);
323  const QFileInfoList subil = subdir.entryInfoList();
324  if (subil.isEmpty())
325  continue;
326 
327  QFileInfoList::const_iterator subit = subil.begin();
328  for (; subit != subil.end(); ++subit)
329  devs.push_back(subit->filePath());
330  }
331  }
332  else if (rawtype.toUpper() == "ASI")
333  {
334  QDir dir("/dev/", "asirx*", QDir::Name, QDir::System);
335  const QFileInfoList il = dir.entryInfoList();
336  if (il.isEmpty())
337  return devs;
338 
339  QFileInfoList::const_iterator it = il.begin();
340  for (; it != il.end(); ++it)
341  {
342  if (GetASIDeviceNumber(it->filePath()) >= 0)
343  {
344  devs.push_back(it->filePath());
345  continue;
346  }
347  break;
348  }
349  }
350 #ifdef USING_HDHOMERUN
351  else if (rawtype.toUpper() == "HDHOMERUN")
352  {
353  uint32_t target_ip = 0;
354  uint32_t device_type = HDHOMERUN_DEVICE_TYPE_TUNER;
355  uint32_t device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
356  const int max_count = 50;
357  hdhomerun_discover_device_t result_list[max_count];
358 
359  int result = hdhomerun_discover_find_devices_custom(
360  target_ip, device_type, device_id, result_list, max_count);
361 
362  if (result == -1)
363  {
364  LOG(VB_GENERAL, LOG_ERR, "Error finding HDHomerun devices");
365  return devs;
366  }
367 
368  if (result >= max_count)
369  {
370  LOG(VB_GENERAL, LOG_WARNING,
371  "Warning: may be > 50 HDHomerun devices");
372  }
373 
374  // Return "deviceid ipaddress" pairs
375  for (int i = 0; i < result; i++)
376  {
377  QString id = QString("%1").arg(result_list[i].device_id, 0, 16);
378  QString ip = QString("%1.%2.%3.%4")
379  .arg((result_list[i].ip_addr>>24) & 0xFF)
380  .arg((result_list[i].ip_addr>>16) & 0xFF)
381  .arg((result_list[i].ip_addr>> 8) & 0xFF)
382  .arg((result_list[i].ip_addr>> 0) & 0xFF);
383 
384  for (int tuner = 0; tuner < result_list[i].tuner_count; tuner++)
385  {
386  QString hdhrdev = id.toUpper() + " " + ip + " " +
387  QString("%1").arg(tuner);
388  devs.push_back(hdhrdev);
389  }
390  }
391  }
392 #endif // USING_HDHOMERUN
393 #ifdef USING_VBOX
394  else if (rawtype.toUpper() == "VBOX")
395  {
396  devs = VBox::probeDevices();
397  }
398 #endif // USING_VBOX
399 #ifdef USING_CETON
400  else if (rawtype.toUpper() == "CETON")
401  {
402  // TODO implement CETON probing.
403  LOG(VB_GENERAL, LOG_INFO, "CardUtil::ProbeVideoDevices: "
404  "TODO Probe Ceton devices");
405  }
406 #endif // USING_CETON
407  else
408  {
409  LOG(VB_GENERAL, LOG_ERR, QString("Raw Type: '%1' is not supported")
410  .arg(rawtype));
411  }
412 
413  return devs;
414 }
415 
416 QString CardUtil::ProbeDVBType(const QString &device)
417 {
418  QString ret = "ERROR_UNKNOWN";
419 
420  if (device.isEmpty())
421  return ret;
422 
423 #ifdef USING_DVB
424  QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
425  QByteArray dev = dvbdev.toLatin1();
426 
427  int fd_frontend = open(dev.constData(), O_RDWR | O_NONBLOCK);
428  if (fd_frontend < 0)
429  {
430  LOG(VB_GENERAL, LOG_ERR, QString("Can't open DVB frontend (%1) for %2.")
431  .arg(dvbdev).arg(device));
432  return ret;
433  }
434 
435  struct dvb_frontend_info info;
436  memset(&info, 0, sizeof(info));
437  int err = ioctl(fd_frontend, FE_GET_INFO, &info);
438  if (err < 0)
439  {
440  close(fd_frontend);
441  LOG(VB_GENERAL, LOG_ERR, QString("FE_GET_INFO ioctl failed (%1)")
442  .arg(dvbdev) + ENO);
443  return ret;
444  }
445  close(fd_frontend);
446 
447  DTVTunerType type(info.type);
448 #if HAVE_FE_CAN_2G_MODULATION
449  if (type == DTVTunerType::kTunerTypeDVBS1 &&
450  (info.caps & FE_CAN_2G_MODULATION))
452 #endif // HAVE_FE_CAN_2G_MODULATION
453  ret = (type.toString() != "UNKNOWN") ? type.toString().toUpper() : ret;
454 #endif // USING_DVB
455 
456  return ret;
457 }
458 
462 QString CardUtil::ProbeDVBFrontendName(const QString &device)
463 {
464  QString ret = "ERROR_UNKNOWN";
465  (void) device;
466 
467 #ifdef USING_DVB
468  QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
469  QByteArray dev = dvbdev.toLatin1();
470  int fd_frontend = open(dev.constData(), O_RDWR | O_NONBLOCK);
471  if (fd_frontend < 0)
472  return "ERROR_OPEN";
473 
474  struct dvb_frontend_info info;
475  memset(&info, 0, sizeof(info));
476  int err = ioctl(fd_frontend, FE_GET_INFO, &info);
477  if (err < 0)
478  {
479  close(fd_frontend);
480  return "ERROR_PROBE";
481  }
482 
483  ret = info.name;
484 
485  close(fd_frontend);
486 #endif // USING_DVB
487 
488  return ret;
489 }
490 
508 bool CardUtil::HasDVBCRCBug(const QString &device)
509 {
510  QString name = ProbeDVBFrontendName(device);
511  return ((name == "VLSI VES1x93 DVB-S") || // munges PMT
512  (name == "ST STV0299 DVB-S")); // munges PAT
513 }
514 
516 {
517  QString name = ProbeDVBFrontendName(device);
518  if (name.indexOf("DVB-S") >= 0)
519  return 300;
520  if (name == "DiBcom 3000P/M-C DVB-T")
521  return 100;
522  return 25;
523 }
524 
526 {
527  QString type = GetRawCardType(cardid);
528  if ("DVB" != type)
529  return type;
530 
531  QString device = GetVideoDevice(cardid);
532 
533  if (device.isEmpty())
534  return "ERROR_OPEN";
535 
536  return ProbeDVBType(device);
537 }
538 
540 bool CardUtil::IsDVBCardType(const QString &card_type)
541 {
542  QString ct = card_type.toUpper();
543  return (ct == "DVB") || (ct == "QAM") || (ct == "QPSK") ||
544  (ct == "OFDM") || (ct == "ATSC") || (ct == "DVB_S2");
545 }
546 
547 QString get_on_cardid(const QString &to_get, uint cardid)
548 {
549  MSqlQuery query(MSqlQuery::InitCon());
550  query.prepare(
551  QString("SELECT %1 ").arg(to_get) +
552  "FROM capturecard "
553  "WHERE capturecard.cardid = :CARDID");
554  query.bindValue(":CARDID", cardid);
555 
556  if (!query.exec())
557  MythDB::DBError("CardUtil::get_on_source", query);
558  else if (query.next())
559  return query.value(0).toString();
560 
561  return QString::null;
562 }
563 
564 bool set_on_source(const QString &to_set, uint cardid, uint sourceid,
565  const QString &value)
566 {
567  QString tmp = get_on_cardid("capturecard.cardid", cardid);
568  if (tmp.isEmpty())
569  return false;
570 
571  bool ok;
572  uint input_cardid = tmp.toUInt(&ok);
573  if (!ok)
574  return false;
575 
576  MSqlQuery query(MSqlQuery::InitCon());
577  query.prepare(
578  QString("UPDATE capturecard SET %1 = :VALUE ").arg(to_set) +
579  "WHERE cardid = :CARDID");
580  query.bindValue(":CARDID", input_cardid);
581  query.bindValue(":VALUE", value);
582 
583  if (query.exec())
584  return true;
585 
586  MythDB::DBError("CardUtil::set_on_source", query);
587  return false;
588 }
589 
590 QString get_on_inputid(const QString &to_get, uint inputid)
591 {
592  MSqlQuery query(MSqlQuery::InitCon());
593  query.prepare(
594  QString("SELECT %1 ").arg(to_get) +
595  "FROM capturecard "
596  "WHERE capturecard.cardid = :INPUTID");
597  query.bindValue(":INPUTID", inputid);
598 
599  if (!query.exec())
600  MythDB::DBError("CardUtil::get_on_inputid", query);
601  else if (query.next())
602  return query.value(0).toString();
603 
604  return QString::null;
605 }
606 
607 bool set_on_input(const QString &to_set, uint inputid, const QString &value)
608 {
609  QString tmp = get_on_inputid("capturecard.cardid", inputid);
610  if (tmp.isEmpty())
611  return false;
612 
613  bool ok;
614  uint input_cardinputid = tmp.toUInt(&ok);
615  if (!ok)
616  return false;
617 
618  MSqlQuery query(MSqlQuery::InitCon());
619  query.prepare(
620  QString("UPDATE capturecard SET %1 = :VALUE ").arg(to_set) +
621  "WHERE cardid = :INPUTID");
622  query.bindValue(":INPUTID", input_cardinputid);
623  query.bindValue(":VALUE", value);
624 
625  if (query.exec())
626  return true;
627 
628  MythDB::DBError("CardUtil::set_on_input", query);
629  return false;
630 }
631 
641 vector<uint> CardUtil::GetCardIDs(QString videodevice,
642  QString rawtype,
643  QString inputname,
644  QString hostname)
645 {
646  vector<uint> list;
647 
648  if (hostname.isEmpty())
649  hostname = gCoreContext->GetHostName();
650 
651  MSqlQuery query(MSqlQuery::InitCon());
652  QString qstr =
653  (videodevice.isEmpty()) ?
654  "SELECT cardid "
655  "FROM capturecard "
656  "WHERE hostname = :HOSTNAME" :
657 
658  "SELECT cardid "
659  "FROM capturecard "
660  "WHERE videodevice = :DEVICE AND "
661  " inputname = :INPUTNAME AND "
662  " hostname = :HOSTNAME";
663 
664  if (!rawtype.isEmpty())
665  qstr += " AND cardtype = :CARDTYPE";
666 
667  qstr += " ORDER BY cardid";
668 
669  query.prepare(qstr);
670 
671  if (!videodevice.isEmpty())
672  {
673  query.bindValue(":DEVICE", videodevice);
674  query.bindValue(":INPUTNAME", inputname);
675  }
676 
677  query.bindValue(":HOSTNAME", hostname);
678 
679  if (!rawtype.isEmpty())
680  query.bindValue(":CARDTYPE", rawtype.toUpper());
681 
682  if (!query.exec())
683  MythDB::DBError("CardUtil::GetCardIDs(videodevice...)", query);
684  else
685  {
686  while (query.next())
687  list.push_back(query.value(0).toUInt());
688  }
689 
690  return list;
691 }
692 
694 {
695  if (!cardid)
696  return 0;
697 
698  MSqlQuery query(MSqlQuery::InitCon());
699  QString qstr =
700  "SELECT COUNT(*) "
701  "FROM capturecard "
702  "WHERE parentid = :CARDID";
703 
704  query.prepare(qstr);
705  query.bindValue(":CARDID", cardid);
706 
707  uint count = 0;
708 
709  if (!query.exec())
710  MythDB::DBError("CardUtil::GetChildCardCount()", query);
711  else if (query.next())
712  count = query.value(0).toUInt();
713 
714  return count;
715 }
716 
717 vector<uint> CardUtil::GetChildCardIDs(uint cardid)
718 {
719  vector<uint> list;
720 
721  if (!cardid)
722  return list;
723 
724  MSqlQuery query(MSqlQuery::InitCon());
725  QString qstr =
726  "SELECT cardid "
727  "FROM capturecard "
728  "WHERE parentid = :CARDID "
729  "ORDER BY cardid";
730 
731  query.prepare(qstr);
732  query.bindValue(":CARDID", cardid);
733 
734  if (!query.exec())
735  MythDB::DBError("CardUtil::GetChildCardIDs()", query);
736  else
737  {
738  while (query.next())
739  list.push_back(query.value(0).toUInt());
740  }
741 
742  return list;
743 }
744 
745 static uint clone_capturecard(uint src_cardid, uint orig_dst_cardid)
746 {
747  uint dst_cardid = orig_dst_cardid;
748 
749  MSqlQuery query(MSqlQuery::InitCon());
750  if (!dst_cardid)
751  {
752  query.prepare(
753  "DELETE FROM capturecard "
754  "WHERE videodevice = 'temp_dummy'");
755 
756  if (!query.exec())
757  {
758  MythDB::DBError("clone_capturecard -- delete temp", query);
759  return 0;
760  }
761 
762  query.prepare(
763  "INSERT INTO capturecard "
764  "SET videodevice = 'temp_dummy'");
765 
766  if (!query.exec())
767  {
768  MythDB::DBError("clone_capturecard -- insert temp", query);
769  return 0;
770  }
771 
772  query.prepare(
773  "SELECT cardid "
774  "FROM capturecard "
775  "WHERE videodevice = 'temp_dummy'");
776 
777  if (!query.exec())
778  {
779  MythDB::DBError("clone_capturecard -- get temp id", query);
780  return 0;
781  }
782 
783  if (!query.next())
784  {
785  LOG(VB_GENERAL, LOG_ERR, "clone_capturecard -- get temp id");
786  return 0;
787  }
788 
789  dst_cardid = query.value(0).toUInt();
790  }
791 
792  query.prepare(
793  "SELECT videodevice, cardtype, "
794  " hostname, signal_timeout, channel_timeout, "
795  " dvb_wait_for_seqstart, dvb_on_demand, dvb_tuning_delay, "
796  " dvb_diseqc_type, diseqcid, dvb_eitscan, "
797  " inputname, sourceid, externalcommand, "
798  " changer_device, changer_model, tunechan, "
799  " startchan, displayname, dishnet_eit, "
800  " recpriority, quicktune, schedorder, "
801  " livetvorder "
802  "FROM capturecard "
803  "WHERE cardid = :CARDID");
804  query.bindValue(":CARDID", src_cardid);
805 
806  if (!query.exec())
807  {
808  MythDB::DBError("clone_capturecard -- get data", query);
809  return 0;
810  }
811  if (!query.next())
812  {
813  LOG(VB_GENERAL, LOG_ERR, "clone_cardinput -- get data 2");
814  return 0;
815  }
816 
817  MSqlQuery query2(MSqlQuery::InitCon());
818  query2.prepare(
819  "UPDATE capturecard "
820  "SET videodevice = :V0, "
821  " cardtype = :V1, "
822  " hostname = :V2, "
823  " signal_timeout = :V3, "
824  " channel_timeout = :V4, "
825  " dvb_wait_for_seqstart = :V5, "
826  " dvb_on_demand = :V6, "
827  " dvb_tuning_delay = :V7, "
828  " dvb_diseqc_type = :V8, "
829  " diseqcid = :V9,"
830  " dvb_eitscan = :V10, "
831  " inputname = :V11, "
832  " sourceid = :V12, "
833  " externalcommand = :V13, "
834  " changer_device = :V14, "
835  " changer_model = :V15, "
836  " tunechan = :V16, "
837  " startchan = :V17, "
838  " displayname = :V18, "
839  " dishnet_eit = :V19, "
840  " recpriority = :V20, "
841  " quicktune = :V21, "
842  " schedorder = :V22, "
843  " livetvorder = :V23, "
844  " parentid = :PARENTID "
845  "WHERE cardid = :CARDID");
846  for (uint i = 0; i < 24; i++)
847  query2.bindValue(QString(":V%1").arg(i), query.value(i).toString());
848  query2.bindValue(":CARDID", dst_cardid);
849  query2.bindValue(":PARENTID", src_cardid);
850 
851  if (!query2.exec())
852  {
853  MythDB::DBError("clone_capturecard -- save data", query2);
854  if (!orig_dst_cardid)
855  CardUtil::DeleteCard(dst_cardid);
856  return 0;
857  }
858 
859  // copy input group linkages
860  vector<uint> src_grps = CardUtil::GetInputGroups(src_cardid);
861  vector<uint> dst_grps = CardUtil::GetInputGroups(dst_cardid);
862  for (uint j = 0; j < dst_grps.size(); j++)
863  CardUtil::UnlinkInputGroup(dst_cardid, dst_grps[j]);
864  for (uint j = 0; j < src_grps.size(); j++)
865  CardUtil::LinkInputGroup(dst_cardid, src_grps[j]);
866 
867  // clone diseqc_config (just points to the same diseqc_tree row)
868  DiSEqCDevSettings diseqc;
869  if (diseqc.Load(src_cardid))
870  diseqc.Store(dst_cardid);
871 
872  return dst_cardid;
873 }
874 
875 bool CardUtil::CloneCard(uint src_cardid, uint orig_dst_cardid)
876 {
877  QString type = CardUtil::GetRawCardType(src_cardid);
878  if (!IsTunerSharingCapable(type))
879  return false;
880 
881  uint dst_cardid = clone_capturecard(src_cardid, orig_dst_cardid);
882  if (!dst_cardid)
883  return false;
884 
885  return true;
886 }
887 
889 {
890  QString fwnode;
891 
892  MSqlQuery query(MSqlQuery::InitCon());
893  query.prepare("SELECT changer_device "
894  "FROM capturecard WHERE cardid = :INPUTID ");
895  query.bindValue(":CARDID", inputid);
896 
897  if (query.exec() && query.next())
898  {
899  fwnode = query.value(0).toString();
900  }
901 
902  return fwnode;
903 }
904 
906 {
907  QString fwnode;
908 
909  MSqlQuery query(MSqlQuery::InitCon());
910  query.prepare("SELECT changer_model "
911  "FROM capturecard WHERE cardid = :INPUTID ");
912  query.bindValue(":CARDID", inputid);
913 
914  if (query.exec() && query.next())
915  {
916  fwnode = query.value(0).toString();
917  }
918 
919  return fwnode;
920 }
921 
922 vector<uint> CardUtil::GetCardIDs(uint sourceid)
923 {
924  MSqlQuery query(MSqlQuery::InitCon());
925 
926  query.prepare(
927  "SELECT DISTINCT cardid "
928  "FROM capturecard "
929  "WHERE sourceid = :SOURCEID");
930  query.bindValue(":SOURCEID", sourceid);
931 
932  vector<uint> list;
933 
934  if (!query.exec())
935  {
936  MythDB::DBError("CardUtil::GetCardIDs()", query);
937  return list;
938  }
939 
940  while (query.next())
941  list.push_back(query.value(0).toUInt());
942 
943  return list;
944 }
945 
947  uint cardid, const QString &channum, QString &inputname)
948 {
949  MSqlQuery query(MSqlQuery::InitCon());
950  query.prepare(
951  "SELECT cardid, inputname "
952  "FROM channel, capturecard "
953  "WHERE channel.channum = :CHANNUM AND "
954  " channel.sourceid = capturecard.sourceid AND "
955  " capturecard.cardid = :CARDID");
956  query.bindValue(":CHANNUM", channum);
957  query.bindValue(":CARDID", cardid);
958 
959  if (!query.exec() || !query.isActive())
960  MythDB::DBError("get_cardinputid", query);
961  else if (query.next())
962  {
963  inputname = query.value(1).toString();
964  return query.value(0).toInt();
965  }
966 
967  return -1;
968 }
969 
970 bool CardUtil::SetStartChannel(uint cardinputid, const QString &channum)
971 {
972  MSqlQuery query(MSqlQuery::InitCon());
973  query.prepare("UPDATE capturecard "
974  "SET startchan = :CHANNUM "
975  "WHERE cardid = :INPUTID");
976  query.bindValue(":CHANNUM", channum);
977  query.bindValue(":INPUTID", cardinputid);
978 
979  if (!query.exec())
980  {
981  MythDB::DBError("set_startchan", query);
982  return false;
983  }
984 
985  return true;
986 }
987 
994 {
995  QString str = QString::null;
996  MSqlQuery query(MSqlQuery::InitCon());
997  query.prepare("SELECT inputname "
998  "FROM capturecard "
999  "WHERE capturecard.cardid = :CARDID "
1000  "ORDER BY livetvorder = 0, livetvorder, cardid "
1001  "LIMIT 1");
1002  query.bindValue(":CARDID", nCardID);
1003 
1004  if (!query.exec() || !query.isActive())
1005  MythDB::DBError("CardUtil::GetStartInput()", query);
1006  else if (query.next())
1007  str = query.value(0).toString();
1008 
1009  return str;
1010 }
1011 
1012 QStringList CardUtil::GetInputNames(uint cardid, uint sourceid)
1013 {
1014  QStringList list;
1015  MSqlQuery query(MSqlQuery::InitCon());
1016 
1017  if (sourceid)
1018  {
1019  query.prepare("SELECT inputname "
1020  "FROM capturecard "
1021  "WHERE sourceid = :SOURCEID AND "
1022  " cardid = :CARDID");
1023  query.bindValue(":SOURCEID", sourceid);
1024  }
1025  else
1026  {
1027  query.prepare("SELECT inputname "
1028  "FROM capturecard "
1029  "WHERE cardid = :CARDID");
1030  }
1031  query.bindValue(":CARDID", cardid);
1032 
1033  if (!query.exec())
1034  {
1035  MythDB::DBError("CardUtil::GetInputNames()", query);
1036  }
1037  else
1038  {
1039  while (query.next())
1040  list.append( query.value(0).toString() );
1041  }
1042 
1043  return list;
1044 }
1045 
1046 bool CardUtil::GetInputInfo(InputInfo &input, vector<uint> *groupids)
1047 {
1048  if (!input.inputid)
1049  return false;
1050 
1051  MSqlQuery query(MSqlQuery::InitCon());
1052  query.prepare("SELECT "
1053  "inputname, sourceid, cardid, livetvorder, "
1054  "schedorder, displayname, recpriority, quicktune "
1055  "FROM capturecard "
1056  "WHERE cardid = :INPUTID");
1057  query.bindValue(":INPUTID", input.inputid);
1058 
1059  if (!query.exec())
1060  {
1061  MythDB::DBError("CardUtil::GetInputInfo()", query);
1062  return false;
1063  }
1064 
1065  if (!query.next())
1066  return false;
1067 
1068  input.name = query.value(0).toString();
1069  input.sourceid = query.value(1).toUInt();
1070  input.cardid = query.value(2).toUInt();
1071  input.livetvorder = query.value(3).toUInt();
1072  input.scheduleOrder = query.value(4).toUInt();
1073  input.displayName = query.value(5).toString();
1074  input.recPriority = query.value(6).toInt();
1075  input.quickTune = query.value(7).toBool();
1076 
1077  if (groupids)
1078  *groupids = GetInputGroups(input.inputid);
1079 
1080  return true;
1081 }
1082 
1083 QList<InputInfo> CardUtil::GetAllInputInfo()
1084 {
1085  QList<InputInfo> infoInputList;
1086 
1087  MSqlQuery query(MSqlQuery::InitCon());
1088  query.prepare("SELECT cardid, "
1089  "inputname, sourceid, cardid, livetvorder, "
1090  "schedorder, displayname, recpriority, quicktune "
1091  "FROM capturecard");
1092 
1093  if (!query.exec())
1094  {
1095  MythDB::DBError("CardUtil::GetAllInputInfo()", query);
1096  return infoInputList;
1097  }
1098 
1099  while (query.next())
1100  {
1101  InputInfo input;
1102  input.inputid = query.value(0).toUInt();
1103  input.name = query.value(1).toString();
1104  input.sourceid = query.value(2).toUInt();
1105  input.cardid = query.value(3).toUInt();
1106  input.livetvorder = query.value(4).toUInt();
1107  input.scheduleOrder = query.value(5).toUInt();
1108  input.displayName = query.value(6).toString();
1109  input.recPriority = query.value(7).toInt();
1110  input.quickTune = query.value(8).toBool();
1111 
1112  infoInputList.push_back(input);
1113  }
1114 
1115  return infoInputList;
1116 }
1117 
1119 {
1120  InputInfo info("None", 0, inputid, 0, 0, 0, 0);
1121  GetInputInfo(info);
1122  return info.cardid;
1123 }
1124 
1126 {
1127  InputInfo info("None", 0, inputid, 0, 0, 0, 0);
1128  GetInputInfo(info);
1129  return info.name;
1130 }
1131 
1133 {
1134  MSqlQuery query(MSqlQuery::InitCon());
1135  query.prepare("SELECT startchan "
1136  "FROM capturecard "
1137  "WHERE cardid = :INPUTID");
1138  query.bindValue(":INPUTID", inputid);
1139 
1140  if (!query.exec())
1141  MythDB::DBError("CardUtil::GetStartingChannel(uint)", query);
1142  else if (query.next())
1143  return query.value(0).toString();
1144 
1145  return QString::null;
1146 }
1147 
1149 {
1150  if (!inputid)
1151  return QString::null;
1152 
1153  MSqlQuery query(MSqlQuery::InitCon());
1154  query.prepare("SELECT displayname, cardid, cardtype, inputname "
1155  "FROM capturecard "
1156  "WHERE cardid = :INPUTID");
1157  query.bindValue(":INPUTID", inputid);
1158 
1159  if (!query.exec())
1160  MythDB::DBError("CardUtil::GetDisplayName(uint)", query);
1161  else if (query.next())
1162  {
1163  QString result = query.value(0).toString();
1164  if (result.isEmpty())
1165  result = QString("%1: %2/%3").arg(query.value(1).toInt())
1166  .arg(query.value(2).toString()).arg(query.value(3).toString());
1167  return result;
1168  }
1169 
1170  return QString::null;
1171 }
1172 
1173 uint CardUtil::GetInputID(uint cardid, const QString &inputname)
1174 {
1175  MSqlQuery query(MSqlQuery::InitCon());
1176  query.prepare("SELECT cardid "
1177  "FROM capturecard "
1178  "WHERE inputname = :INPUTNAME AND "
1179  " cardid = :CARDID");
1180  query.bindValue(":INPUTNAME", inputname);
1181  query.bindValue(":CARDID", cardid);
1182 
1183  if (!query.exec())
1184  MythDB::DBError("CardUtil::GetInputID(uint,QString)", query);
1185  else if (query.next())
1186  return query.value(0).toUInt();
1187 
1188  return 0;
1189 }
1190 
1192 {
1193  MSqlQuery query(MSqlQuery::InitCon());
1194  query.prepare(
1195  "SELECT sourceid "
1196  "FROM capturecard "
1197  "WHERE cardid = :INPUTID");
1198  query.bindValue(":INPUTID", inputid);
1199  if (!query.exec() || !query.isActive())
1200  MythDB::DBError("CardUtil::GetSourceID()", query);
1201  else if (query.next())
1202  return query.value(0).toUInt();
1203 
1204  return 0;
1205 }
1206 
1207 vector<uint> CardUtil::GetAllInputIDs(void)
1208 {
1209  vector<uint> list;
1210 
1211  MSqlQuery query(MSqlQuery::InitCon());
1212  query.prepare(
1213  "SELECT cardid "
1214  "FROM capturecard");
1215 
1216  if (!query.exec())
1217  {
1218  MythDB::DBError("CardUtil::GetAllInputIDs(uint)", query);
1219  return list;
1220  }
1221 
1222  while (query.next())
1223  list.push_back(query.value(0).toUInt());
1224 
1225  return list;
1226 }
1227 
1228 vector<uint> CardUtil::GetInputIDs(uint cardid)
1229 {
1230  vector<uint> list;
1231 
1232  MSqlQuery query(MSqlQuery::InitCon());
1233  query.prepare(
1234  "SELECT cardid "
1235  "FROM capturecard "
1236  "WHERE cardid = :CARDID");
1237 
1238  query.bindValue(":CARDID", cardid);
1239 
1240  if (!query.exec())
1241  {
1242  MythDB::DBError("CardUtil::GetInputIDs(uint)", query);
1243  return list;
1244  }
1245 
1246  while (query.next())
1247  list.push_back(query.value(0).toUInt());
1248 
1249  return list;
1250 }
1251 
1253  const uint sourceid,
1254  const QString &inputname,
1255  const QString &externalcommand,
1256  const QString &changer_device,
1257  const QString &changer_model,
1258  const QString &hostname,
1259  const QString &tunechan,
1260  const QString &startchan,
1261  const QString &displayname,
1262  bool dishnet_eit,
1263  const uint recpriority,
1264  const uint quicktune,
1265  const uint schedorder,
1266  const uint livetvorder)
1267 {
1268  MSqlQuery query(MSqlQuery::InitCon());
1269 
1270  query.prepare(
1271  "UPDATE capturecard "
1272  "SET sourceid = :SOURCEID, "
1273  " inputname = :INPUTNAME, "
1274  " externalcommand = :EXTERNALCOMMAND, "
1275  " changer_device = :CHANGERDEVICE, "
1276  " changer_model = :CHANGERMODEL, "
1277  " tunechan = :TUNECHAN, "
1278  " startchan = :STARTCHAN, "
1279  " displayname = :DISPLAYNAME, "
1280  " dishnet_eit = :DISHNETEIT, "
1281  " recpriority = :RECPRIORITY, "
1282  " quicktune = :QUICKTUNE, "
1283  " schedorder = :SCHEDORDER, "
1284  " livetvorder = :LIVETVORDER "
1285  "WHERE cardid = :CARDID AND "
1286  " inputname = 'None'");
1287 
1288  query.bindValue(":CARDID", cardid);
1289  query.bindValue(":SOURCEID", sourceid);
1290  query.bindValue(":INPUTNAME", inputname);
1291  query.bindValue(":EXTERNALCOMMAND", externalcommand);
1292  query.bindValue(":CHANGERDEVICE", changer_device);
1293  query.bindValue(":CHANGERMODEL", changer_model);
1294  query.bindValue(":TUNECHAN", tunechan);
1295  query.bindValue(":STARTCHAN", startchan);
1296  query.bindValue(":DISPLAYNAME", displayname.isNull() ? "" : displayname);
1297  query.bindValue(":DISHNETEIT", dishnet_eit);
1298  query.bindValue(":RECPRIORITY", recpriority);
1299  query.bindValue(":QUICKTUNE", quicktune);
1300  query.bindValue(":SCHEDORDER", schedorder);
1301  query.bindValue(":LIVETVORDER", livetvorder);
1302 
1303  if (!query.exec())
1304  {
1305  MythDB::DBError("CreateCardInput", query);
1306  return -1;
1307  }
1308 
1309  return cardid;
1310 }
1311 
1313 {
1314  MSqlQuery query(MSqlQuery::InitCon());
1315  query.prepare(
1316  "UPDATE capturecard "
1317  "SET sourceid = 0, "
1318  " inputname = 'None', "
1319  " externalcommand = '', "
1320  " changer_device = '', "
1321  " changer_model = '', "
1322  " tunechan = '', "
1323  " startchan = '', "
1324  " displayname = '', "
1325  " dishnet_eit = 0, "
1326  " recpriority = 0, "
1327  " quicktune = 0, "
1328  " schedorder = 1, "
1329  " livetvorder = 1 "
1330  "WHERE cardid = :INPUTID");
1331  query.bindValue(":INPUTID", inputid);
1332 
1333  if (!query.exec())
1334  {
1335  MythDB::DBError("DeleteInput", query);
1336  return false;
1337  }
1338 
1339  query.prepare("DELETE FROM inputgroup "
1340  "WHERE cardinputid = :INPUTID AND "
1341  " inputgroupname LIKE 'user:%'");
1342  query.bindValue(":INPUTID", inputid);
1343 
1344  if (!query.exec())
1345  {
1346  MythDB::DBError("DeleteInput2", query);
1347  return false;
1348  }
1349 
1350  return true;
1351 }
1352 
1354 {
1355  return true;
1356 }
1357 
1359 {
1360  MSqlQuery query(MSqlQuery::InitCon());
1361 
1362  query.prepare("SELECT inputgroupid FROM inputgroup "
1363  "WHERE inputgroupname = :GROUPNAME "
1364  "LIMIT 1");
1365  query.bindValue(":GROUPNAME", name);
1366  if (!query.exec())
1367  {
1368  MythDB::DBError("CreateNewInputGroup 0", query);
1369  return 0;
1370  }
1371 
1372  if (query.next())
1373  return query.value(0).toUInt();
1374 
1375  query.prepare("SELECT MAX(inputgroupid) FROM inputgroup");
1376  if (!query.exec())
1377  {
1378  MythDB::DBError("CreateNewInputGroup 1", query);
1379  return 0;
1380  }
1381 
1382  uint inputgroupid = (query.next()) ? query.value(0).toUInt() + 1 : 1;
1383 
1384  query.prepare(
1385  "INSERT INTO inputgroup "
1386  " (cardinputid, inputgroupid, inputgroupname) "
1387  "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
1388  query.bindValue(":INPUTID", 0);
1389  query.bindValue(":GROUPID", inputgroupid);
1390  query.bindValue(":GROUPNAME", name);
1391  if (!query.exec())
1392  {
1393  MythDB::DBError("CreateNewInputGroup 2", query);
1394  return 0;
1395  }
1396 
1397  return inputgroupid;
1398 }
1399 
1401 {
1402  MSqlQuery query(MSqlQuery::InitCon());
1403  query.prepare(
1404  "SELECT inputgroupid "
1405  "FROM inputgroup "
1406  "WHERE cardinputid = :INPUTID "
1407  " AND inputgroupname REGEXP '^[a-z_-]*\\\\|'");
1408  query.bindValue(":INPUTID", cardid);
1409 
1410  if (!query.exec())
1411  {
1412  MythDB::DBError("CardUtil::GetDeviceInputGroup()", query);
1413  return false;
1414  }
1415 
1416  if (query.next())
1417  {
1418  return query.value(0).toUInt();
1419  }
1420 
1421  return 0;
1422 }
1423 
1424 bool CardUtil::LinkInputGroup(uint inputid, uint inputgroupid)
1425 {
1426  MSqlQuery query(MSqlQuery::InitCon());
1427 
1428  query.prepare(
1429  "SELECT cardinputid, inputgroupid, inputgroupname "
1430  "FROM inputgroup "
1431  "WHERE inputgroupid = :GROUPID "
1432  "ORDER BY inputgroupid, cardinputid, inputgroupname");
1433  query.bindValue(":GROUPID", inputgroupid);
1434 
1435  if (!query.exec())
1436  {
1437  MythDB::DBError("CardUtil::CreateInputGroup() 1", query);
1438  return false;
1439  }
1440 
1441  if (!query.next())
1442  return false;
1443 
1444  const QString name = query.value(2).toString();
1445 
1446  query.prepare(
1447  "INSERT INTO inputgroup "
1448  " (cardinputid, inputgroupid, inputgroupname) "
1449  "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
1450 
1451  query.bindValue(":INPUTID", inputid);
1452  query.bindValue(":GROUPID", inputgroupid);
1453  query.bindValue(":GROUPNAME", name);
1454 
1455  if (!query.exec())
1456  {
1457  MythDB::DBError("CardUtil::CreateInputGroup() 2", query);
1458  return false;
1459  }
1460 
1461  return true;
1462 }
1463 
1464 bool CardUtil::UnlinkInputGroup(uint inputid, uint inputgroupid)
1465 {
1466  MSqlQuery query(MSqlQuery::InitCon());
1467 
1468  if (!inputid && !inputgroupid)
1469  {
1470  query.prepare(
1471  "DELETE FROM inputgroup "
1472  "WHERE cardinputid NOT IN "
1473  "( SELECT cardid FROM capturecard )");
1474  }
1475  else
1476  {
1477  query.prepare(
1478  "DELETE FROM inputgroup "
1479  "WHERE cardinputid = :INPUTID AND "
1480  " inputgroupid = :GROUPID ");
1481 
1482  query.bindValue(":INPUTID", inputid);
1483  query.bindValue(":GROUPID", inputgroupid);
1484  }
1485 
1486  if (!query.exec())
1487  {
1488  MythDB::DBError("CardUtil::DeleteInputGroup()", query);
1489  return false;
1490  }
1491 
1492  return true;
1493 }
1494 
1495 vector<uint> CardUtil::GetInputGroups(uint inputid)
1496 {
1497  vector<uint> list;
1498 
1499  MSqlQuery query(MSqlQuery::InitCon());
1500 
1501  query.prepare(
1502  "SELECT inputgroupid "
1503  "FROM inputgroup "
1504  "WHERE cardinputid = :INPUTID "
1505  "ORDER BY inputgroupid, cardinputid, inputgroupname");
1506 
1507  query.bindValue(":INPUTID", inputid);
1508 
1509  if (!query.exec())
1510  {
1511  MythDB::DBError("CardUtil::GetInputGroups()", query);
1512  return list;
1513  }
1514 
1515  while (query.next())
1516  list.push_back(query.value(0).toUInt());
1517 
1518  return list;
1519 }
1520 
1522 {
1523  vector<uint> list;
1524 
1525  vector<uint> inputs = GetInputIDs(cardid);
1526  if (inputs.empty())
1527  return list;
1528 
1529  list = GetInputGroups(inputs[0]);
1530  for (uint i = 1; (i < inputs.size()) && !list.empty(); i++)
1531  {
1532  vector<uint> curlist = GetInputGroups(inputs[i]);
1533  vector<uint> newlist;
1534  for (uint j = 0; j < list.size(); j++)
1535  {
1536  if (find(curlist.begin(), curlist.end(), list[j]) != curlist.end())
1537  newlist.push_back(list[j]);
1538  }
1539  list = newlist;
1540  }
1541 
1542  return list;
1543 }
1544 
1545 vector<uint> CardUtil::GetGroupCardIDs(uint inputgroupid)
1546 {
1547  vector<uint> list;
1548 
1549  MSqlQuery query(MSqlQuery::InitCon());
1550 
1551  query.prepare(
1552  "SELECT DISTINCT cardid "
1553  "FROM capturecard, inputgroup "
1554  "WHERE inputgroupid = :GROUPID AND "
1555  " capturecard.cardid = inputgroup.cardinputid "
1556  "ORDER BY cardid");
1557 
1558  query.bindValue(":GROUPID", inputgroupid);
1559 
1560  if (!query.exec())
1561  {
1562  MythDB::DBError("CardUtil::GetGroupCardIDs()", query);
1563  return list;
1564  }
1565 
1566  while (query.next())
1567  list.push_back(query.value(0).toUInt());
1568 
1569  return list;
1570 }
1571 
1572 vector<uint> CardUtil::GetConflictingCards(uint inputid, uint exclude_cardid)
1573 {
1574  vector<uint> inputgroupids = CardUtil::GetInputGroups(inputid);
1575 
1576  for (uint i = 0; i < inputgroupids.size(); i++)
1577  {
1578  LOG(VB_RECORD, LOG_INFO, LOC + QString(" Group ID %1")
1579  .arg(inputgroupids[i]));
1580  }
1581 
1582  vector<uint> cardids;
1583  for (uint i = 0; i < inputgroupids.size(); i++)
1584  {
1585  vector<uint> tmp = CardUtil::GetGroupCardIDs(inputgroupids[i]);
1586  for (uint j = 0; j < tmp.size(); j++)
1587  {
1588  if (tmp[j] == exclude_cardid)
1589  continue;
1590 
1591  if (find(cardids.begin(), cardids.end(), tmp[j]) != cardids.end())
1592  continue;
1593 
1594  cardids.push_back(tmp[j]);
1595  }
1596  }
1597 
1598  for (uint i = 0; i < cardids.size(); i++)
1599  LOG(VB_RECORD, LOG_INFO, LOC + QString(" Card ID %1").arg(cardids[i]));
1600 
1601  return cardids;
1602 }
1603 
1605  uint &signal_timeout, uint &channel_timeout)
1606 {
1607  MSqlQuery query(MSqlQuery::InitCon());
1608  query.prepare(
1609  "SELECT signal_timeout, channel_timeout "
1610  "FROM capturecard "
1611  "WHERE cardid = :CARDID");
1612  query.bindValue(":CARDID", cardid);
1613 
1614  if (!query.exec() || !query.isActive())
1615  MythDB::DBError("CardUtil::GetTimeouts()", query);
1616  else if (query.next())
1617  {
1618  signal_timeout = (uint) max(query.value(0).toInt(), 250);
1619  channel_timeout = (uint) max(query.value(1).toInt(), 500);
1620  return true;
1621  }
1622 
1623  return false;
1624 }
1625 
1627 {
1628  DiSEqCDev dev;
1629  DiSEqCDevTree *diseqc_tree = dev.FindTree(cardid);
1630 
1631  bool needsConf = false;
1632  if (diseqc_tree)
1633  needsConf = diseqc_tree->IsInNeedOfConf();
1634 
1635  return needsConf;
1636 }
1637 
1638 uint CardUtil::GetQuickTuning(uint cardid, const QString &input_name)
1639 {
1640  uint quicktune = 0;
1641 
1642  MSqlQuery query(MSqlQuery::InitCon());
1643  query.prepare(
1644  "SELECT quicktune "
1645  "FROM capturecard "
1646  "WHERE cardid = :CARDID AND "
1647  " inputname = :INPUTNAME");
1648  query.bindValue(":CARDID", cardid);
1649  query.bindValue(":INPUTNAME", input_name);
1650 
1651  if (!query.exec() || !query.isActive())
1652  MythDB::DBError("CardUtil::GetQuickTuning()", query);
1653  else if (query.next())
1654  quicktune = query.value(0).toUInt();
1655 
1656  return quicktune;
1657 }
1658 
1659 bool CardUtil::hasV4L2(int videofd)
1660 {
1661  (void) videofd;
1662 #ifdef USING_V4L2
1663  struct v4l2_capability vcap;
1664  memset(&vcap, 0, sizeof(vcap));
1665 
1666  return ((ioctl(videofd, VIDIOC_QUERYCAP, &vcap) >= 0) &&
1667  (vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE));
1668 #else // if !USING_V4L2
1669  return false;
1670 #endif // !USING_V4L2
1671 }
1672 
1674  int videofd, QString &card, QString &driver, uint32_t &version,
1675  uint32_t &capabilities)
1676 {
1677  card = driver = QString::null;
1678  version = 0;
1679  capabilities = 0;
1680 
1681  if (videofd < 0)
1682  return false;
1683 
1684 #ifdef USING_V4L2
1685  // First try V4L2 query
1686  struct v4l2_capability capability;
1687  memset(&capability, 0, sizeof(struct v4l2_capability));
1688  if (ioctl(videofd, VIDIOC_QUERYCAP, &capability) >= 0)
1689  {
1690  card = QString::fromLatin1((const char*)capability.card);
1691  driver = QString::fromLatin1((const char*)capability.driver);
1692  version = capability.version;
1693  capabilities = capability.capabilities;
1694  }
1695 #ifdef USING_V4L1
1696  else // Fallback to V4L1 query
1697  {
1698  struct video_capability capability;
1699  if (ioctl(videofd, VIDIOCGCAP, &capability) >= 0)
1700  card = QString::fromLatin1((const char*)capability.name);
1701  }
1702 #endif // USING_V4L1
1703 #endif // USING_V4L2
1704 
1705  if (!driver.isEmpty())
1706  driver.remove( QRegExp("\\[[0-9]\\]$") );
1707 
1708  return !card.isEmpty();
1709 }
1710 
1712 {
1713  (void) videofd;
1714 
1715  InputNames list;
1716  ok = false;
1717 
1718 #ifdef USING_V4L2
1719  bool usingv4l2 = hasV4L2(videofd);
1720 
1721  // V4L v2 query
1722  struct v4l2_input vin;
1723  memset(&vin, 0, sizeof(vin));
1724  while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMINPUT, &vin) >= 0))
1725  {
1726  QString input((char *)vin.name);
1727  list[vin.index] = input;
1728  vin.index++;
1729  }
1730  if (vin.index)
1731  {
1732  ok = true;
1733  return list;
1734  }
1735 
1736 #ifdef USING_V4L1
1737  // V4L v1 query
1738  struct video_capability vidcap;
1739  memset(&vidcap, 0, sizeof(vidcap));
1740  if (ioctl(videofd, VIDIOCGCAP, &vidcap) != 0)
1741  {
1742  QString msg = QObject::tr("Could not query inputs.");
1743  LOG(VB_GENERAL, LOG_ERR, "ProbeV4LVideoInputs(): Error, " + msg + ENO);
1744  list[-1] = msg;
1745  vidcap.channels = 0;
1746  }
1747 
1748  for (int i = 0; i < vidcap.channels; i++)
1749  {
1750  struct video_channel test;
1751  memset(&test, 0, sizeof(test));
1752  test.channel = i;
1753 
1754  if (ioctl(videofd, VIDIOCGCHAN, &test) != 0)
1755  {
1756  LOG(VB_GENERAL, LOG_ERR, "ProbeV4LVideoInputs(): Error, " +
1757  QString("Could determine name of input #%1"
1758  "\n\t\t\tNot adding it to the list.")
1759  .arg(test.channel) + ENO);
1760  continue;
1761  }
1762 
1763  list[i] = test.name;
1764  }
1765 #endif // USING_V4L1
1766 
1767  // Create an input on single input cards that don't advertise input
1768  if (list.isEmpty())
1769  list[0] = "Television";
1770 
1771  ok = true;
1772 #else // if !USING_V4L2
1773  list[-1] += QObject::tr("ERROR, Compile with V4L support to query inputs");
1774 #endif // !USING_V4L2
1775  return list;
1776 }
1777 
1779 {
1780  (void) videofd;
1781 
1782  InputNames list;
1783  ok = false;
1784 
1785 #ifdef USING_V4L2
1786  bool usingv4l2 = hasV4L2(videofd);
1787 
1788  // V4L v2 query
1789  struct v4l2_audio ain;
1790  memset(&ain, 0, sizeof(ain));
1791  while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMAUDIO, &ain) >= 0))
1792  {
1793  QString input((char *)ain.name);
1794  list[ain.index] = input;
1795  ain.index++;
1796  }
1797  if (ain.index)
1798  {
1799  ok = true;
1800  return list;
1801  }
1802 
1803  ok = true;
1804 #else // if !USING_V4L2
1805  list[-1] += QObject::tr(
1806  "ERROR, Compile with V4L support to query audio inputs");
1807 #endif // !USING_V4L2
1808  return list;
1809 }
1810 
1812 {
1813  InputNames list;
1814  MSqlQuery query(MSqlQuery::InitCon());
1815  query.prepare(
1816  "SELECT cardid, inputname "
1817  "FROM capturecard "
1818  "WHERE hostname = :HOSTNAME "
1819  " AND videodevice = :DEVICE "
1820  " AND parentid = 0 "
1821  " AND inputname <> 'None'");
1822  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
1823  query.bindValue(":DEVICE", device);
1824 
1825  if (!query.exec() || !query.isActive())
1826  MythDB::DBError("CardUtil::GetConfiguredDVBInputs", query);
1827  else
1828  {
1829  while (query.next())
1830  list[query.value(0).toUInt()] = query.value(1).toString();
1831  }
1832  return list;
1833 }
1834 
1835 QStringList CardUtil::ProbeVideoInputs(QString device, QString cardtype)
1836 {
1837  QStringList ret;
1838 
1839  if (IsSingleInputCard(cardtype))
1840  ret += "MPEG2TS";
1841  else if ("DVB" == cardtype)
1842  ret += ProbeDVBInputs(device);
1843  else
1844  ret += ProbeV4LVideoInputs(device);
1845 
1846  return ret;
1847 }
1848 
1849 QStringList CardUtil::ProbeAudioInputs(QString device, QString cardtype)
1850 {
1851  LOG(VB_GENERAL, LOG_DEBUG, QString("ProbeAudioInputs(%1,%2)")
1852  .arg(device).arg(cardtype));
1853  QStringList ret;
1854 
1855  if ("HDPVR" == cardtype)
1856  ret += ProbeV4LAudioInputs(device);
1857 
1858  return ret;
1859 }
1860 
1861 QStringList CardUtil::ProbeV4LVideoInputs(QString device)
1862 {
1863  bool ok;
1864  QStringList ret;
1865  QByteArray dev = device.toLatin1();
1866  int videofd = open(dev.constData(), O_RDWR);
1867  if (videofd < 0)
1868  {
1869  ret += QObject::tr("Could not open '%1' "
1870  "to probe its inputs.").arg(device);
1871  return ret;
1872  }
1873  InputNames list = CardUtil::ProbeV4LVideoInputs(videofd, ok);
1874  close(videofd);
1875 
1876  if (!ok)
1877  {
1878  ret += list[-1];
1879  return ret;
1880  }
1881 
1882  InputNames::iterator it;
1883  for (it = list.begin(); it != list.end(); ++it)
1884  {
1885  if (it.key() >= 0)
1886  ret += *it;
1887  }
1888 
1889  return ret;
1890 }
1891 
1892 QStringList CardUtil::ProbeV4LAudioInputs(QString device)
1893 {
1894  LOG(VB_GENERAL, LOG_DEBUG, QString("ProbeV4LAudioInputs(%1)").arg(device));
1895 
1896  bool ok;
1897  QStringList ret;
1898  int videofd = open(device.toLatin1().constData(), O_RDWR);
1899  if (videofd < 0)
1900  {
1901  LOG(VB_GENERAL, LOG_ERR, "ProbeAudioInputs() -> couldn't open device");
1902  ret += QObject::tr("Could not open '%1' to probe its inputs.")
1903  .arg(device);
1904  return ret;
1905  }
1906  InputNames list = CardUtil::ProbeV4LAudioInputs(videofd, ok);
1907  close(videofd);
1908 
1909  if (!ok)
1910  {
1911  ret += list[-1];
1912  return ret;
1913  }
1914 
1915  InputNames::iterator it;
1916  for (it = list.begin(); it != list.end(); ++it)
1917  {
1918  if (it.key() >= 0)
1919  ret += *it;
1920  }
1921 
1922  return ret;
1923 }
1924 
1925 QStringList CardUtil::ProbeDVBInputs(QString device)
1926 {
1927  QStringList ret;
1928 
1929 #ifdef USING_DVB
1930  InputNames list = GetConfiguredDVBInputs(device);
1931  InputNames::iterator it;
1932  for (it = list.begin(); it != list.end(); ++it)
1933  {
1934  if (it.key())
1935  ret += *it;
1936  }
1937 #else
1938  (void) device;
1939  ret += QObject::tr("ERROR, Compile with DVB support to query inputs");
1940 #endif
1941 
1942  return ret;
1943 }
1944 
1945 QString CardUtil::GetDeviceLabel(const QString &cardtype,
1946  const QString &videodevice)
1947 {
1948  return QString("[ %1 : %2 ]").arg(cardtype).arg(videodevice);
1949 }
1950 
1952 {
1953  QString devlabel;
1954  MSqlQuery query(MSqlQuery::InitCon());
1955  query.prepare("SELECT cardtype, videodevice "
1956  "FROM capturecard WHERE cardid = :CARDID ");
1957  query.bindValue(":CARDID", cardid);
1958 
1959  if (query.exec() && query.next())
1960  {
1961  return GetDeviceLabel(query.value(0).toString(),
1962  query.value(1).toString());
1963  }
1964 
1965  return "[ UNKNOWN ]";
1966 }
1967 
1969  uint cardid,
1970  const QString &device,
1971  const QString &cardtype,
1972  QStringList &inputs)
1973 {
1974  inputs.clear();
1975  if (IsSingleInputCard(cardtype))
1976  inputs += "MPEG2TS";
1977  else if ("DVB" != cardtype)
1978  inputs += ProbeV4LVideoInputs(device);
1979 
1980 #ifdef USING_DVB
1981  if ("DVB" == cardtype)
1982  {
1983  bool needs_conf = IsInNeedOfExternalInputConf(cardid);
1984  InputNames list = GetConfiguredDVBInputs(device);
1985  if (!needs_conf && list.empty())
1986  {
1987  inputs += "DVBInput";
1988  }
1989 
1990  // Always list the 1 through n+1 inputs
1991  if (needs_conf)
1992  {
1993  for (int i = 0; i <= list.size(); ++i)
1994  inputs += QString("DVBInput #%1").arg(i+1);
1995  }
1996 
1997  // Always list the existing inputs
1998  InputNames::const_iterator it;
1999  for (it = list.begin(); it != list.end(); ++it)
2000  {
2001  inputs += *it;
2002  }
2003  }
2004 #endif // USING_DVB
2005 }
2006 
2007 int CardUtil::CreateCaptureCard(const QString &videodevice,
2008  const QString &audiodevice,
2009  const QString &vbidevice,
2010  const QString &cardtype,
2011  const uint audioratelimit,
2012  const QString &hostname,
2013  const uint dvb_swfilter,
2014  const uint dvb_sat_type,
2015  bool dvb_wait_for_seqstart,
2016  bool skipbtaudio,
2017  bool dvb_on_demand,
2018  const uint dvb_diseqc_type,
2019  const uint firewire_speed,
2020  const QString &firewire_model,
2021  const uint firewire_connection,
2022  const uint signal_timeout,
2023  const uint channel_timeout,
2024  const uint dvb_tuning_delay,
2025  const uint contrast,
2026  const uint brightness,
2027  const uint colour,
2028  const uint hue,
2029  const uint diseqcid,
2030  bool dvb_eitscan)
2031 {
2032  MSqlQuery query(MSqlQuery::InitCon());
2033 
2034  query.prepare(
2035  "INSERT INTO capturecard "
2036  "(videodevice, audiodevice, vbidevice, cardtype, "
2037  "audioratelimit, hostname, dvb_swfilter, dvb_sat_type, "
2038  "dvb_wait_for_seqstart, skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
2039  "firewire_speed, firewire_model, firewire_connection, signal_timeout, "
2040  "channel_timeout, dvb_tuning_delay, contrast, brightness, colour, "
2041  "hue, diseqcid, dvb_eitscan) "
2042  "VALUES (:VIDEODEVICE, :AUDIODEVICE, :VBIDEVICE, :CARDTYPE, "
2043  ":AUDIORATELIMIT, :HOSTNAME, :DVBSWFILTER, :DVBSATTYPE, "
2044  ":DVBWAITFORSEQSTART, :SKIPBTAUDIO, :DVBONDEMAND, :DVBDISEQCTYPE, "
2045  ":FIREWIRESPEED, :FIREWIREMODEL, :FIREWIRECONNECTION, :SIGNALTIMEOUT, "
2046  ":CHANNELTIMEOUT, :DVBTUNINGDELAY, :CONTRAST, :BRIGHTNESS, :COLOUR, "
2047  ":HUE, :DISEQCID, :DVBEITSCAN ) ");
2048 
2049  query.bindValue(":VIDEODEVICE", videodevice);
2050  query.bindValue(":AUDIODEVICE", audiodevice);
2051  query.bindValue(":VBIDEVICE", vbidevice);
2052  query.bindValue(":CARDTYPE", cardtype);
2053  query.bindValue(":AUDIORATELIMIT", audioratelimit);
2054  query.bindValue(":HOSTNAME", hostname);
2055  query.bindValue(":DVBSWFILTER", dvb_swfilter);
2056  query.bindValue(":DVBSATTYPE", dvb_sat_type);
2057  query.bindValue(":DVBWAITFORSEQSTART", dvb_wait_for_seqstart);
2058  query.bindValue(":SKIPBTAUDIO", skipbtaudio);
2059  query.bindValue(":DVBONDEMAND", dvb_on_demand);
2060  query.bindValue(":DVBDISEQCTYPE", dvb_diseqc_type);
2061  query.bindValue(":FIREWIRESPEED", firewire_speed);
2062  query.bindValue(":FIREWIREMODEL", firewire_model);
2063  query.bindValue(":FIREWIRECONNECTION", firewire_connection);
2064  query.bindValue(":SIGNALTIMEOUT", signal_timeout);
2065  query.bindValue(":CHANNELTIMEOUT", channel_timeout);
2066  query.bindValue(":DVBTUNINGDELAY", dvb_tuning_delay);
2067  query.bindValue(":CONTRAST", contrast);
2068  query.bindValue(":BRIGHTNESS", brightness);
2069  query.bindValue(":COLOUR", colour);
2070  query.bindValue(":HUE", hue);
2071  query.bindValue(":DISEQCID", diseqcid);
2072  query.bindValue(":DVBEITSCAN", dvb_eitscan);
2073 
2074  if (!query.exec())
2075  {
2076  MythDB::DBError("CreateCaptureCard", query);
2077  return -1;
2078  }
2079 
2080  query.prepare("SELECT MAX(cardid) FROM capturecard");
2081 
2082  if (!query.exec())
2083  {
2084  MythDB::DBError("CreateCaptureCard maxcard", query);
2085  return -1;
2086  }
2087 
2088  int cardid = -1; /* must be int not uint because of return type. */
2089 
2090  if (query.next())
2091  {
2092  cardid = query.value(0).toInt();
2093  uint groupid = CardUtil::CreateDeviceInputGroup(hostname, videodevice);
2094  CardUtil::LinkInputGroup(cardid, groupid);
2095  }
2096 
2097  return cardid;
2098 }
2099 
2101 {
2102  MSqlQuery query(MSqlQuery::InitCon());
2103  bool ok = true;
2104 
2105  if (!cardid)
2106  return true;
2107 
2108  // delete any DiSEqC device tree
2109  DiSEqCDevTree tree;
2110  tree.Load(cardid);
2111  if (!tree.Root())
2112  {
2113  tree.SetRoot(NULL);
2114  tree.Store(cardid);
2115  }
2116 
2117  // delete any clones
2118  QString rawtype = GetRawCardType(cardid);
2119  QString videodevice = GetVideoDevice(cardid);
2120  if (IsTunerSharingCapable(rawtype) && !videodevice.isEmpty())
2121  {
2122  query.prepare(
2123  "SELECT cardid "
2124  "FROM capturecard "
2125  "WHERE videodevice = :DEVICE AND "
2126  " cardid > :CARDID");
2127  query.bindValue(":DEVICE", videodevice);
2128  query.bindValue(":CARDID", cardid);
2129 
2130  if (!query.exec())
2131  {
2132  MythDB::DBError("DeleteCard -- find clone cards", query);
2133  return false;
2134  }
2135 
2136  while (query.next())
2137  ok &= DeleteCard(query.value(0).toUInt());
2138 
2139  if (!ok)
2140  return false;
2141  }
2142 
2143  // delete inputs
2144  vector<uint> inputs = CardUtil::GetInputIDs(cardid);
2145  for (uint i = 0; i < inputs.size(); i++)
2146  ok &= CardUtil::DeleteInput(inputs[i]);
2147 
2148  if (!ok)
2149  return false;
2150 
2151  // actually delete the capturecard row for this card
2152  query.prepare("DELETE FROM capturecard WHERE cardid = :CARDID");
2153  query.bindValue(":CARDID", cardid);
2154 
2155  if (!query.exec())
2156  {
2157  MythDB::DBError("DeleteCard -- delete row", query);
2158  ok = false;
2159  }
2160 
2161  if (ok)
2162  {
2163  // delete any orphaned inputs & unused input groups
2165  UnlinkInputGroup(0,0);
2166  }
2167 
2168  return ok;
2169 }
2170 
2172 {
2173  MSqlQuery query(MSqlQuery::InitCon());
2174  return (query.exec("TRUNCATE TABLE inputgroup") &&
2175  query.exec("TRUNCATE TABLE diseqc_config") &&
2176  query.exec("TRUNCATE TABLE diseqc_tree") &&
2177  query.exec("TRUNCATE TABLE capturecard"));
2178 }
2179 
2180 vector<uint> CardUtil::GetCardList(void)
2181 {
2182  vector<uint> list;
2183 
2184  MSqlQuery query(MSqlQuery::InitCon());
2185  query.prepare(
2186  "SELECT cardid "
2187  "FROM capturecard "
2188  "ORDER BY cardid");
2189 
2190  if (!query.exec())
2191  MythDB::DBError("CardUtil::GetCardList()", query);
2192  else
2193  {
2194  while (query.next())
2195  list.push_back(query.value(0).toUInt());
2196  }
2197 
2198  return list;
2199 }
2200 
2202 {
2203  vector<uint> list;
2204 
2205  MSqlQuery query(MSqlQuery::InitCon());
2206  query.prepare(
2207  "SELECT DISTINCT cardid "
2208  "FROM capturecard "
2209  "WHERE livetvorder <> 0 "
2210  "ORDER BY livetvorder");
2211 
2212  if (!query.exec())
2213  MythDB::DBError("CardUtil::GetCardList()", query);
2214  else
2215  {
2216  while (query.next())
2217  list.push_back(query.value(0).toUInt());
2218  }
2219 
2220  return list;
2221 }
2222 
2223 
2224 QString CardUtil::GetDeviceName(dvb_dev_type_t type, const QString &device)
2225 {
2226  QString devname = QString(device);
2227 
2228  if (DVB_DEV_FRONTEND == type)
2229  return devname;
2230  else if (DVB_DEV_DVR == type)
2231  return devname.replace(devname.indexOf("frontend"), 8, "dvr");
2232  else if (DVB_DEV_DEMUX == type)
2233  return devname.replace(devname.indexOf("frontend"), 8, "demux");
2234  else if (DVB_DEV_CA == type)
2235  return devname.replace(devname.indexOf("frontend"), 8, "ca");
2236  else if (DVB_DEV_AUDIO == type)
2237  return devname.replace(devname.indexOf("frontend"), 8, "audio");
2238  else if (DVB_DEV_VIDEO == type)
2239  return devname.replace(devname.indexOf("frontend"), 8, "video");
2240 
2241  return "";
2242 }
2243 
2253 bool CardUtil::HDHRdoesDVB(const QString &device)
2254 {
2255  (void) device;
2256 
2257 #ifdef USING_HDHOMERUN
2258  hdhomerun_device_t *hdhr;
2259  hdhr = hdhomerun_device_create_from_str(device.toLatin1(), NULL);
2260  if (!hdhr)
2261  return false;
2262 
2263  const char *model = hdhomerun_device_get_model_str(hdhr);
2264  if (model && strstr(model, "dvb"))
2265  {
2266  hdhomerun_device_destroy(hdhr);
2267  return true;
2268  }
2269 
2270  hdhomerun_device_destroy(hdhr);
2271 
2272 #endif
2273 
2274  return false;
2275 }
2276 
2281 QString CardUtil::GetHDHRdesc(const QString &device)
2282 {
2283  QString connectErr = QObject::tr("Unable to connect to device.");
2284 
2285 #ifdef USING_HDHOMERUN
2286  bool deviceIsIP = false;
2287  uint32_t dev;
2288 
2289  if (device.contains('.')) // Simplistic check, but also allows DNS names
2290  deviceIsIP = true;
2291  else
2292  {
2293  bool validID;
2294 
2295  dev = device.toUInt(&validID, 16);
2296  if (!validID || !hdhomerun_discover_validate_device_id(dev))
2297  return QObject::tr("Invalid Device ID");
2298  }
2299  (void) deviceIsIP;
2300 
2301  LOG(VB_GENERAL, LOG_INFO, "CardUtil::GetHDHRdescription(" + device +
2302  ") - trying to locate device");
2303 
2304  hdhomerun_device_t *hdhr;
2305  hdhr = hdhomerun_device_create_from_str(device.toLatin1(), NULL);
2306  if (!hdhr)
2307  return QObject::tr("Invalid Device ID or address.");
2308 
2309  const char *model = hdhomerun_device_get_model_str(hdhr);
2310  if (!model)
2311  {
2312  hdhomerun_device_destroy(hdhr);
2313  return connectErr;
2314  }
2315 
2316 
2317  QString description = model;
2318  char *sVersion;
2319  uint32_t iVersion;
2320 
2321  if (hdhomerun_device_get_version(hdhr, &sVersion, &iVersion))
2322  description += QObject::tr(", firmware: %2").arg(sVersion);
2323 
2324  hdhomerun_device_destroy(hdhr);
2325 
2326  return description;
2327 #else
2328 
2329  (void) device;
2330  return connectErr;
2331 #endif
2332 }
2333 
2338 QString CardUtil::GetVBoxdesc(const QString &id, const QString &ip,
2339  const QString &tunerNo, const QString &tunerType)
2340 {
2341  QString connectErr = QObject::tr("Unable to connect to device.");
2342 
2343 #ifdef USING_VBOX
2344  VBox *vbox = new VBox(ip);
2345 
2346  if (!vbox->checkConnection())
2347  {
2348  delete vbox;
2349  return connectErr;
2350  }
2351 
2352  QString version;
2353 
2354  if (!vbox->checkVersion(version))
2355  {
2356  QString apiVersionErr = QObject::tr("The VBox software version is to old (%1), we require %2")
2357  .arg(version).arg(VBOX_MIN_API_VERSION);
2358  delete vbox;
2359  return apiVersionErr;
2360 
2361  }
2362 
2363  delete vbox;
2364 
2365  return QString("V@Box TV Gateway - ID: %1, IP: %2, Tuner: %3-%4").arg(id)
2366  .arg(ip).arg(tunerNo).arg(tunerType);
2367 
2368 #else
2369  (void) id;
2370  (void) ip;
2371  (void) tunerNo;
2372  (void) tunerType;
2373 
2374  return connectErr;
2375 #endif
2376 }
2377 
2378 #ifdef USING_ASI
2379 static QString sys_dev(uint device_num, QString dev)
2380 {
2381  return QString("/sys/class/asi/asirx%1/%2").arg(device_num).arg(dev);
2382 }
2383 
2384 static QString read_sys(QString sys_dev)
2385 {
2386  QFile f(sys_dev);
2387  f.open(QIODevice::ReadOnly);
2388  QByteArray sdba = f.readAll();
2389  f.close();
2390  return sdba;
2391 }
2392 
2393 static bool write_sys(QString sys_dev, QString str)
2394 {
2395  QFile f(sys_dev);
2396  f.open(QIODevice::WriteOnly);
2397  QByteArray ba = str.toLocal8Bit();
2398  qint64 offset = 0;
2399  for (uint tries = 0; (offset < ba.size()) && tries < 5; tries++)
2400  {
2401  qint64 written = f.write(ba.data()+offset, ba.size()-offset);
2402  if (written < 0)
2403  return false;
2404  offset += written;
2405  }
2406  return true;
2407 }
2408 #endif
2409 
2410 int CardUtil::GetASIDeviceNumber(const QString &device, QString *error)
2411 {
2412 #ifdef USING_ASI
2413  // basic confirmation
2414  struct stat statbuf;
2415  memset(&statbuf, 0, sizeof(statbuf));
2416  if (stat(device.toLocal8Bit().constData(), &statbuf) < 0)
2417  {
2418  if (error)
2419  *error = QString("Unable to stat '%1'").arg(device) + ENO;
2420  return -1;
2421  }
2422 
2423  if (!S_ISCHR(statbuf.st_mode))
2424  {
2425  if (error)
2426  *error = QString("'%1' is not a character device").arg(device);
2427  return -1;
2428  }
2429 
2430  if (!(statbuf.st_rdev & 0x0080))
2431  {
2432  if (error)
2433  *error = QString("'%1' not a DVEO ASI receiver").arg(device);
2434  return -1;
2435  }
2436 
2437  int device_num = statbuf.st_rdev & 0x007f;
2438 
2439  // extra confirmation
2440  QString sys_dev_contents = read_sys(sys_dev(device_num, "dev"));
2441  QStringList sys_dev_clist = sys_dev_contents.split(":");
2442  if (2 != sys_dev_clist.size())
2443  {
2444  if (error)
2445  {
2446  *error = QString("Unable to read '%1'")
2447  .arg(sys_dev(device_num, "dev"));
2448  }
2449  return -1;
2450  }
2451  if (sys_dev_clist[0].toUInt() != (statbuf.st_rdev>>8))
2452  {
2453  if (error)
2454  *error = QString("'%1' not a DVEO ASI device").arg(device);
2455  return -1;
2456  }
2457 
2458  return device_num;
2459 #else
2460  (void) device;
2461  if (error)
2462  *error = "Not compiled with ASI support.";
2463  return -1;
2464 #endif
2465 }
2466 
2468 {
2469 #ifdef USING_ASI
2470  // get the buffer size
2471  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "bufsize"));
2472  bool ok;
2473  uint buf_size = sys_bufsize_contents.toUInt(&ok);
2474  if (!ok)
2475  {
2476  if (error)
2477  {
2478  *error = QString("Failed to read buffer size from '%1'")
2479  .arg(sys_dev(device_num, "bufsize"));
2480  }
2481  return 0;
2482  }
2483  return buf_size;
2484 #else
2485  (void) device_num;
2486  if (error)
2487  *error = "Not compiled with ASI support.";
2488  return 0;
2489 #endif
2490 }
2491 
2493 {
2494 #ifdef USING_ASI
2495  // get the buffer size
2496  QString sys_numbuffers_contents = read_sys(sys_dev(device_num, "buffers"));
2497  bool ok;
2498  uint num_buffers = sys_numbuffers_contents.toUInt(&ok);
2499  if (!ok)
2500  {
2501  if (error)
2502  {
2503  *error = QString("Failed to read num buffers from '%1'")
2504  .arg(sys_dev(device_num, "buffers"));
2505  }
2506  return 0;
2507  }
2508  return num_buffers;
2509 #else
2510  (void) device_num;
2511  if (error)
2512  *error = "Not compiled with ASI support.";
2513  return 0;
2514 #endif
2515 }
2516 
2517 int CardUtil::GetASIMode(uint device_num, QString *error)
2518 {
2519 #ifdef USING_ASI
2520  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "mode"));
2521  bool ok;
2522  uint mode = sys_bufsize_contents.toUInt(&ok);
2523  if (!ok)
2524  {
2525  if (error)
2526  {
2527  *error = QString("Failed to read mode from '%1'")
2528  .arg(sys_dev(device_num, "mode"));
2529  }
2530  return -1;
2531  }
2532  return mode;
2533 #else
2534  (void) device_num;
2535  if (error)
2536  *error = "Not compiled with ASI support.";
2537  return -1;
2538 #endif
2539 }
2540 
2541 bool CardUtil::SetASIMode(uint device_num, uint mode, QString *error)
2542 {
2543 #ifdef USING_ASI
2544  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "mode"));
2545  bool ok;
2546  uint old_mode = sys_bufsize_contents.toUInt(&ok);
2547  if (ok && old_mode == mode)
2548  return true;
2549  ok = write_sys(sys_dev(device_num, "mode"), QString("%1\n").arg(mode));
2550  if (!ok && error)
2551  {
2552  *error = QString("Failed to set mode to %1 using '%2'")
2553  .arg(mode).arg(sys_dev(device_num, "mode"));
2554  }
2555  return ok;
2556 #else
2557  (void) device_num;
2558  if (error)
2559  *error = "Not compiled with ASI support.";
2560  return false;
2561 #endif
2562 }
static QStringList GetCardTypes(void)
Definition: cardutil.cpp:238
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:785
uint scheduleOrder
Definition: inputinfo.h:80
dvb_dev_type_t
Definition: cardutil.h:33
static bool IsTunerSharingCapable(const QString &rawtype)
Definition: cardutil.h:159
static bool HasDVBCRCBug(const QString &device)
Returns true if and only if the device munges PAT/PMT tables, and then doesn't fix the CRC...
Definition: cardutil.cpp:508
int recPriority
Definition: inputinfo.h:79
static QStringList ProbeVideoDevices(const QString &rawtype)
Definition: cardutil.cpp:307
void bindValue(const QString &placeholder, const QVariant &val)
Definition: mythdbcon.cpp:884
DVB-S device settings class.
Definition: diseqc.h:37
static vector< uint > GetCardIDs(QString videodevice=QString::null, QString rawtype=QString::null, QString inputname=QString::null, QString hostname=QString::null)
Returns all cardids of cards that uses the specified videodevice if specified, and optionally rawtype...
Definition: cardutil.cpp:641
static QString GetInputName(uint inputid)
Definition: cardutil.cpp:1125
DiSEqCDevDevice * Root(void)
Retrieves the root node in the tree.
Definition: diseqc.h:93
static uint GetASINumBuffers(uint device_num, QString *error=NULL)
Definition: cardutil.cpp:2492
static bool CloneCard(uint src_cardid, uint dst_cardid)
Definition: cardutil.cpp:875
static vector< uint > GetGroupCardIDs(uint inputgroupid)
Definition: cardutil.cpp:1545
DiSEqCDevTree * FindTree(uint cardid)
Retrieve device tree.
Definition: diseqc.cpp:248
static QStringList GetVideoDevices(const QString &rawtype, QString hostname=QString::null)
Returns the videodevices of the matching cards, duplicates removed.
Definition: cardutil.cpp:264
bool Store(uint cardid)
Stores the device tree to the database.
Definition: diseqc.cpp:402
static int CreateCaptureCard(const QString &videodevice, const QString &audiodevice, const QString &vbidevice, const QString &cardtype, const uint audioratelimit, const QString &hostname, const uint dvb_swfilter, const uint dvb_sat_type, bool dvb_wait_for_seqstart, bool skipbtaudio, bool dvb_on_demand, const uint dvb_diseqc_type, const uint firewire_speed, const QString &firewire_model, const uint firewire_connection, const uint signal_timeout, const uint channel_timeout, const uint dvb_tuning_delay, const uint contrast, const uint brightness, const uint colour, const uint hue, const uint diseqcid, bool dvb_eitscan)
Definition: cardutil.cpp:2007
static vector< uint > GetSharedInputGroups(uint cardid)
Definition: cardutil.cpp:1521
static uint CreateInputGroup(const QString &name)
Definition: cardutil.cpp:1358
bool Load(uint cardid)
Loads the device tree from the database.
Definition: diseqc.cpp:331
static QString ProbeDVBType(const QString &device)
Definition: cardutil.cpp:416
QVariant value(int i) const
Definition: mythdbcon.h:182
static void error(const char *str,...)
Definition: vbi.c:41
static int CreateCardInput(const uint cardid, const uint sourceid, const QString &inputname, const QString &externalcommand, const QString &changer_device, const QString &changer_model, const QString &hostname, const QString &tunechan, const QString &startchan, const QString &displayname, bool dishnet_eit, const uint recpriority, const uint quicktune, const uint schedorder, const uint livetvorder)
Definition: cardutil.cpp:1252
uint sourceid
associated channel listings source
Definition: inputinfo.h:73
bool checkVersion(QString &version)
Definition: vboxutils.cpp:207
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
Definition: vboxutils.h:13
static QString ProbeDVBFrontendName(const QString &device)
Returns the card type from the video device.
Definition: cardutil.cpp:462
static bool IsTunerShared(uint cardidA, uint cardidB)
Definition: cardutil.cpp:157
static QString GetRawCardType(uint cardid)
Definition: cardutil.h:263
static QStringList ProbeDVBInputs(QString device)
Definition: cardutil.cpp:1925
static bool write_sys(QString sys_dev, QString str)
Definition: cardutil.cpp:2393
static bool IsInNeedOfExternalInputConf(uint cardid)
Definition: cardutil.cpp:1626
static uint GetChildCardCount(uint cardid)
Definition: cardutil.cpp:693
static vector< uint > GetConflictingCards(uint inputid, uint exclude_cardid)
Definition: cardutil.cpp:1572
unsigned int uint
Definition: compat.h:136
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static bool IsCardTypePresent(const QString &rawtype, QString hostname=QString::null)
Returns true if the card type is present and connected to an input.
Definition: cardutil.cpp:204
static uint clone_capturecard(uint src_cardid, uint orig_dst_cardid)
Definition: cardutil.cpp:745
GLint GLenum GLsizei GLint GLenum GLenum type
static bool DeleteCard(uint cardid)
Definition: cardutil.cpp:2100
static bool GetInputInfo(InputInfo &info, vector< uint > *groupids=NULL)
Definition: cardutil.cpp:1046
bool set_on_input(const QString &to_set, uint inputid, const QString &value)
Definition: cardutil.cpp:607
static bool DeleteInput(uint inputid)
Definition: cardutil.cpp:1312
static QString GetScanableCardTypes(void)
Definition: cardutil.cpp:54
static const int kTunerTypeDVBS1
uint cardid
card id associated with input
Definition: inputinfo.h:75
bool Load(uint card_input_id)
Loads configuration chain from DB for specified card input id.
Definition: diseqc.cpp:137
static QString sys_dev(uint device_num, QString dev)
Definition: cardutil.cpp:2379
static uint CreateDeviceInputGroup(const QString &host, const QString &device)
Definition: cardutil.h:332
static QStringList ProbeVideoInputs(QString device, QString cardtype=QString::null)
Definition: cardutil.cpp:1835
static QString GetVBoxdesc(const QString &id, const QString &ip, const QString &tunerNo, const QString &tunerType)
Get a nicely formatted string describing the device.
Definition: cardutil.cpp:2338
static vector< uint > GetChildCardIDs(uint cardid)
Definition: cardutil.cpp:717
QString displayName
Definition: inputinfo.h:78
voidpf uLong offset
Definition: ioapi.h:142
static const int kTunerTypeDVBS2
static InputNames ProbeV4LAudioInputs(int videofd, bool &ok)
Definition: cardutil.cpp:1778
static QString GetStartInput(uint cardid)
Returns the start input for the card.
Definition: cardutil.cpp:993
static uint GetDeviceInputGroup(uint cardid)
Definition: cardutil.cpp:1400
void SetRoot(DiSEqCDevDevice *root)
Changes the root node of the tree.
Definition: diseqc.cpp:611
uint livetvorder
order for live TV use
Definition: inputinfo.h:81
static QString GetDeviceName(dvb_dev_type_t, const QString &device)
Definition: cardutil.cpp:2224
static bool DeleteOrphanInputs(void)
Definition: cardutil.cpp:1353
static uint GetCardID(uint inputid)
Definition: cardutil.cpp:1118
static vector< uint > GetInputIDs(uint cardid)
Definition: cardutil.cpp:1228
static QString GetFirewireChangerModel(uint inputid)
Definition: cardutil.cpp:905
static bool UnlinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:1464
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:542
static bool IsSingleInputCard(const QString &rawtype)
Definition: cardutil.h:190
static QList< InputInfo > GetAllInputInfo()
Definition: cardutil.cpp:1083
static InputNames GetConfiguredDVBInputs(const QString &device)
Definition: cardutil.cpp:1811
static bool HDHRdoesDVB(const QString &device)
If the device is valid, check if the model does DVB.
Definition: cardutil.cpp:2253
const char * name
Definition: ParseText.cpp:338
static uint GetASIBufferSize(uint device_num, QString *error=NULL)
Definition: cardutil.cpp:2467
uint inputid
unique key in DB for this input
Definition: inputinfo.h:74
static QString ProbeSubTypeName(uint cardid)
Definition: cardutil.cpp:525
bool isActive(void) const
Definition: mythdbcon.h:188
static int GetASIDeviceNumber(const QString &device, QString *error=NULL)
Definition: cardutil.cpp:2410
static bool SetASIMode(uint device_num, uint mode, QString *error=NULL)
Definition: cardutil.cpp:2541
QString toString() const
static QString GetFirewireChangerNode(uint inputid)
Definition: cardutil.cpp:888
static QStringList ProbeAudioInputs(QString device, QString cardtype=QString::null)
Definition: cardutil.cpp:1849
static QStringList probeDevices(void)
Definition: vboxutils.cpp:36
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:810
bool quickTune
Definition: inputinfo.h:82
static QString GetVideoDevice(uint cardid)
Definition: cardutil.h:265
static QStringList GetInputNames(uint cardid, uint sourceid=0)
Definition: cardutil.cpp:1012
static vector< uint > GetCardList(void)
Definition: cardutil.cpp:2180
static uint GetQuickTuning(uint cardid, const QString &inputname)
Definition: cardutil.cpp:1638
static bool GetTimeouts(uint cardid, uint &signal_timeout, uint &channel_timeout)
Definition: cardutil.cpp:1604
bool set_on_source(const QString &to_set, uint cardid, uint sourceid, const QString &value)
Definition: cardutil.cpp:564
typedef void(APIENTRY *MYTH_GLTEXIMAGE1DPROC)(GLenum target
QString get_on_cardid(const QString &to_get, uint cardid)
Definition: cardutil.cpp:547
QString name
input name
Definition: inputinfo.h:72
static QString GetDeviceLabel(const QString &cardtype, const QString &videodevice)
Definition: cardutil.cpp:1945
static bool SetStartChannel(uint cardinputid, const QString &channum)
Definition: cardutil.cpp:970
QMap< int, QString > InputNames
Definition: cardutil.h:22
static const QString LOC
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1191
static void GetCardInputs(uint cardid, const QString &device, const QString &cardtype, QStringList &inputs)
Definition: cardutil.cpp:1968
static bool hasV4L2(int videofd)
Definition: cardutil.cpp:1659
const char int mode
Definition: ioapi.h:135
bool Store(uint card_input_id) const
Stores configuration chain to DB for specified card input id.
Definition: diseqc.cpp:171
static int GetCardInputID(uint cardid, const QString &channum, QString &inputname)
Definition: cardutil.cpp:946
static bool GetV4LInfo(int videofd, QString &card, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:1673
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:610
bool checkConnection(void)
Definition: vboxutils.cpp:201
static bool LinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:1424
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:181
static bool DeleteAllCards(void)
Definition: cardutil.cpp:2171
static uint GetInputID(uint cardid, const QString &inputname)
Definition: cardutil.cpp:1173
static bool IsCableCardPresent(uint cardid, const QString &cardType)
Definition: cardutil.cpp:113
QString GetHostName(void)
static vector< uint > GetLiveTVCardList(void)
Definition: cardutil.cpp:2201
DVB-S device tree class.
Definition: diseqc.h:75
static vector< uint > GetAllInputIDs(void)
Definition: cardutil.cpp:1207
bool IsInNeedOfConf(void) const
Definition: diseqc.cpp:810
static InputNames ProbeV4LVideoInputs(int videofd, bool &ok)
Definition: cardutil.cpp:1711
static int GetASIMode(uint device_num, QString *error=NULL)
Definition: cardutil.cpp:2517
static QString GetHDHRdesc(const QString &device)
Get a nicely formatted string describing the device.
Definition: cardutil.cpp:2281
static bool IsDVBCardType(const QString &card_type)
Returns true iff the card_type is one of the DVB types.
Definition: cardutil.cpp:540
static vector< uint > GetInputGroups(uint inputid)
Definition: cardutil.cpp:1495
static uint GetMinSignalMonitoringDelay(const QString &device)
Definition: cardutil.cpp:515
QString get_on_inputid(const QString &to_get, uint inputid)
Definition: cardutil.cpp:590
static QString GetStartingChannel(uint inputid)
Definition: cardutil.cpp:1132
Main DVB-S device interface.
Definition: diseqc.h:52
static QString read_sys(QString sys_dev)
Definition: cardutil.cpp:2384
static QString GetDisplayName(uint inputid)
Definition: cardutil.cpp:1148