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