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