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