MythTV  master
diseqc.cpp
Go to the documentation of this file.
1 /* -*- Mode: c++ -*-
2  * \file dvbdevtree.cpp
3  * \brief DVB-S Device Tree Control Classes.
4  * \author Copyright (C) 2006, Yeasah Pell
5  */
6 
7 // Std C headers
8 #include <cstring>
9 #include <cmath>
10 #include <unistd.h>
11 
12 // POSIX headers
13 #include <sys/time.h>
14 
15 // Qt headers
16 #include <QString>
17 
18 // MythTV headers
19 #include "mythcorecontext.h"
20 #include "mythdb.h"
21 #include "mythlogging.h"
22 #include "diseqc.h"
23 #include "dtvmultiplex.h"
24 #include "compat.h"
25 
26 #ifdef USING_DVB
27 # include "dvbtypes.h"
28 #else
29 # define SEC_VOLTAGE_13 0
30 # define SEC_VOLTAGE_18 1
31 # define SEC_VOLTAGE_OFF 2
32 # define SEC_MINI_A 0
33 # define SEC_MINI_B 1
34 #endif
35 
36 // DiSEqC sleep intervals per eutelsat spec
37 #define DISEQC_SHORT_WAIT (15 * 1000)
38 #define DISEQC_LONG_WAIT (100 * 1000)
39 #define DISEQC_POWER_OFF_WAIT ((1000 * 1000) - 1)
40 #define DISEQC_POWER_ON_WAIT (500 * 1000)
41 
42 // Number of times to retry ioctls after receiving ETIMEDOUT before giving up
43 #define TIMEOUT_RETRIES 10
44 #define TIMEOUT_WAIT (250 * 1000)
45 
46 // Framing byte
47 #define DISEQC_FRM 0xe0
48 #define DISEQC_FRM_REPEAT (1 << 0)
49 #define DISEQC_FRM_REPLY_REQ (1 << 1)
50 
51 // Address byte
52 #define DISEQC_ADR_ALL 0x00
53 #define DISEQC_ADR_SW_ALL 0x10
54 #define DISEQC_ADR_LNB 0x11
55 #define DISEQC_ADR_LNB_SW 0x12
56 #define DISEQC_ADR_SW_BLK 0x14
57 #define DISEQC_ADR_SW 0x15
58 #define DISEQC_ADR_SMATV 0x18
59 #define DISEQC_ADR_POL_ALL 0x20
60 #define DISEQC_ADR_POL_LIN 0x21
61 #define DISEQC_ADR_POS_ALL 0x30
62 #define DISEQC_ADR_POS_AZ 0x31
63 #define DISEQC_ADR_POS_EL 0x32
64 
65 // Command byte
66 #define DISEQC_CMD_RESET 0x00
67 #define DISEQC_CMD_CLR_RESET 0x01
68 #define DISEQC_CMD_WRITE_N0 0x38
69 #define DISEQC_CMD_WRITE_N1 0x39
70 #define DISEQC_CMD_WRITE_FREQ 0x58
71 #define DISEQC_CMD_ODU 0x5A
72 #define DISEQC_CMD_ODU_MDU 0x5C
73 #define DISEQC_CMD_HALT 0x60
74 #define DISEQC_CMD_LMT_OFF 0x63
75 #define DISEQC_CMD_LMT_E 0x66
76 #define DISEQC_CMD_LMT_W 0x67
77 #define DISEQC_CMD_DRIVE_E 0x68
78 #define DISEQC_CMD_DRIVE_W 0x69
79 #define DISEQC_CMD_STORE_POS 0x6a
80 #define DISEQC_CMD_GOTO_POS 0x6b
81 #define DISEQC_CMD_GOTO_X 0x6e
82 
83 #define TO_RADS (M_PI / 180.0)
84 #define TO_DEC (180.0 / M_PI)
85 
86 #define EPS 1E-4
87 
88 #define LOC QString("DiSEqCDevTree: ")
89 
91 
93 {
94  for (; !table->name.isEmpty(); table++)
95  {
96  if (type == table->value)
97  {
98  return table->name;
99  }
100  }
101  return QString();
102 }
103 
105  const TypeTable *table)
106 {
107  uint first_val = table->value;
108  for (; !table->name.isEmpty(); table++)
109  {
110  if (type == table->name)
111  return table->value;
112  }
113  return first_val;
114 }
115 
117 
130 bool DiSEqCDevSettings::Load(uint card_input_id)
131 {
132  if (card_input_id == m_inputId)
133  return true;
134 
135  m_config.clear();
136 
137  // load settings from DB
138  MSqlQuery query(MSqlQuery::InitCon());
139  query.prepare(
140  "SELECT diseqcid, value "
141  "FROM diseqc_config "
142  "WHERE cardinputid = :INPUTID");
143 
144  query.bindValue(":INPUTID", card_input_id);
145  if (!query.exec() || !query.isActive())
146  {
147  MythDB::DBError("DiSEqCDevSettings::Load", query);
148  return false;
149  }
150 
151  while (query.next())
152  m_config[query.value(0).toUInt()] = query.value(1).toDouble();
153 
154  m_inputId = card_input_id;
155 
156  return true;
157 }
158 
164 bool DiSEqCDevSettings::Store(uint card_input_id) const
165 {
166  MSqlQuery query(MSqlQuery::InitCon());
167 
168  // clear out previous settings
169  query.prepare(
170  "DELETE from diseqc_config "
171  "WHERE cardinputid = :INPUTID");
172  query.bindValue(":INPUTID", card_input_id);
173 
174  if (!query.exec() || !query.isActive())
175  {
176  MythDB::DBError("DiSEqCDevSettings::Store 1", query);
177  return false;
178  }
179 
180  // insert new settings
181  query.prepare(
182  "INSERT INTO diseqc_config "
183  " ( cardinputid, diseqcid, value) "
184  "VALUES (:INPUTID, :DEVID, :VALUE) ");
185 
186  uint_to_dbl_t::const_iterator it = m_config.begin();
187  for (; it != m_config.end(); ++it)
188  {
189  query.bindValue(":INPUTID", card_input_id);
190  query.bindValue(":DEVID", it.key());
191  query.bindValue(":VALUE", *it);
192  if (!query.exec() || !query.isActive())
193  {
194  MythDB::DBError("DiSEqCDevSettings::Store 2", query);
195  return false;
196  }
197  }
198 
199  return true;
200 }
201 
208 {
209  uint_to_dbl_t::const_iterator it = m_config.find(devid);
210 
211  if (it != m_config.end())
212  return *it;
213 
214  return 0.0;
215 }
216 
222 void DiSEqCDevSettings::SetValue(uint devid, double value)
223 {
224  m_config[devid] = value;
225  m_inputId = (uint) -1;
226 }
227 
229 
235 
241 {
242  return s_trees.FindTree(cardid);
243 }
244 
249 {
251 }
252 
254 
260 {
261  InvalidateTrees();
262 }
263 
269 {
270  QMutexLocker lock(&m_treesLock);
271 
272  cardid_to_diseqc_tree_t::iterator it = m_trees.find(cardid);
273  if (it != m_trees.end())
274  return *it;
275 
276  auto *tree = new DiSEqCDevTree;
277  tree->Load(cardid);
278  m_trees[cardid] = tree;
279 
280  return tree;
281 }
282 
287 {
288  QMutexLocker lock(&m_treesLock);
289 
290  cardid_to_diseqc_tree_t::iterator it = m_trees.begin();
291  for (; it != m_trees.end(); ++it)
292  delete *it;
293 
294  m_trees.clear();
295 }
296 
298 
303 const uint DiSEqCDevTree::kFirstFakeDiSEqCID = 0xf0000000;
304 
306 {
307  delete m_root;
308 }
309 
315 bool DiSEqCDevTree::Load(const QString &device)
316 {
317  // lookup configuration for this card
318  MSqlQuery query(MSqlQuery::InitCon());
319  query.prepare(
320  "SELECT cardid "
321  "FROM capturecard "
322  "WHERE hostname = :HOSTNAME AND "
323  " videodevice = :VIDEODEVICE "
324  "LIMIT 1");
325  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
326  query.bindValue(":VIDEODEVICE", device);
327 
328  uint cardid = 0;
329 
330  if (!query.exec())
331  {
332  MythDB::DBError("DiSEqCDevTree::Load", query);
333  }
334  else if (query.next())
335  {
336  cardid = query.value(0).toUInt();
337  }
338 
339  return Load(cardid);
340 }
341 
348 {
349  // clear children
350 
351  // TODO find root cause so that "delete m_root" can be enabled again, see ticket #13465
352  // Not doing the "delete m_root" fixes a segfault but creates a memory leak
353 #if 0
354  delete m_root;
355 #endif
356  m_delete.clear();
357  m_root = nullptr;
358 
359  // lookup configuration for this card
360  MSqlQuery query(MSqlQuery::InitCon());
361  query.prepare(
362  "SELECT diseqcid, cardtype, inputname "
363  "FROM capturecard "
364  "WHERE cardid = :CARDID");
365  query.bindValue(":CARDID", cardid);
366 
367  if (!query.exec())
368  {
369  MythDB::DBError("DiSEqCDevTree::Load", query);
370  }
371  else if (!query.next())
372  {
373  return m_root;
374  }
375 
376  if (query.value(0).toBool())
377  {
379  *this, query.value(0).toUInt());
380  }
381  else if ((query.value(1).toString().toUpper() == "DVB") &&
382  ((query.value(2).toString().toUpper() == "DVB-S" ) ||
383  (query.value(2).toString().toUpper() == "DVB-S2") ))
384  {
385  LOG(VB_GENERAL, LOG_WARNING, LOC +
386  QString("No device tree for cardid %1").arg(cardid));
387  }
388 
389  return m_root;
390 }
391 
397 bool DiSEqCDevTree::Exists(int cardid)
398 {
399  // lookup configuration for this card
400  MSqlQuery query(MSqlQuery::InitCon());
401  query.prepare(
402  "SELECT diseqcid "
403  "FROM capturecard "
404  "WHERE cardid = :CARDID");
405  query.bindValue(":CARDID", cardid);
406 
407  if (!query.exec())
408  {
409  MythDB::DBError("DiSEqCDevTree::Load", query);
410  }
411  else if (query.next())
412  {
413  if (query.value(0).toUInt() > 0)
414  return true;
415  }
416 
417  return false;
418 }
419 
426 bool DiSEqCDevTree::Store(uint cardid, const QString &device)
427 {
428  MSqlQuery query0(MSqlQuery::InitCon());
429 
430  // apply pending node deletions
431  if (!m_delete.empty())
432  {
433  MSqlQuery query1(MSqlQuery::InitCon());
434 
435  query0.prepare(
436  "DELETE FROM diseqc_tree "
437  "WHERE diseqcid = :DEVID");
438  query1.prepare(
439  "DELETE FROM diseqc_config "
440  "WHERE diseqcid = :DEVID");
441 
442  vector<uint>::const_iterator it = m_delete.begin();
443  for (; it != m_delete.end(); ++it)
444  {
445  query0.bindValue(":DEVID", *it);
446  if (!query0.exec())
447  MythDB::DBError("DiSEqCDevTree::Store 1", query0);
448 
449  query1.bindValue(":DEVID", *it);
450  if (!query1.exec())
451  MythDB::DBError("DiSEqCDevTree::Store 2", query1);
452 
453  }
454  m_delete.clear();
455  }
456 
457  // store changed and new nodes
458  uint devid = 0;
459  if (m_root && m_root->Store())
460  devid = m_root->GetDeviceID();
461  else if (m_root)
462  {
463  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to save DiSEqC tree.");
464  return false;
465  }
466 
467  // update capture card to point to tree, or 0 if there is no tree
468  query0.prepare(
469  "UPDATE capturecard "
470  "SET diseqcid = :DEVID "
471  "WHERE (hostname = :HOSTNAME AND "
472  " videodevice = :VIDEODEVICE) "
473  " OR cardid = :CARDID");
474  query0.bindValue(":DEVID", devid);
475  query0.bindValue(":HOSTNAME", gCoreContext->GetHostName());
476  query0.bindValue(":VIDEODEVICE", device);
477  query0.bindValue(":CARDID", cardid);
478  if (!query0.exec())
479  {
480  MythDB::DBError("DiSEqCDevTree::Store 3", query0);
481  return false;
482  }
483 
484  return true;
485 }
486 
488 {
489  (void) on;
490 
491  bool success = false;
492 
493 #ifdef USING_DVB
494  for (uint retry = 0; !success && (retry < TIMEOUT_RETRIES); retry++)
495  {
496  if (ioctl(m_fdFrontend, FE_SET_TONE,
497  on ? SEC_TONE_ON : SEC_TONE_OFF) == 0)
498  success = true;
499  else
500  usleep(TIMEOUT_WAIT);
501  }
502 #endif // USING_DVB
503 
504  if (!success)
505  LOG(VB_GENERAL, LOG_ERR, LOC + "FE_SET_TONE failed" + ENO);
506 
507  return success;
508 }
509 
517  const DTVMultiplex &tuning)
518 {
519  if (!m_root)
520  {
521  LOG(VB_GENERAL, LOG_ERR, LOC + "No root device tree node!");
522  return false;
523  }
524 
525  // apply any voltage change
526  ApplyVoltage(settings, tuning);
527 
528  // turn off tone burst first if commands need to be sent
529  if (m_root->IsCommandNeeded(settings, tuning))
530  {
531  SetTone(false);
532  usleep(DISEQC_SHORT_WAIT);
533  }
534 
535  return m_root->Execute(settings, tuning);
536 }
537 
544 {
545  if (m_root)
546  m_root->Reset();
547 
548  m_lastVoltage = (uint) -1;
549 }
550 
558 {
559  DiSEqCDevDevice *node = m_root;
560  DiSEqCDevRotor *rotor = nullptr;
561 
562  for (uint count = 0; node;)
563  {
564  rotor = dynamic_cast<DiSEqCDevRotor*>(node);
565 
566  if (rotor && (++count > index))
567  break;
568 
569  node = node->GetSelectedChild(settings);
570  }
571 
572  return rotor;
573 }
574 
581 {
582  DiSEqCDevDevice *node = m_root;
583  DiSEqCDevLNB *lnb = nullptr;
584 
585  while (node)
586  {
587  lnb = dynamic_cast<DiSEqCDevLNB*>(node);
588 
589  if (lnb)
590  break;
591 
592  node = node->GetSelectedChild(settings);
593  }
594 
595  return lnb;
596 }
597 
604 {
605  DiSEqCDevDevice *node = m_root;
606  DiSEqCDevSCR *scr = nullptr;
607 
608  while (node)
609  {
610  scr = dynamic_cast<DiSEqCDevSCR*>(node);
611 
612  if (scr)
613  break;
614 
615  node = node->GetSelectedChild(settings);
616  }
617 
618  return scr;
619 }
620 
621 
628 {
629  if (m_root)
630  return m_root->FindDevice(dev_id);
631 
632  return nullptr;
633 }
634 
640 {
641  DiSEqCDevDevice *old_root = m_root;
642 
643  m_root = root;
644 
645  delete old_root;
646 }
647 
648 #ifdef USING_DVB
649 static bool send_diseqc(int fd, const dvb_diseqc_master_cmd &cmd)
650 {
651  (void) fd;
652  (void) cmd;
653 
654  bool success = false;
655 
656  for (uint retry = 0; !success && (retry < TIMEOUT_RETRIES); retry++)
657  {
658  if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd) == 0)
659  success = true;
660  else
661  usleep(TIMEOUT_WAIT);
662  }
663 
664  if (!success)
665  {
666  LOG(VB_GENERAL, LOG_ERR, LOC +
667  "send_diseqc FE_DISEQC_SEND_MASTER_CMD failed" + ENO);
668  }
669 
670  return success;
671 }
672 #endif //USING_DVB
673 
682 bool DiSEqCDevTree::SendCommand(uint adr, uint cmd, uint repeats,
683  uint data_len, unsigned char *data)
684 {
685  // check payload validity
686  if (data_len > 3 || (data_len > 0 && !data))
687  {
688  LOG(VB_GENERAL, LOG_ERR, LOC + "Bad DiSEqC command");
689  return false;
690  }
691 
692 #ifndef USING_DVB
693 
694  (void) adr;
695  (void) cmd;
696  (void) repeats;
697  return false;
698 
699 #else // if USING_DVB
700 
701  bool resend_cmd = false;
702 
703  // prepare command
704  dvb_diseqc_master_cmd mcmd = {};
705  mcmd.msg[0] = DISEQC_FRM;
706  mcmd.msg[1] = adr;
707  mcmd.msg[2] = cmd;
708  mcmd.msg_len = data_len + 3;
709 
710  if (data_len > 0)
711  memcpy(mcmd.msg + 3, data, data_len);
712 
713  // diagnostic
714  QString cmdstr;
715  for (uint byte = 0; byte < mcmd.msg_len; byte++)
716  cmdstr += QString("%1 ").arg(mcmd.msg[byte], 2, 16);
717 
718  LOG(VB_CHANNEL, LOG_INFO, LOC + "Sending DiSEqC Command: " + cmdstr);
719 
720  if (repeats >= 10)
721  {
722  repeats = repeats - 10;
723  resend_cmd = true;
724  }
725 
726  // send the command
727  for (uint i = 0; i <= repeats; i++)
728  {
729  if (!send_diseqc(GetFD(), mcmd))
730  {
731  LOG(VB_GENERAL, LOG_ERR, LOC + "DiSEqC command failed" + ENO);
732  return false;
733  }
734 
735  if (!resend_cmd)
736  mcmd.msg[0] |= DISEQC_FRM_REPEAT;
737 
738  usleep(DISEQC_SHORT_WAIT);
739  }
740 
741  return true;
742 
743 #endif // USING_DVB
744 }
745 
752 bool DiSEqCDevTree::ResetDiseqc(bool hard_reset, bool is_SCR)
753 {
754  Reset();
755 
756  // power cycle the bus if requested
757  // tests show that the wait times required can be very long (~1sec)
758  if (hard_reset)
759  {
760  LOG(VB_CHANNEL, LOG_INFO, LOC + "Power-cycling DiSEqC Bus");
761 
762  SetVoltage(SEC_VOLTAGE_OFF);
763  usleep(DISEQC_POWER_OFF_WAIT);
764  diseqc_bus_already_reset = false;
765  }
766 
767  if (!diseqc_bus_already_reset || !is_SCR)
768  {
769  // make sure the bus is powered
770  SetVoltage(SEC_VOLTAGE_18);
771  usleep(DISEQC_POWER_ON_WAIT);
772  // some DiSEqC devices need more time. see #8465
773  usleep(DISEQC_POWER_ON_WAIT);
774 
775  // issue a global reset command
776  LOG(VB_CHANNEL, LOG_INFO, LOC + "Resetting DiSEqC Bus");
778  {
779  LOG(VB_GENERAL, LOG_ERR, LOC + "DiSEqC reset failed" + ENO);
780  return false;
781  }
782 
783  if (is_SCR)
785  }
786  else
787  {
788  LOG(VB_CHANNEL, LOG_INFO, LOC + "Skipping reset: already done for this SCR bus");
789  }
790 
791  usleep(DISEQC_LONG_WAIT);
792 
793  return true;
794 }
795 
801 void DiSEqCDevTree::Open(int fd_frontend, bool is_SCR)
802 {
803  m_fdFrontend = fd_frontend;
804 
805  // issue reset command
806  ResetDiseqc(false, is_SCR);
807 }
808 
810 {
811 
812  if (voltage == m_lastVoltage)
813  return true;
814 
815  int volts = ((voltage == SEC_VOLTAGE_18) ? 18 :
816  ((voltage == SEC_VOLTAGE_13) ? 13 : 0));
817 
818  LOG(VB_CHANNEL, LOG_INFO, LOC + "Changing LNB voltage to " +
819  QString("%1V").arg(volts));
820 
821  bool success = false;
822 
823 #ifdef USING_DVB
824  for (uint retry = 0; !success && retry < TIMEOUT_RETRIES; retry++)
825  {
826  if (ioctl(m_fdFrontend, FE_SET_VOLTAGE, voltage) == 0)
827  success = true;
828  else
829  usleep(TIMEOUT_WAIT);
830  }
831 #endif // USING_DVB
832 
833  if (!success)
834  {
835  LOG(VB_GENERAL, LOG_ERR, LOC + "FE_SET_VOLTAGE failed" + ENO);
836  return false;
837  }
838 
839  m_lastVoltage = voltage;
840  return true;
841 }
842 
844 {
845  if (m_root)
847 
848  return false;
849 }
850 
852  const DTVMultiplex &tuning)
853 {
854  uint voltage = SEC_VOLTAGE_18;
855 
856  if (m_root)
857  voltage = m_root->GetVoltage(settings, tuning);
858 
859  return SetVoltage(voltage);
860 }
861 
863 
869 {
870  { "switch", kTypeSwitch },
871  { "rotor", kTypeRotor },
872  { "scr", kTypeSCR },
873  { "lnb", kTypeLNB },
874  { QString(), kTypeLNB },
875 };
876 
877 
879 {
880  if (IsRealDeviceID())
882 }
883 
885 {
886  DiSEqCDevDevice *dev = nullptr;
887 
888  if (GetDeviceID() == dev_id)
889  dev = this;
890 
891  uint num_children = GetChildCount();
892 
893  for (uint ch = 0; !dev && ch < num_children; ch++)
894  {
895  DiSEqCDevDevice *child = GetChild(ch);
896  if (child)
897  {
898  if (child->GetDeviceID() == dev_id)
899  dev = child;
900  else
901  dev = child->FindDevice(dev_id);
902  }
903  }
904 
905  return dev;
906 }
907 
909 {
910  // load settings from DB
911  MSqlQuery query(MSqlQuery::InitCon());
912  query.prepare(
913  "SELECT type, description "
914  "FROM diseqc_tree "
915  "WHERE diseqcid = :DEVID");
916  query.bindValue(":DEVID", devid);
917 
918  if (!query.exec() || !query.isActive())
919  {
920  MythDB::DBError("DiSEqCDevDevice::CreateById", query);
921  return nullptr;
922  }
923  if (!query.next())
924  {
925  LOG(VB_GENERAL, LOG_ERR, LOC + "CreateById failed to find dtv dev " +
926  QString("%1").arg(devid));
927 
928  return nullptr;
929  }
930 
931  dvbdev_t type = DevTypeFromString(query.value(0).toString());
932  QString desc = query.value(1).toString();
933  DiSEqCDevDevice *node = CreateByType(tree, type, devid);
934 
935  if (node)
936  {
937  node->SetDescription(desc);
938  node->Load();
939  }
940 
941  return node;
942 }
943 
945  dvbdev_t type,
946  uint dev_id)
947 {
948  if (!dev_id)
949  dev_id = tree.CreateFakeDiSEqCID();
950 
951  DiSEqCDevDevice *node = nullptr;
952  switch (type)
953  {
954  case kTypeSwitch:
955  node = new DiSEqCDevSwitch(tree, dev_id);
956  if (node)
957  node->SetDescription("Switch");
958  break;
959  case kTypeRotor:
960  node = new DiSEqCDevRotor(tree, dev_id);
961  if (node)
962  node->SetDescription("Rotor");
963  break;
964  case kTypeSCR:
965  node = new DiSEqCDevSCR(tree, dev_id);
966  if (node)
967  node->SetDescription("Unicable");
968  break;
969  case kTypeLNB:
970  node = new DiSEqCDevLNB(tree, dev_id);
971  if (node)
972  node->SetDescription("LNB");
973  break;
974  default:
975  break;
976  }
977 
978  if (node)
979  node->SetDeviceType(type);
980 
981  return node;
982 }
983 
1053 
1060 {
1061  { "legacy_sw21", kTypeLegacySW21 },
1062  { "legacy_sw42", kTypeLegacySW42 },
1063  { "legacy_sw64", kTypeLegacySW64 },
1064  { "tone", kTypeTone },
1065  { "diseqc", kTypeDiSEqCCommitted },
1066  { "diseqc_uncom", kTypeDiSEqCUncommitted },
1067  { "voltage", kTypeVoltage },
1068  { "mini_diseqc", kTypeMiniDiSEqC },
1069  { QString(), kTypeTone },
1070 };
1071 
1073  : DiSEqCDevDevice(tree, devid)
1074 {
1075  m_children.resize(m_numPorts);
1076 
1077  for (uint i = 0; i < m_numPorts; i++)
1078  m_children[i] = nullptr;
1079 
1081 }
1082 
1084 {
1085  auto it = m_children.begin();
1086  for (; it != m_children.end(); ++it)
1087  {
1088  if (*it)
1089  delete *it;
1090  }
1091 }
1092 
1094  const DTVMultiplex &tuning)
1095 {
1096  bool success = true;
1097 
1098  // sanity check switch position
1099  int pos = GetPosition(settings);
1100  if (pos < 0)
1101  return false;
1102 
1103  // perform switching
1104  if (ShouldSwitch(settings, tuning))
1105  {
1106  switch (m_type)
1107  {
1108  case kTypeTone:
1109  success = ExecuteTone(settings, tuning, pos);
1110  break;
1111  case kTypeDiSEqCCommitted:
1113  success = ExecuteDiseqc(settings, tuning, pos);
1114  break;
1115  case kTypeLegacySW21:
1116  case kTypeLegacySW42:
1117  case kTypeLegacySW64:
1118  success = ExecuteLegacy(settings, tuning, pos);
1119  break;
1120  case kTypeVoltage:
1121  success = ExecuteVoltage(settings, tuning, pos);
1122  break;
1123  case kTypeMiniDiSEqC:
1124  success = ExecuteMiniDiSEqC(settings, tuning, pos);
1125  break;
1126  default:
1127  success = false;
1128  LOG(VB_GENERAL, LOG_ERR, LOC +
1129  QString("Unknown switch type (%1)").arg((uint)m_type));
1130  break;
1131  }
1132 
1133  // if a child device will be sending a diseqc command, wait 100ms
1134  if (m_children[pos]->IsCommandNeeded(settings, tuning))
1135  {
1136  LOG(VB_CHANNEL, LOG_INFO, LOC + "Waiting for switch");
1137  usleep(DISEQC_LONG_WAIT);
1138  }
1139 
1140  m_lastPos = pos;
1141  }
1142 
1143  // chain to child if the switch was successful
1144  if (success)
1145  success = m_children[pos]->Execute(settings, tuning);
1146 
1147  return success;
1148 }
1149 
1151 {
1152  m_lastPos = (uint) -1;
1153  m_lastHighBand = (uint) -1;
1154  m_lastHorizontal = (uint) -1;
1155  auto it = m_children.begin();
1156  for (; it != m_children.end(); ++it)
1157  {
1158  if (*it)
1159  (*it)->Reset();
1160  }
1161 }
1162 
1164  const DTVMultiplex &tuning) const
1165 {
1166  int pos = GetPosition(settings);
1167  if (pos < 0)
1168  return false;
1169 
1170  return (ShouldSwitch(settings, tuning) ||
1171  m_children[pos]->IsCommandNeeded(settings, tuning));
1172 }
1173 
1175 {
1176  // sanity check switch position
1177  int pos = GetPosition(settings);
1178  if (pos < 0)
1179  return nullptr;
1180 
1181  return m_children[pos];
1182 }
1183 
1185 {
1186  return m_numPorts;
1187 }
1188 
1190 {
1191  if (ordinal < m_children.size())
1192  return m_children[ordinal];
1193 
1194  return nullptr;
1195 }
1196 
1198 {
1199  if (ordinal >= m_children.size())
1200  return false;
1201 
1202  if (m_children[ordinal])
1203  delete m_children[ordinal];
1204 
1205  m_children[ordinal] = device;
1206  if (device)
1207  {
1208  device->SetOrdinal(ordinal);
1209  device->SetParent(this);
1210  }
1211 
1212  return true;
1213 }
1214 
1216  const DTVMultiplex &tuning) const
1217 {
1218  uint voltage = SEC_VOLTAGE_18;
1219  DiSEqCDevDevice *child = GetSelectedChild(settings);
1220 
1221  if (child)
1222  voltage = child->GetVoltage(settings, tuning);
1223 
1224  return voltage;
1225 }
1226 
1228 {
1229  // clear old children
1230  auto it = m_children.begin();
1231  for (; it != m_children.end(); ++it)
1232  {
1233  if (*it)
1234  delete *it;
1235  }
1236 
1237  m_children.clear();
1238 
1239  // populate switch parameters from db
1240  MSqlQuery query(MSqlQuery::InitCon());
1241  query.prepare(
1242  "SELECT subtype, address, switch_ports, cmd_repeat "
1243  "FROM diseqc_tree "
1244  "WHERE diseqcid = :DEVID");
1245  query.bindValue(":DEVID", GetDeviceID());
1246 
1247  if (!query.exec() || !query.isActive())
1248  {
1249  MythDB::DBError("DiSEqCDevSwitch::Load 1", query);
1250  return false;
1251  }
1252  if (query.next())
1253  {
1254  m_type = SwitchTypeFromString(query.value(0).toString());
1255  m_address = query.value(1).toUInt();
1256  m_numPorts = query.value(2).toUInt();
1257  m_repeat = query.value(3).toUInt();
1258  m_children.resize(m_numPorts);
1259  for (uint i = 0; i < m_numPorts; i++)
1260  m_children[i] = nullptr;
1261  }
1262 
1263  // load children from db
1264  query.prepare(
1265  "SELECT diseqcid, ordinal "
1266  "FROM diseqc_tree "
1267  "WHERE parentid = :DEVID");
1268  query.bindValue(":DEVID", GetDeviceID());
1269  if (!query.exec() || !query.isActive())
1270  {
1271  MythDB::DBError("DiSEqCDevSwitch::Load 2", query);
1272  return false;
1273  }
1274 
1275  while (query.next())
1276  {
1277  uint child_dev_id = query.value(0).toUInt();
1278  uint ordinal = query.value(1).toUInt();
1279  DiSEqCDevDevice *child = CreateById(m_tree, child_dev_id);
1280  if (child && !SetChild(ordinal, child))
1281  {
1282  LOG(VB_GENERAL, LOG_ERR, LOC +
1283  QString("Switch port out of range (%1 > %2)")
1284  .arg(ordinal + 1).arg(m_numPorts));
1285  delete child;
1286  }
1287  }
1288 
1289  return true;
1290 }
1291 
1292 bool DiSEqCDevSwitch::Store(void) const
1293 {
1294  QString type = SwitchTypeToString(m_type);
1295  MSqlQuery query(MSqlQuery::InitCon());
1296 
1297  // insert new or update old
1298  if (IsRealDeviceID())
1299  {
1300  query.prepare(
1301  "UPDATE diseqc_tree "
1302  "SET parentid = :PARENT, "
1303  " ordinal = :ORDINAL, "
1304  " type = 'switch', "
1305  " description = :DESC, "
1306  " subtype = :TYPE, "
1307  " address = :ADDRESS, "
1308  " switch_ports = :PORTS, "
1309  " cmd_repeat = :REPEAT "
1310  "WHERE diseqcid = :DEVID");
1311  query.bindValue(":DEVID", GetDeviceID());
1312  }
1313  else
1314  {
1315  query.prepare(
1316  "INSERT INTO diseqc_tree"
1317  " ( parentid, ordinal, type, "
1318  " description, address, subtype, "
1319  " switch_ports, cmd_repeat ) "
1320  "VALUES "
1321  " (:PARENT, :ORDINAL, 'switch', "
1322  " :DESC, :ADDRESS, :TYPE, "
1323  " :PORTS, :REPEAT )");
1324  }
1325 
1326  if (m_parent)
1327  query.bindValue(":PARENT", m_parent->GetDeviceID());
1328 
1329  query.bindValue(":ORDINAL", m_ordinal);
1330  query.bindValue(":DESC", GetDescription());
1331  query.bindValue(":ADDRESS", m_address);
1332  query.bindValue(":TYPE", type);
1333  query.bindValue(":PORTS", m_numPorts);
1334  query.bindValue(":REPEAT", m_repeat);
1335 
1336  if (!query.exec())
1337  {
1338  MythDB::DBError("DiSEqCDevSwitch::Store", query);
1339  return false;
1340  }
1341 
1342  // figure out devid if we did an insert
1343  if (!IsRealDeviceID())
1344  SetDeviceID(query.lastInsertId().toUInt());
1345 
1346  // chain to children
1347  bool success = true;
1348  for (size_t ch = 0; ch < m_children.size(); ch++)
1349  {
1350  if (m_children[ch])
1351  success &= m_children[ch]->Store();
1352  }
1353 
1354  return success;
1355 }
1356 
1358 {
1359  uint old_num = m_children.size();
1360 
1361  if (old_num > num_ports)
1362  {
1363  for (uint ch = num_ports; ch < old_num; ch++)
1364  {
1365  if (m_children[ch])
1366  delete m_children[ch];
1367  }
1368  m_children.resize(num_ports);
1369  }
1370  else if (old_num < num_ports)
1371  {
1372  m_children.resize(num_ports);
1373  for (uint ch = old_num; ch < num_ports; ch++)
1374  m_children[ch] = nullptr;
1375  }
1376 
1377  m_numPorts = num_ports;
1378 }
1379 
1381  const DTVMultiplex &tuning,
1382  uint pos)
1383 {
1384  (void) settings;
1385  (void) tuning;
1386  (void) pos;
1387 
1388 #if defined(USING_DVB) && defined(FE_DISHNETWORK_SEND_LEGACY_CMD)
1389  static const unsigned char kSw21Cmds[] = { 0x34, 0x65, };
1390  static const unsigned char kSw42Cmds[] = { 0x46, 0x17, };
1391  static const unsigned char kSw64VCmds[] = { 0x39, 0x4b, 0x0d, };
1392  static const unsigned char kSw64HCmds[] = { 0x1a, 0x5c, 0x2e, };
1393 
1394  const unsigned char *cmds = nullptr;
1395  unsigned char horizcmd = 0x00;
1396  uint num_ports = 0;
1397 
1398  // determine polarity from lnb
1399  bool horizontal = false;
1400  DiSEqCDevLNB *lnb = m_tree.FindLNB(settings);
1401  if (lnb)
1402  horizontal = lnb->IsHorizontal(tuning);
1403 
1404  // get command table for this switch
1405  switch (m_type)
1406  {
1407  case kTypeLegacySW21:
1408  cmds = kSw21Cmds;
1409  num_ports = 2;
1410  if (horizontal)
1411  horizcmd = 0x80;
1412  break;
1413  case kTypeLegacySW42:
1414  cmds = kSw42Cmds;
1415  num_ports = 2;
1416  break;
1417  case kTypeLegacySW64:
1418  if (horizontal)
1419  cmds = kSw64HCmds;
1420  else
1421  cmds = kSw64VCmds;
1422  num_ports = 3;
1423  break;
1424  default:
1425  return false;
1426  }
1427  if (num_ports)
1428  pos %= num_ports;
1429 
1430  LOG(VB_CHANNEL, LOG_INFO, LOC +
1431  QString("Changing to Legacy switch port %1/%2")
1432  .arg(pos + 1).arg(num_ports));
1433 
1434  // send command
1435  if (ioctl(m_tree.GetFD(), FE_DISHNETWORK_SEND_LEGACY_CMD,
1436  cmds[pos] | horizcmd) == -1)
1437  {
1438  LOG(VB_GENERAL, LOG_ERR, LOC +
1439  "FE_DISHNETWORK_SEND_LEGACY_CMD failed" + ENO);
1440 
1441  return false;
1442  }
1443 
1444  return true;
1445 
1446 #else // !FE_DISHNETWORK_SEND_LEGACY_CMD
1447 
1448  LOG(VB_GENERAL, LOG_ERR, LOC + "You must compile with a newer "
1449  "version of the linux headers for DishNet Legacy switch support.");
1450  return false;
1451 
1452 #endif // !FE_DISHNETWORK_SEND_LEGACY_CMD
1453 }
1454 
1455 #ifdef USING_DVB
1456 static bool set_tone(int fd, fe_sec_tone_mode tone)
1457 {
1458  (void) fd;
1459  (void) tone;
1460 
1461  bool success = false;
1462 
1463  for (uint retry = 0; !success && (retry < TIMEOUT_RETRIES); retry++)
1464  {
1465  if (ioctl(fd, FE_SET_TONE, tone) == 0)
1466  success = true;
1467  else
1468  usleep(TIMEOUT_WAIT);
1469  }
1470 
1471  if (!success)
1472  {
1473  LOG(VB_GENERAL, LOG_ERR, LOC + "set_tone failed" + ENO);
1474  }
1475 
1476  return success;
1477 }
1478 #endif // USING_DVB
1479 
1480 #ifdef USING_DVB
1481 static bool set_voltage(int fd, fe_sec_voltage volt)
1482 {
1483  (void) fd;
1484  (void) volt;
1485 
1486  bool success = false;
1487 
1488  for (uint retry = 0; !success && (retry < TIMEOUT_RETRIES); retry++)
1489  {
1490  if (0 == ioctl(fd, FE_SET_VOLTAGE, volt))
1491  success = true;
1492  else
1493  usleep(TIMEOUT_WAIT);
1494  }
1495 
1496  if (!success)
1497  {
1498  LOG(VB_GENERAL, LOG_ERR, LOC + "FE_SET_VOLTAGE failed" + ENO);
1499  }
1500 
1501  return success;
1502 }
1503 #endif // USING_DVB
1504 
1505 #ifdef USING_DVB
1506 static bool mini_diseqc(int fd, fe_sec_mini_cmd cmd)
1507 {
1508  (void) fd;
1509  (void) cmd;
1510 
1511  bool success = false;
1512 
1513  for (uint retry = 0; !success && (retry < TIMEOUT_RETRIES); retry++)
1514  {
1515  if (ioctl(fd, FE_DISEQC_SEND_BURST, cmd) == 0)
1516  success = true;
1517  else
1518  usleep(TIMEOUT_WAIT);
1519  }
1520 
1521  if (!success)
1522  {
1523  LOG(VB_GENERAL, LOG_ERR, LOC +
1524  "mini_diseqc FE_DISEQC_SEND_BURST failed" + ENO);
1525  }
1526 
1527  return success;
1528 }
1529 #endif // USING_DVB
1530 
1532  const DTVMultiplex &/*tuning*/,
1533  uint pos)
1534 {
1535  LOG(VB_CHANNEL, LOG_INFO, LOC + "Changing to Tone switch port " +
1536  QString("%1/2").arg(pos + 1));
1537 
1538 #ifdef USING_DVB
1539  if (set_tone(m_tree.GetFD(), (0 == pos) ? SEC_TONE_OFF : SEC_TONE_ON))
1540  return true;
1541 #endif // USING_DVB
1542 
1543  LOG(VB_GENERAL, LOG_ERR, LOC + "Setting Tone Switch failed." + ENO);
1544  return false;
1545 }
1546 
1548  const DTVMultiplex &tuning, uint pos)
1549 {
1550  (void) settings;
1551  (void) tuning;
1552 
1553  LOG(VB_CHANNEL, LOG_INFO, LOC + "Changing to Voltage Switch port " +
1554  QString("%1/2").arg(pos + 1));
1555 
1556 #ifdef USING_DVB
1557  if (set_voltage(m_tree.GetFD(),
1558  (0 == pos) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18))
1559  {
1560  return true;
1561  }
1562 #endif // USING_DVB
1563 
1564  LOG(VB_GENERAL, LOG_ERR, LOC + "Setting Voltage Switch failed." + ENO);
1565 
1566  return false;
1567 }
1568 
1570  const DTVMultiplex &tuning, uint pos)
1571 {
1572  (void) settings;
1573  (void) tuning;
1574 
1575  LOG(VB_CHANNEL, LOG_INFO, LOC + "Changing to MiniDiSEqC Switch port " +
1576  QString("%1/2").arg(pos + 1));
1577 
1578 #ifdef USING_DVB
1579  if (mini_diseqc(m_tree.GetFD(), (0 == pos) ? SEC_MINI_A : SEC_MINI_B))
1580  return true;
1581 #endif // USING_DVB
1582 
1583  LOG(VB_GENERAL, LOG_ERR, LOC + "Setting Mini DiSEqC Switch failed." + ENO);
1584 
1585  return false;
1586 }
1587 
1589  const DTVMultiplex &tuning) const
1590 {
1591  int pos = GetPosition(settings);
1592  if (pos < 0)
1593  return false;
1594 
1595  // committed switch should change for band and polarity as well
1597  {
1598  // retrieve LNB info
1599  bool high_band = false;
1600  bool horizontal = false;
1601  DiSEqCDevLNB *lnb = m_tree.FindLNB(settings);
1602  if (lnb)
1603  {
1604  high_band = lnb->IsHighBand(tuning);
1605  horizontal = lnb->IsHorizontal(tuning);
1606  }
1607 
1608  if(high_band != m_lastHighBand ||
1609  horizontal != m_lastHorizontal)
1610  return true;
1611  }
1612  else if (kTypeLegacySW42 == m_type ||
1614  {
1615  // retrieve LNB info
1616  bool horizontal = false;
1617  DiSEqCDevLNB *lnb = m_tree.FindLNB(settings);
1618  if (lnb)
1619  horizontal = lnb->IsHorizontal(tuning);
1620 
1621  if (horizontal != m_lastHorizontal)
1622  return true;
1623  }
1624  else if (kTypeVoltage == m_type ||
1625  kTypeTone == m_type)
1626  return true;
1627 
1628  return m_lastPos != (uint)pos;
1629 }
1630 
1632  const DTVMultiplex &tuning,
1633  uint pos)
1634 {
1635  // retrieve LNB info
1636  bool high_band = false;
1637  bool horizontal = false;
1638  DiSEqCDevLNB *lnb = m_tree.FindLNB(settings);
1639  if (lnb)
1640  {
1641  high_band = lnb->IsHighBand(tuning);
1642  horizontal = lnb->IsHorizontal(tuning);
1643  }
1644 
1645  // check number of ports
1646  if (((kTypeDiSEqCCommitted == m_type) && (m_numPorts > 4)) ||
1647  ((kTypeDiSEqCUncommitted == m_type) && (m_numPorts > 16)))
1648  {
1649  LOG(VB_GENERAL, LOG_ERR, LOC +
1650  QString("Invalid number of ports for DiSEqC 1.x Switch (%1)")
1651  .arg(m_numPorts));
1652  return false;
1653  }
1654 
1655  // build command
1656  uint cmd = DISEQC_CMD_WRITE_N1;
1657  unsigned char data = pos;
1659  {
1660  cmd = DISEQC_CMD_WRITE_N0;
1661  data = ((pos << 2) | (horizontal ? 2 : 0) | (high_band ? 1 : 0));
1662  }
1663  data |= 0xf0;
1664 
1665  LOG(VB_CHANNEL, LOG_INFO, LOC + "Changing to DiSEqC switch port " +
1666  QString("%1/%2").arg(pos + 1).arg(m_numPorts));
1667 
1668  bool ret = m_tree.SendCommand(m_address, cmd, m_repeat, 1, &data);
1669  if(ret)
1670  {
1671  m_lastHighBand = high_band;
1672  m_lastHorizontal = horizontal;
1673  }
1674  return ret;
1675 }
1676 
1678 {
1679  int pos = (int) settings.GetValue(GetDeviceID());
1680 
1681  if (pos >= (int)m_numPorts)
1682  {
1683  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Port %1 ").arg(pos + 1) +
1684  QString("is not in range [0..%1)").arg(m_numPorts));
1685 
1686  return -1;
1687  }
1688 
1689  if ((pos >= 0) && !m_children[pos])
1690  {
1691  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Port %1 ").arg(pos + 1) +
1692  "has no connected devices configured.");
1693 
1694  return -1;
1695  }
1696 
1697  return pos;
1698 }
1699 
1701 
1702 static double GetCurTimeFloating(void)
1703 {
1704  struct timeval curtime {};
1705  gettimeofday(&curtime, nullptr);
1706  return (double)curtime.tv_sec + (((double)curtime.tv_usec) / 1000000);
1707 }
1708 
1714 {
1715  { "diseqc_1_2", kTypeDiSEqC_1_2 },
1716  { "diseqc_1_3", kTypeDiSEqC_1_3 },
1717  { nullptr, kTypeDiSEqC_1_3 }
1718 };
1719 
1721 {
1722  delete m_child;
1723 }
1724 
1726  const DTVMultiplex &tuning)
1727 {
1728  bool success = true;
1729 
1730  double position = settings.GetValue(GetDeviceID());
1731  if (m_reset || (position != m_lastPosition))
1732  {
1733  switch (m_type)
1734  {
1735  case kTypeDiSEqC_1_2:
1736  success = ExecuteRotor(settings, tuning, position);
1737  break;
1738  case kTypeDiSEqC_1_3:
1739  success = ExecuteUSALS(settings, tuning, position);
1740  break;
1741  default:
1742  success = false;
1743  LOG(VB_GENERAL, LOG_ERR, LOC + "Unknown rotor type " +
1744  QString("(%1)").arg((uint) m_type));
1745  break;
1746  }
1747 
1748  m_lastPosition = position;
1749  m_reset = false;
1750  if (success)
1751  // prevent tuning paramaters overiding rotor parameters
1752  usleep(DISEQC_LONG_WAIT);
1753  }
1754 
1755  // chain to child
1756  if (success && m_child)
1757  success = m_child->Execute(settings, tuning);
1758 
1759  return success;
1760 }
1761 
1763 {
1764  m_reset = true;
1765  if (m_child)
1766  m_child->Reset();
1767 }
1768 
1770  const DTVMultiplex &tuning) const
1771 {
1772  double position = settings.GetValue(GetDeviceID());
1773 
1774  if (m_reset || (position != m_lastPosition))
1775  return true;
1776 
1777  if (m_child)
1778  return m_child->IsCommandNeeded(settings, tuning);
1779 
1780  return false;
1781 }
1782 
1784 {
1785  return m_child;
1786 }
1787 
1789 {
1790  if (ordinal)
1791  return false;
1792 
1793  DiSEqCDevDevice *old_child = m_child;
1794  m_child = nullptr;
1795  delete old_child;
1796 
1797  m_child = device;
1798  if (m_child)
1799  {
1800  m_child->SetOrdinal(ordinal);
1801  m_child->SetParent(this);
1802  }
1803 
1804  return true;
1805 }
1806 
1807 bool DiSEqCDevRotor::IsMoving(const DiSEqCDevSettings &settings) const
1808 {
1809  double position = settings.GetValue(GetDeviceID());
1810  double completed = GetProgress();
1811  bool moving = (completed < 1.0) || (position != m_lastPosition);
1812 
1813  return (m_lastPosKnown && moving);
1814 }
1815 
1817  const DTVMultiplex &tuning) const
1818 {
1819  // override voltage if the last position is known and the rotor is moving
1820  if (IsMoving(settings))
1821  {
1822  LOG(VB_CHANNEL, LOG_INFO, LOC +
1823  "Overriding voltage to 18V for faster rotor movement");
1824  }
1825  else if (m_child)
1826  {
1827  return m_child->GetVoltage(settings, tuning);
1828  }
1829 
1830  return SEC_VOLTAGE_18;
1831 }
1832 
1834 {
1835  // populate switch parameters from db
1836  MSqlQuery query(MSqlQuery::InitCon());
1837  query.prepare(
1838  "SELECT subtype, rotor_positions, "
1839  " rotor_hi_speed, rotor_lo_speed, "
1840  " cmd_repeat "
1841  "FROM diseqc_tree "
1842  "WHERE diseqcid = :DEVID");
1843  query.bindValue(":DEVID", GetDeviceID());
1844 
1845  if (!query.exec() || !query.isActive())
1846  {
1847  MythDB::DBError("DiSEqCDevRotor::Load 1", query);
1848  return false;
1849  }
1850  if (query.next())
1851  {
1852  m_type = RotorTypeFromString(query.value(0).toString());
1853  m_speedHi = query.value(2).toDouble();
1854  m_speedLo = query.value(3).toDouble();
1855  m_repeat = query.value(4).toUInt();
1856 
1857  // form of "angle1=index1:angle2=index2:..."
1858  QString positions = query.value(1).toString();
1859  QStringList pos = positions.split(":", QString::SkipEmptyParts);
1860  QStringList::const_iterator it = pos.begin();
1861  for (; it != pos.end(); ++it)
1862  {
1863  const QStringList eq = (*it).split("=", QString::SkipEmptyParts);
1864  if (eq.size() == 2)
1865  m_posmap[eq[0].toFloat()] = eq[1].toUInt();
1866  }
1867  }
1868 
1869  // load children from db
1870  if (m_child)
1871  {
1872  delete m_child;
1873  m_child = nullptr;
1874  }
1875 
1876  query.prepare(
1877  "SELECT diseqcid "
1878  "FROM diseqc_tree "
1879  "WHERE parentid = :DEVID");
1880  query.bindValue(":DEVID", GetDeviceID());
1881 
1882  if (!query.exec() || !query.isActive())
1883  {
1884  MythDB::DBError("DiSEqCDevRotor::Load 2", query);
1885  return false;
1886  }
1887  if (query.next())
1888  {
1889  uint child_dev_id = query.value(0).toUInt();
1890  SetChild(0, CreateById(m_tree, child_dev_id));
1891  }
1892 
1893  return true;
1894 }
1895 
1896 bool DiSEqCDevRotor::Store(void) const
1897 {
1898  QString posmap = "";
1899  QString type = RotorTypeToString(m_type);
1900 
1901  if (!m_posmap.empty())
1902  {
1903  QStringList pos;
1904 
1905  dbl_to_uint_t::const_iterator it = m_posmap.begin();
1906  for (; it != m_posmap.end(); ++it)
1907  pos.push_back(QString("%1=%2").arg(it.key()).arg(*it));
1908 
1909  posmap = pos.join(":");
1910  }
1911 
1912  MSqlQuery query(MSqlQuery::InitCon());
1913 
1914  // insert new or update old
1915  if (IsRealDeviceID())
1916  {
1917  query.prepare(
1918  "UPDATE diseqc_tree "
1919  "SET parentid = :PARENT, "
1920  " ordinal = :ORDINAL, "
1921  " type = 'rotor', "
1922  " description = :DESC, "
1923  " subtype = :TYPE, "
1924  " rotor_hi_speed = :HISPEED, "
1925  " rotor_lo_speed = :LOSPEED, "
1926  " rotor_positions = :POSMAP, "
1927  " cmd_repeat = :REPEAT "
1928  "WHERE diseqcid = :DEVID");
1929  query.bindValue(":DEVID", GetDeviceID());
1930  }
1931  else
1932  {
1933  query.prepare(
1934  "INSERT INTO diseqc_tree "
1935  " ( parentid, ordinal, type, "
1936  " description, subtype, rotor_hi_speed, "
1937  " rotor_lo_speed, rotor_positions, cmd_repeat ) "
1938  "VALUES "
1939  " (:PARENT, :ORDINAL, 'rotor', "
1940  " :DESC, :TYPE, :HISPEED, "
1941  " :LOSPEED, :POSMAP, :REPEAT )");
1942  }
1943 
1944  if (m_parent)
1945  query.bindValue(":PARENT", m_parent->GetDeviceID());
1946 
1947  query.bindValue(":ORDINAL", m_ordinal);
1948  query.bindValue(":DESC", GetDescription());
1949  query.bindValue(":TYPE", type);
1950  query.bindValue(":HISPEED", m_speedHi);
1951  query.bindValue(":LOSPEED", m_speedLo);
1952  query.bindValue(":POSMAP", posmap);
1953  query.bindValue(":REPEAT", m_repeat);
1954 
1955  if (!query.exec())
1956  {
1957  MythDB::DBError("DiSEqCDevRotor::Store", query);
1958  return false;
1959  }
1960 
1961  // figure out devid if we did an insert
1962  if (!IsRealDeviceID())
1963  SetDeviceID(query.lastInsertId().toUInt());
1964 
1965  // chain to child
1966  if (m_child)
1967  return m_child->Store();
1968 
1969  return true;
1970 }
1971 
1978 {
1979  if (m_moveTime == 0.0)
1980  return 1.0;
1981 
1982  // calculate duration of move
1983  double speed = ((m_tree.GetVoltage() == SEC_VOLTAGE_18) ?
1984  m_speedHi : m_speedLo);
1985  double change = abs(m_desiredAzimuth - m_lastAzimuth);
1986  double duration = change / speed;
1987 
1988  // determine completion percentage
1989  double time_since_move = GetCurTimeFloating() - m_moveTime;
1990  double completed = time_since_move / duration;
1991  if(completed > 1.0)
1992  {
1993  RotationComplete();
1994  completed = 1.0;
1995  }
1996 
1997  return completed;
1998 }
1999 
2008 {
2009  return m_lastPosKnown;
2010 }
2011 
2013 {
2014  uint_to_dbl_t inv_posmap;
2015  dbl_to_uint_t::const_iterator it;
2016  for (it = m_posmap.begin(); it != m_posmap.end(); ++it)
2017  inv_posmap[*it] = it.key();
2018 
2019  return inv_posmap;
2020 }
2021 
2023 {
2024  m_posmap.clear();
2025 
2026  uint_to_dbl_t::const_iterator it;
2027  for (it = inv_posmap.begin(); it != inv_posmap.end(); ++it)
2028  m_posmap[*it] = it.key();
2029 }
2030 
2032  const DTVMultiplex& /*tuning*/,
2033  double angle)
2034 {
2035  // determine stored position from position map
2036  dbl_to_uint_t::const_iterator it = m_posmap.lowerBound(angle - EPS);
2037  unsigned char index = (uint) angle;
2038  if (it != m_posmap.end())
2039  {
2040  index = *it;
2042  }
2043 
2044  LOG(VB_CHANNEL, LOG_INFO, LOC + "Rotor - " +
2045  QString("Goto Stored Position %1").arg(index));
2046 
2048  m_repeat, 1, &index);
2049 }
2050 
2052  const DTVMultiplex& /*tuning*/,
2053  double angle)
2054 {
2055  double azimuth = CalculateAzimuth(angle);
2056  StartRotorPositionTracking(azimuth);
2057 
2058  LOG(VB_CHANNEL, LOG_INFO, LOC + "USALS Rotor - " +
2059  QString("Goto %1 (Azimuth %2)").arg(angle).arg(azimuth));
2060 
2061  uint az16 = (uint) (abs(azimuth) * 16.0);
2062  unsigned char cmd[2];
2063  cmd[0] = ((azimuth > 0.0) ? 0xE0 : 0xD0) | ((az16 >> 8) &0x0f);
2064  cmd[1] = (az16 &0xff);
2065 
2067  m_repeat, 2, cmd);
2068 }
2069 
2071 {
2072  // Azimuth Calculation references:
2073  // http://engr.nmsu.edu/~etti/3_2/3_2e.html
2074  // http://www.angelfire.com/trek/ismail/theory.html
2075 
2076  // Earth Station Latitude and Longitude in radians
2077  double P = gCoreContext->GetSetting("Latitude", "").toDouble() * TO_RADS;
2078  double Ue = gCoreContext->GetSetting("Longitude", "").toDouble() * TO_RADS;
2079 
2080  // Satellite Longitude in radians
2081  double Us = angle * TO_RADS;
2082 
2083  return TO_DEC * atan( tan(Us - Ue) / sin(P) );
2084 }
2085 
2087 {
2088  if (m_moveTime == 0.0)
2089  return m_lastAzimuth;
2090 
2091  double change = m_desiredAzimuth - m_lastAzimuth;
2092  return m_lastAzimuth + (change * GetProgress());
2093 }
2094 
2096 {
2097  // save time and angle of this command
2098  m_desiredAzimuth = azimuth;
2099 
2100  // set last to approximate current position (or worst case if unknown)
2101  if (m_lastPosKnown || m_moveTime > 0.0)
2103  else
2104  m_lastAzimuth = azimuth > 0.0 ? -75.0 : 75.0;
2105 
2107 }
2108 
2110 {
2111  m_moveTime = 0.0;
2112  m_lastPosKnown = true;
2114 }
2115 
2117 
2123 {
2124  { "A", kTypeScrPosA },
2125  { "B", kTypeScrPosB },
2126  { QString(), kTypeScrPosA },
2127 };
2128 
2130 {
2131  delete m_child;
2132 }
2133 
2135 {
2136  if (m_child)
2137  m_child->Reset();
2138 }
2139 
2140 bool DiSEqCDevSCR::Execute(const DiSEqCDevSettings &settings, const DTVMultiplex &tuning)
2141 {
2142  // retrieve LNB info
2143  DiSEqCDevLNB *lnb = m_tree.FindLNB(settings);
2144  if (!lnb)
2145  {
2146  LOG(VB_GENERAL, LOG_ERR, LOC + "SCR: No LNB for this configuration!");
2147  return false;
2148  }
2149 
2150  bool high_band = lnb->IsHighBand(tuning);
2151  bool horizontal = lnb->IsHorizontal(tuning);
2152  uint32_t frequency = lnb->GetIntermediateFrequency(settings, tuning);
2153  uint t = (frequency / 1000 + m_scrFrequency + 2) / 4 - 350;
2154 
2155  // retrieve position settings (value should be 0 or 1)
2156  auto scr_position = (dvbdev_pos_t)int(settings.GetValue(GetDeviceID()));
2157 
2158  // check parameters
2159  if (m_scrUserband > 8)
2160  {
2161  LOG(VB_GENERAL, LOG_INFO, QString("SCR: Userband ID=%1 is out of standard range!")
2162  .arg(m_scrUserband));
2163  }
2164 
2165  if (t >= 1024)
2166  {
2167  LOG(VB_GENERAL, LOG_ERR, LOC + "SCR: T out of range!");
2168  return false;
2169  }
2170 
2171  LOG(VB_GENERAL, LOG_INFO, QString("SCR: Tuning to %1kHz, %2, %3 using UB=%4, FREQ=%5MHz, POS=%6%7")
2172  .arg(tuning.m_frequency)
2173  .arg(high_band ? "HiBand" : "LoBand")
2174  .arg(horizontal ? "H" : "V")
2175  .arg(m_scrUserband)
2176  .arg(m_scrFrequency)
2177  .arg((scr_position) ? "B" : "A")
2178  .arg((m_scrPin >= 0 && m_scrPin <= 255) ?
2179  QString(", PIN=%1").arg(m_scrPin) : QString("")));
2180 
2181  // build command
2182  unsigned char data[3];
2183  data[0] = t >> 8 | m_scrUserband << 5;
2184  data[1] = t & 0x00FF;
2185 
2186  if (high_band)
2187  data[0] |= (1 << 2);
2188 
2189  if (horizontal)
2190  data[0] |= (1 << 3);
2191 
2192  if (scr_position)
2193  data[0] |= (1 << 4);
2194 
2195  // send command
2196  if (m_scrPin >= 0 && m_scrPin <= 255)
2197  {
2198  data[2] = m_scrPin;
2199  return SendCommand(DISEQC_CMD_ODU_MDU, m_repeat, 3, data);
2200  }
2201  return SendCommand(DISEQC_CMD_ODU, m_repeat, 2, data);
2202 }
2203 
2204 bool DiSEqCDevSCR::PowerOff(void) const
2205 {
2206  // check parameters
2207  if (m_scrUserband > 8)
2208  {
2209  LOG(VB_GENERAL, LOG_INFO, QString("SCR: Userband ID=%1 is out of standard range!")
2210  .arg(m_scrUserband));
2211  }
2212 
2213  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SCR: Power off UB=%1%7")
2214  .arg(m_scrUserband)
2215  .arg((m_scrPin >= 0 && m_scrPin <= 255)
2216  ? QString(", PIN=%1").arg(m_scrPin)
2217  : QString("")));
2218 
2219  // build command
2220  unsigned char data[3];
2221  data[0] = (uint8_t) (m_scrUserband << 5);
2222  data[1] = 0x00;
2223 
2224  // send command
2225  if (m_scrPin >= 0 && m_scrPin <= 255)
2226  {
2227  data[2] = m_scrPin;
2228  return SendCommand(DISEQC_CMD_ODU_MDU, m_repeat, 3, data);
2229  }
2230  return SendCommand(DISEQC_CMD_ODU, m_repeat, 2, data);
2231 }
2232 
2233 bool DiSEqCDevSCR::SendCommand(uint cmd, uint repeats, uint data_len,
2234  unsigned char *data) const
2235 {
2236  (void) repeats;
2237 
2238  // power on bus
2239  if (!m_tree.SetVoltage(SEC_VOLTAGE_18))
2240  return false;
2241  usleep(DISEQC_LONG_WAIT);
2242 
2243  // send command
2244  bool ret = m_tree.SendCommand(DISEQC_ADR_SW_ALL, cmd, repeats, data_len, data);
2245 
2246  // power off bus
2247  if (!m_tree.SetVoltage(SEC_VOLTAGE_13))
2248  return false;
2249 
2250  return ret;
2251 }
2252 
2254  const DTVMultiplex &/*tuning*/) const
2255 {
2256  return SEC_VOLTAGE_13;
2257 }
2258 
2259 uint32_t DiSEqCDevSCR::GetIntermediateFrequency(const uint32_t frequency) const
2260 {
2261  uint t = (frequency / 1000 + m_scrFrequency + 2) / 4 - 350;
2262  return ((t + 350) * 4) * 1000 - frequency;
2263 }
2264 
2266 {
2267  // populate scr parameters from db
2268  MSqlQuery query(MSqlQuery::InitCon());
2269  query.prepare(
2270  "SELECT scr_userband, scr_frequency, "
2271  " scr_pin, cmd_repeat "
2272  "FROM diseqc_tree "
2273  "WHERE diseqcid = :DEVID");
2274  query.bindValue(":DEVID", GetDeviceID());
2275 
2276  if (!query.exec() || !query.isActive())
2277  {
2278  MythDB::DBError("DiSEqCDevSCR::Load 1", query);
2279  return false;
2280  }
2281  if (query.next())
2282  {
2283  m_scrUserband = query.value(0).toUInt();
2284  m_scrFrequency = query.value(1).toUInt();
2285  m_scrPin = query.value(2).toInt();
2286  m_repeat = query.value(3).toUInt();
2287  }
2288 
2289  // load children from db
2290  if (m_child)
2291  {
2292  delete m_child;
2293  m_child = nullptr;
2294  }
2295 
2296  query.prepare(
2297  "SELECT diseqcid "
2298  "FROM diseqc_tree "
2299  "WHERE parentid = :DEVID");
2300  query.bindValue(":DEVID", GetDeviceID());
2301 
2302  if (!query.exec() || !query.isActive())
2303  {
2304  MythDB::DBError("DiSEqCDevSCR::Load 2", query);
2305  return false;
2306  }
2307  if (query.next())
2308  {
2309  uint child_dev_id = query.value(0).toUInt();
2310  SetChild(0, CreateById(m_tree, child_dev_id));
2311  }
2312 
2313  return true;
2314 }
2315 
2316 bool DiSEqCDevSCR::Store(void) const
2317 {
2318  MSqlQuery query(MSqlQuery::InitCon());
2319 
2320  // insert new or update old
2321  if (IsRealDeviceID())
2322  {
2323  query.prepare(
2324  "UPDATE diseqc_tree "
2325  "SET parentid = :PARENT, "
2326  " ordinal = :ORDINAL, "
2327  " type = 'scr', "
2328  " description = :DESC, "
2329  " scr_userband = :USERBAND, "
2330  " scr_frequency = :FREQUENCY, "
2331  " scr_pin = :PIN, "
2332  " cmd_repeat = :REPEAT "
2333  "WHERE diseqcid = :DEVID");
2334  query.bindValue(":DEVID", GetDeviceID());
2335  }
2336  else
2337  {
2338  query.prepare(
2339  "INSERT INTO diseqc_tree"
2340  " ( parentid, ordinal, type, "
2341  " description, scr_userband, scr_frequency, "
2342  " scr_pin, cmd_repeat) "
2343  "VALUES "
2344  " (:PARENT, :ORDINAL, 'scr', "
2345  " :DESC, :USERBAND, :FREQUENCY,"
2346  " :PIN, :REPEAT) ");
2347  }
2348 
2349  if (m_parent)
2350  query.bindValue(":PARENT", m_parent->GetDeviceID());
2351 
2352  query.bindValue(":ORDINAL", m_ordinal);
2353  query.bindValue(":DESC", GetDescription());
2354  query.bindValue(":USERBAND", m_scrUserband);
2355  query.bindValue(":FREQUENCY", m_scrFrequency);
2356  query.bindValue(":PIN", m_scrPin);
2357  query.bindValue(":REPEAT", m_repeat);
2358 
2359  // update dev_id
2360  if (!query.exec())
2361  {
2362  MythDB::DBError("DiSEqCDevSCR::Store", query);
2363  return false;
2364  }
2365 
2366  // figure out devid if we did an insert
2367  if (!IsRealDeviceID())
2368  SetDeviceID(query.lastInsertId().toUInt());
2369 
2370  // chain to child
2371  if (m_child)
2372  return m_child->Store();
2373 
2374  return true;
2375 }
2376 
2378 {
2379  if (ordinal)
2380  return false;
2381 
2382  DiSEqCDevDevice *old_child = m_child;
2383  m_child = nullptr;
2384  delete old_child;
2385 
2386  m_child = device;
2387  if (m_child)
2388  {
2389  m_child->SetOrdinal(ordinal);
2390  m_child->SetParent(this);
2391  }
2392 
2393  return true;
2394 }
2395 
2397 
2403 {
2404  { "fixed", kTypeFixed },
2405  { "voltage", kTypeVoltageControl },
2406  { "voltage_tone", kTypeVoltageAndToneControl },
2407  { "bandstacked", kTypeBandstacked },
2408  { QString(), kTypeVoltageAndToneControl },
2409 };
2410 
2411 bool DiSEqCDevLNB::Execute(const DiSEqCDevSettings& /*settings*/, const DTVMultiplex &tuning)
2412 {
2413  // set tone for bandselect
2415  m_tree.SetTone(IsHighBand(tuning));
2416 
2417  return true;
2418 }
2419 
2421  const DTVMultiplex &tuning) const
2422 {
2423  uint voltage = SEC_VOLTAGE_18;
2424 
2425  if ((kTypeVoltageControl == m_type) ||
2427  {
2428  voltage = (IsHorizontal(tuning) ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13);
2429  }
2430 
2431  return voltage;
2432 }
2433 
2435 {
2436  // populate lnb parameters from db
2437  MSqlQuery query(MSqlQuery::InitCon());
2438  query.prepare(
2439  "SELECT subtype, lnb_lof_switch, "
2440  " lnb_lof_hi, lnb_lof_lo, "
2441  " lnb_pol_inv, cmd_repeat "
2442  "FROM diseqc_tree "
2443  "WHERE diseqcid = :DEVID");
2444  query.bindValue(":DEVID", GetDeviceID());
2445 
2446  if (!query.exec() || !query.isActive())
2447  {
2448  MythDB::DBError("DiSEqCDevLNB::Load", query);
2449  return false;
2450  }
2451  if (query.next())
2452  {
2453  m_type = LNBTypeFromString(query.value(0).toString());
2454  m_lofSwitch = query.value(1).toInt();
2455  m_lofHi = query.value(2).toInt();
2456  m_lofLo = query.value(3).toInt();
2457  m_pol_inv = query.value(4).toBool();
2458  m_repeat = query.value(5).toUInt();
2459  }
2460 
2461  return true;
2462 }
2463 
2464 bool DiSEqCDevLNB::Store(void) const
2465 {
2466  QString type = LNBTypeToString(m_type);
2467  MSqlQuery query(MSqlQuery::InitCon());
2468 
2469  // insert new or update old
2470  if (IsRealDeviceID())
2471  {
2472  query.prepare(
2473  "UPDATE diseqc_tree "
2474  "SET parentid = :PARENT, "
2475  " ordinal = :ORDINAL, "
2476  " type = 'lnb', "
2477  " description = :DESC, "
2478  " subtype = :TYPE, "
2479  " lnb_lof_switch = :LOFSW, "
2480  " lnb_lof_lo = :LOFLO, "
2481  " lnb_lof_hi = :LOFHI, "
2482  " lnb_pol_inv = :POLINV, "
2483  " cmd_repeat = :REPEAT "
2484  "WHERE diseqcid = :DEVID");
2485  query.bindValue(":DEVID", GetDeviceID());
2486  }
2487  else
2488  {
2489  query.prepare(
2490  "INSERT INTO diseqc_tree"
2491  " ( parentid, ordinal, type, "
2492  " description, subtype, lnb_lof_switch, "
2493  " lnb_lof_lo, lnb_lof_hi, lnb_pol_inv, "
2494  " cmd_repeat ) "
2495  "VALUES "
2496  " (:PARENT, :ORDINAL, 'lnb', "
2497  " :DESC, :TYPE, :LOFSW, "
2498  " :LOFLO, :LOFHI, :POLINV, "
2499  " :REPEAT ) ");
2500  }
2501 
2502  if (m_parent)
2503  query.bindValue(":PARENT", m_parent->GetDeviceID());
2504 
2505  query.bindValue(":ORDINAL", m_ordinal);
2506  query.bindValue(":DESC", GetDescription());
2507  query.bindValue(":TYPE", type);
2508  query.bindValue(":LOFSW", m_lofSwitch);
2509  query.bindValue(":LOFLO", m_lofLo);
2510  query.bindValue(":LOFHI", m_lofHi);
2511  query.bindValue(":POLINV", m_pol_inv);
2512  query.bindValue(":REPEAT", m_repeat);
2513 
2514  // update dev_id
2515  if (!query.exec())
2516  {
2517  MythDB::DBError("DiSEqCDevLNB::Store", query);
2518  return false;
2519  }
2520 
2521  // figure out devid if we did an insert
2522  if (!IsRealDeviceID())
2523  SetDeviceID(query.lastInsertId().toUInt());
2524 
2525  return true;
2526 }
2527 
2534 bool DiSEqCDevLNB::IsHighBand(const DTVMultiplex &tuning) const
2535 {
2536  switch (m_type)
2537  {
2539  return (tuning.m_frequency > m_lofSwitch);
2540  case kTypeBandstacked:
2541  return IsHorizontal(tuning);
2542  default:
2543  return false;
2544  }
2545 
2546  return false;
2547 }
2548 
2554 bool DiSEqCDevLNB::IsHorizontal(const DTVMultiplex &tuning) const
2555 {
2556  QString pol = tuning.m_polarity.toString().toLower();
2557  return (pol == "h" || pol == "l") ^ IsPolarityInverted();
2558 }
2559 
2567  const DiSEqCDevSettings& /*settings*/, const DTVMultiplex &tuning) const
2568 {
2569  uint64_t abs_freq = tuning.m_frequency;
2570  uint lof = (IsHighBand(tuning)) ? m_lofHi : m_lofLo;
2571 
2572  return (lof > abs_freq) ? (lof - abs_freq) : (abs_freq - lof);
2573 }
#define DISEQC_CMD_ODU_MDU
Definition: diseqc.cpp:72
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:781
bool IsMoving(const DiSEqCDevSettings &) const
Definition: diseqc.cpp:1807
void Open(int fd_frontend, bool is_SCR)
Retrieve device tree.
Definition: diseqc.cpp:801
static QString TableToString(uint type, const TypeTable *table)
Definition: diseqc.cpp:92
QMutex m_treesLock
Definition: diseqc.h:70
cardid_to_diseqc_tree_t m_trees
Definition: diseqc.h:69
#define TO_RADS
Definition: diseqc.cpp:83
virtual bool Load(void)=0
Loads this device from the database.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:862
DiSEqCDevTree & m_tree
Definition: diseqc.h:201
DVB-S device settings class.
Definition: diseqc.h:35
bool m_reset
Definition: diseqc.h:362
#define DISEQC_ADR_ALL
Definition: diseqc.cpp:52
static double CalculateAzimuth(double angle)
Definition: diseqc.cpp:2070
dvbdev_switch_t m_type
Definition: diseqc.h:282
void SetNumPorts(uint num_ports)
Definition: diseqc.cpp:1357
bool IsCommandNeeded(const DiSEqCDevSettings &, const DTVMultiplex &) const override
Determines if this device or any child will be sending a command for the given configuration chain.
Definition: diseqc.cpp:1769
void Reset(void) override
Resets to the last known settings for this device.
Definition: diseqc.cpp:1150
#define DISEQC_FRM_REPEAT
Definition: diseqc.cpp:48
#define DISEQC_SHORT_WAIT
Definition: diseqc.cpp:37
static const TypeTable kLNBTypeTable[5]
Definition: diseqc.h:493
static DiSEqCDevTree * FindTree(uint cardid)
Retrieve device tree.
Definition: diseqc.cpp:240
uint GetDeviceID(void) const
Definition: diseqc.h:163
bool ShouldSwitch(const DiSEqCDevSettings &settings, const DTVMultiplex &tuning) const
Definition: diseqc.cpp:1588
void SetDescription(const QString &desc)
Definition: diseqc.h:157
bool ApplyVoltage(const DiSEqCDevSettings &settings, const DTVMultiplex &tuning)
Definition: diseqc.cpp:851
double m_speedLo
Definition: diseqc.h:355
#define DISEQC_CMD_GOTO_POS
Definition: diseqc.cpp:80
DiSEqCDevDevice * FindDevice(uint dev_id)
Returns a device by ID.
Definition: diseqc.cpp:627
virtual bool Execute(const DiSEqCDevSettings &, const DTVMultiplex &)=0
Applies DiSEqC settings to this node and any children.
uint GetVoltage(const DiSEqCDevSettings &, const DTVMultiplex &) const override
Retrives the desired voltage for this config.
Definition: diseqc.cpp:1816
bool SetChild(uint ordinal, DiSEqCDevDevice *device) override
Changes the nth child of this node.
Definition: diseqc.cpp:2377
#define DISEQC_CMD_RESET
Definition: diseqc.cpp:66
uint GetVoltage(const DiSEqCDevSettings &, const DTVMultiplex &) const override
Retrives the desired voltage for this config.
Definition: diseqc.cpp:2253
int m_scrPin
Definition: diseqc.h:431
#define DISEQC_POWER_ON_WAIT
Definition: diseqc.cpp:40
DiSEqCDevLNB * FindLNB(const DiSEqCDevSettings &settings)
Returns the LNB device object selected by the configuration chain.
Definition: diseqc.cpp:580
bool IsRealDeviceID(void) const
Definition: diseqc.h:164
bool Execute(const DiSEqCDevSettings &, const DTVMultiplex &) override
Applies DiSEqC settings to this node and any children.
Definition: diseqc.cpp:1093
DTVPolarity m_polarity
Definition: dtvmultiplex.h:104
bool Execute(const DiSEqCDevSettings &, const DTVMultiplex &) override
Applies DiSEqC settings to this node and any children.
Definition: diseqc.cpp:2411
uint m_inputId
current input id
Definition: diseqc.h:47
int GetPosition(const DiSEqCDevSettings &) const
Definition: diseqc.cpp:1677
bool IsInNeedOfConf(void) const
Definition: diseqc.cpp:843
bool Execute(const DiSEqCDevSettings &, const DTVMultiplex &) override
Applies DiSEqC settings to this node and any children.
Definition: diseqc.cpp:2140
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
DiSEqCDevDevice * m_child
Definition: diseqc.h:433
virtual DiSEqCDevDevice * GetChild(uint)
Retrieves the nth child of this node.
Definition: diseqc.h:181
#define DISEQC_FRM
Definition: diseqc.cpp:47
static QString SwitchTypeToString(dvbdev_switch_t type)
Definition: diseqc.h:261
bool IsHighBand(const DTVMultiplex &) const
Determine if the high frequency band is active (for switchable LNBs).
Definition: diseqc.cpp:2534
static double GetCurTimeFloating(void)
Definition: diseqc.cpp:1702
uint GetVoltage(void) const
Definition: diseqc.h:110
bool diseqc_bus_already_reset
Definition: diseqc.cpp:90
virtual bool Store(void) const =0
Stores this device to the database.
void SetValue(uint devid, double value)
Sets a value for this configuration chain by device id.
Definition: diseqc.cpp:222
double GetValue(uint devid) const
Retrieves a value from this configuration chain by device id.
Definition: diseqc.cpp:207
bool ExecuteDiseqc(const DiSEqCDevSettings &, const DTVMultiplex &, uint pos)
Definition: diseqc.cpp:1631
void Reset(void)
Reset state of nodes in tree, forcing updates on the next Execute command.
Definition: diseqc.cpp:543
DiSEqCDevDevice * m_root
Definition: diseqc.h:125
uint_to_dbl_t m_config
Definition: diseqc.h:46
static DiSEqCDevDevice * CreateById(DiSEqCDevTree &tree, uint devid)
Definition: diseqc.cpp:908
double m_moveTime
Definition: diseqc.h:365
dbl_to_uint_t m_posmap
Definition: diseqc.h:356
uint m_repeat
Definition: diseqc.h:204
static bool set_voltage(int fd, fe_sec_voltage volt)
Definition: diseqc.cpp:1481
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
bool SetChild(uint ordinal, DiSEqCDevDevice *device) override
Changes the nth child of this node.
Definition: diseqc.cpp:1788
bool m_lastPosKnown
Definition: diseqc.h:366
bool IsHorizontal(const DTVMultiplex &) const
Determine if horizontal polarity is active (for switchable LNBs).
Definition: diseqc.cpp:2554
DiSEqCDevSwitch(DiSEqCDevTree &tree, uint devid)
Definition: diseqc.cpp:1072
void SetPosMap(const uint_to_dbl_t &posmap)
Definition: diseqc.cpp:2022
DiSEqCDevDevice * GetChild(uint) override
Retrieves the nth child of this node.
Definition: diseqc.cpp:1189
uint GetChildCount(void) const override
Retrieves the proper number of children for this node.
Definition: diseqc.cpp:1184
static DiSEqCDevTrees s_trees
Definition: diseqc.h:57
static const TypeTable kSwitchTypeTable[9]
Definition: diseqc.h:290
uint32_t GetIntermediateFrequency(const uint32_t frequency) const
Definition: diseqc.cpp:2259
bool SetVoltage(uint voltage)
Definition: diseqc.cpp:809
bool Load(uint card_input_id)
Loads configuration chain from DB for specified card input id.
Definition: diseqc.cpp:130
bool Store(uint cardid, const QString &device="")
Stores the device tree to the database.
Definition: diseqc.cpp:426
bool ExecuteLegacy(const DiSEqCDevSettings &, const DTVMultiplex &, uint pos)
Definition: diseqc.cpp:1380
#define DISEQC_CMD_WRITE_N1
Definition: diseqc.cpp:69
#define EPS
Definition: diseqc.cpp:86
DiSEqCDevDevice * GetSelectedChild(const DiSEqCDevSettings &) const override
Retrieves the selected child for this configuration, if any.
Definition: diseqc.cpp:1783
double m_lastAzimuth
Definition: diseqc.h:367
bool SendCommand(uint cmd, uint repeats, uint data_len=0, unsigned char *data=nullptr) const
Definition: diseqc.cpp:2233
dvbdev_t GetDeviceType(void) const
Definition: diseqc.h:162
QVariant value(int i) const
Definition: mythdbcon.h:198
static const TypeTable kRotorTypeTable[3]
Definition: diseqc.h:370
static QString RotorTypeToString(dvbdev_rotor_t type)
Definition: diseqc.h:336
DiSEqCDevRotor * FindRotor(const DiSEqCDevSettings &settings, uint index=0)
Returns the nth rotor device object in the tree.
Definition: diseqc.cpp:557
bool IsPositionKnown(void) const
Returns true if there is reasonable confidence in the value returned by GetProgress().
Definition: diseqc.cpp:2007
Represents a node in a DVB-S device network.
Definition: diseqc.h:133
void SetParent(DiSEqCDevDevice *parent)
Definition: diseqc.h:155
virtual DiSEqCDevDevice * GetSelectedChild(const DiSEqCDevSettings &) const
Retrieves the selected child for this configuration, if any.
Definition: diseqc.h:179
#define DISEQC_CMD_WRITE_N0
Definition: diseqc.cpp:68
int m_fdFrontend
Definition: diseqc.h:124
DiSEqCDevTree * FindTree(uint cardid)
Retrieve device tree.
Definition: diseqc.cpp:268
bool ExecuteUSALS(const DiSEqCDevSettings &, const DTVMultiplex &, double angle)
Definition: diseqc.cpp:2051
#define DISEQC_CMD_ODU
Definition: diseqc.cpp:71
static const TypeTable kSCRPositionTable[3]
Definition: diseqc.h:435
int GetFD(void) const
Definition: diseqc.h:103
double GetProgress(void) const
Returns an indication of rotor progress.
Definition: diseqc.cpp:1977
dvbdev_rotor_t m_type
Definition: diseqc.h:353
QVariant lastInsertId()
Return the id of the last inserted row.
Definition: mythdbcon.cpp:886
uint m_lastHighBand
Definition: diseqc.h:286
static dvbdev_rotor_t RotorTypeFromString(const QString &type)
Definition: diseqc.h:338
#define LOC
Definition: diseqc.cpp:88
uint m_lofHi
Definition: diseqc.h:486
void SetRoot(DiSEqCDevDevice *root)
Changes the root node of the tree.
Definition: diseqc.cpp:639
virtual uint GetVoltage(const DiSEqCDevSettings &, const DTVMultiplex &) const =0
Retrives the desired voltage for this config.
void Reset(void) override
Resets to the last known settings for this device.
Definition: diseqc.cpp:1762
uint m_address
Definition: diseqc.h:283
QString GetSetting(const QString &key, const QString &defaultval="")
vector< uint > m_delete
Definition: diseqc.h:128
DiSEqCDevSCR * FindSCR(const DiSEqCDevSettings &settings)
Returns the SCR device object selected by the configuration chain.
Definition: diseqc.cpp:603
static bool set_tone(int fd, fe_sec_tone_mode tone)
Definition: diseqc.cpp:1456
static uint TableFromString(const QString &type, const TypeTable *table)
Definition: diseqc.cpp:104
static dvbdev_lnb_t LNBTypeFromString(const QString &type)
Definition: diseqc.h:480
bool Load(void) override
Loads this device from the database.
Definition: diseqc.cpp:1833
bool isActive(void) const
Definition: mythdbcon.h:204
Rotor class.
Definition: diseqc.h:293
bool Store(uint card_input_id) const
Stores configuration chain to DB for specified card input id.
Definition: diseqc.cpp:164
virtual bool IsCommandNeeded(const DiSEqCDevSettings &, const DTVMultiplex &) const
Determines if this device or any child will be sending a command for the given configuration chain.
Definition: diseqc.h:171
#define DISEQC_CMD_GOTO_X
Definition: diseqc.cpp:81
uint32_t GetIntermediateFrequency(const DiSEqCDevSettings &settings, const DTVMultiplex &tuning) const
Calculate proper intermediate frequency for the given settings and tuning parameters.
Definition: diseqc.cpp:2566
void RotationComplete(void) const
Definition: diseqc.cpp:2109
uint m_lastPos
Definition: diseqc.h:285
bool Store(void) const override
Stores this device to the database.
Definition: diseqc.cpp:2464
unsigned int uint
Definition: compat.h:140
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:534
bool ExecuteMiniDiSEqC(const DiSEqCDevSettings &, const DTVMultiplex &, uint pos)
Definition: diseqc.cpp:1569
virtual void Reset(void)
Resets to the last known settings for this device.
Definition: diseqc.h:141
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:99
uint CreateFakeDiSEqCID(void)
Definition: diseqc.h:115
bool Store(void) const override
Stores this device to the database.
Definition: diseqc.cpp:1292
bool ExecuteVoltage(const DiSEqCDevSettings &, const DTVMultiplex &, uint pos)
Definition: diseqc.cpp:1547
bool IsCommandNeeded(const DiSEqCDevSettings &, const DTVMultiplex &) const override
Determines if this device or any child will be sending a command for the given configuration chain.
Definition: diseqc.cpp:1163
uint_to_dbl_t GetPosMap(void) const
Definition: diseqc.cpp:2012
bool Load(const QString &device)
Loads the device tree from the database.
Definition: diseqc.cpp:315
uint m_scrFrequency
Definition: diseqc.h:430
uint m_ordinal
Definition: diseqc.h:203
static dvbdev_switch_t SwitchTypeFromString(const QString &type)
Definition: diseqc.h:263
bool m_pol_inv
If a signal is circularly polarized the polarity will flip on each reflection, so antenna systems wit...
Definition: diseqc.h:491
void InvalidateTrees(void)
Invalidate cached trees.
Definition: diseqc.cpp:286
bool Load(void) override
Loads this device from the database.
Definition: diseqc.cpp:2434
Static-scoped locked tree list class.
Definition: diseqc.h:60
uint m_scrUserband
Definition: diseqc.h:429
DiSEqCDevDevice * m_child
Definition: diseqc.h:357
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:806
static bool send_diseqc(int fd, const dvb_diseqc_master_cmd &cmd)
Definition: diseqc.cpp:649
bool PowerOff(void) const
Definition: diseqc.cpp:2204
uint m_numPorts
Definition: diseqc.h:284
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
double m_speedHi
Definition: diseqc.h:354
void StartRotorPositionTracking(double azimuth)
Definition: diseqc.cpp:2095
bool Execute(const DiSEqCDevSettings &settings, const DTVMultiplex &tuning)
Applies settings to the entire tree.
Definition: diseqc.cpp:516
double m_lastPosition
Definition: diseqc.h:360
virtual uint GetChildCount(void) const
Retrieves the proper number of children for this node.
Definition: diseqc.h:170
static const TypeTable kDvbdevLookup[5]
Definition: diseqc.h:212
QString toString() const
bool Load(void) override
Loads this device from the database.
Definition: diseqc.cpp:2265
DiSEqCDevDevice * m_parent
Definition: diseqc.h:202
Unicable / SCR Class.
Definition: diseqc.h:373
bool Store(void) const override
Stores this device to the database.
Definition: diseqc.cpp:1896
bool ResetDiseqc(bool hard_reset, bool is_SCR)
Resets the DiSEqC bus.
Definition: diseqc.cpp:752
static QString LNBTypeToString(dvbdev_lnb_t type)
Definition: diseqc.h:477
QString GetDescription(void) const
Definition: diseqc.h:168
bool SetChild(uint, DiSEqCDevDevice *) override
Changes the nth child of this node.
Definition: diseqc.cpp:1197
LNB Class.
Definition: diseqc.h:438
DiSEqCDevDevice * FindDevice(uint dev_id)
Returns a device by ID.
Definition: diseqc.cpp:884
static void InvalidateTrees(void)
Invalidate cached trees.
Definition: diseqc.cpp:248
void SetDeviceType(dvbdev_t type)
Definition: diseqc.h:154
virtual ~DiSEqCDevDevice()
Definition: diseqc.cpp:878
static bool Exists(int cardid)
Check if a Diseqc device tree exists.
Definition: diseqc.cpp:397
uint m_lofSwitch
Definition: diseqc.h:485
bool IsPolarityInverted(void) const
Definition: diseqc.h:468
#define DISEQC_POWER_OFF_WAIT
Definition: diseqc.cpp:39
void Reset(void) override
Resets to the last known settings for this device.
Definition: diseqc.cpp:2134
QMap< uint, double > uint_to_dbl_t
Definition: diseqc.h:30
dvbdev_lnb_t m_type
Definition: diseqc.h:484
uint GetVoltage(const DiSEqCDevSettings &, const DTVMultiplex &) const override
Retrives the desired voltage for this config.
Definition: diseqc.cpp:2420
double m_desiredAzimuth
Definition: diseqc.h:361
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:602
void SetOrdinal(uint ordinal)
Definition: diseqc.h:156
double GetApproxAzimuth(void) const
Definition: diseqc.cpp:2086
bool Store(void) const override
Stores this device to the database.
Definition: diseqc.cpp:2316
dvbdev_vec_t m_children
Definition: diseqc.h:288
static const uint kFirstFakeDiSEqCID
Definition: diseqc.h:130
static DiSEqCDevDevice * CreateByType(DiSEqCDevTree &tree, dvbdev_t type, uint dev_id=0)
Definition: diseqc.cpp:944
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
#define TO_DEC
Definition: diseqc.cpp:84
bool Load(void) override
Loads this device from the database.
Definition: diseqc.cpp:1227
#define DISEQC_LONG_WAIT
Definition: diseqc.cpp:38
bool ExecuteRotor(const DiSEqCDevSettings &, const DTVMultiplex &, double angle)
Definition: diseqc.cpp:2031
#define TIMEOUT_RETRIES
Definition: diseqc.cpp:43
DiSEqCDevDevice * GetSelectedChild(const DiSEqCDevSettings &) const override
Retrieves the selected child for this configuration, if any.
Definition: diseqc.cpp:1174
void SetDeviceID(uint devid) const
Definition: diseqc.h:196
#define TIMEOUT_WAIT
Definition: diseqc.cpp:44
#define DISEQC_ADR_POS_AZ
Definition: diseqc.cpp:62
QString GetHostName(void)
uint m_lastVoltage
Definition: diseqc.h:126
void AddDeferredDelete(uint dev_id)
Definition: diseqc.h:114
bool SendCommand(uint adr, uint cmd, uint repeats=0, uint data_len=0, unsigned char *data=nullptr)
Sends a DiSEqC command.
Definition: diseqc.cpp:682
DVB-S device tree class.
Definition: diseqc.h:73
uint m_lofLo
Definition: diseqc.h:487
Switch class, including tone, legacy and DiSEqC switches.
Definition: diseqc.h:215
bool ExecuteTone(const DiSEqCDevSettings &, const DTVMultiplex &, uint pos)
Definition: diseqc.cpp:1531
uint m_lastHorizontal
Definition: diseqc.h:287
uint GetVoltage(const DiSEqCDevSettings &, const DTVMultiplex &) const override
Retrives the desired voltage for this config.
Definition: diseqc.cpp:1215
static dvbdev_t DevTypeFromString(const QString &type)
Definition: diseqc.h:186
static bool mini_diseqc(int fd, fe_sec_mini_cmd cmd)
Definition: diseqc.cpp:1506
bool Execute(const DiSEqCDevSettings &, const DTVMultiplex &) override
Applies DiSEqC settings to this node and any children.
Definition: diseqc.cpp:1725
#define DISEQC_ADR_SW_ALL
Definition: diseqc.cpp:53
uint64_t m_frequency
Definition: dtvmultiplex.h:94
bool SetTone(bool on)
Definition: diseqc.cpp:487