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