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