00001
00002
00003
00004
00005
00006
00007
00008 #include <cstring>
00009 #include <cmath>
00010 #include <unistd.h>
00011
00012
00013 #include <sys/time.h>
00014
00015
00016 #include <qstring.h>
00017 #include <qdeepcopy.h>
00018
00019
00020 #include "mythcontext.h"
00021 #include "mythdbcon.h"
00022 #include "diseqc.h"
00023 #include "dtvmultiplex.h"
00024 #include "compat.h"
00025
00026 #ifdef USING_DVB
00027 # include "dvbtypes.h"
00028 #else
00029 # define SEC_VOLTAGE_13 0
00030 # define SEC_VOLTAGE_18 1
00031 # define SEC_VOLTAGE_OFF 2
00032 # define SEC_MINI_A 0
00033 # define SEC_MINI_B 1
00034 #endif
00035
00036
00037 #define DISEQC_SHORT_WAIT (15 * 1000)
00038 #define DISEQC_LONG_WAIT (100 * 1000)
00039 #define DISEQC_POWER_OFF_WAIT (1000 * 1000)
00040 #define DISEQC_POWER_ON_WAIT (500 * 1000)
00041
00042
00043 #define TIMEOUT_RETRIES 10
00044 #define TIMEOUT_WAIT (250 * 1000)
00045
00046
00047 #define DISEQC_FRM 0xe0
00048 #define DISEQC_FRM_REPEAT (1 << 0)
00049 #define DISEQC_FRM_REPLY_REQ (1 << 1)
00050
00051
00052 #define DISEQC_ADR_ALL 0x00
00053 #define DISEQC_ADR_SW_ALL 0x10
00054 #define DISEQC_ADR_LNB 0x11
00055 #define DISEQC_ADR_LNB_SW 0x12
00056 #define DISEQC_ADR_SW_BLK 0x14
00057 #define DISEQC_ADR_SW 0x15
00058 #define DISEQC_ADR_SMATV 0x18
00059 #define DISEQC_ADR_POL_ALL 0x20
00060 #define DISEQC_ADR_POL_LIN 0x21
00061 #define DISEQC_ADR_POS_ALL 0x30
00062 #define DISEQC_ADR_POS_AZ 0x31
00063 #define DISEQC_ADR_POS_EL 0x32
00064
00065
00066 #define DISEQC_CMD_RESET 0x00
00067 #define DISEQC_CMD_CLR_RESET 0x01
00068 #define DISEQC_CMD_WRITE_N0 0x38
00069 #define DISEQC_CMD_WRITE_N1 0x39
00070 #define DISEQC_CMD_WRITE_FREQ 0x58
00071 #define DISEQC_CMD_HALT 0x60
00072 #define DISEQC_CMD_LMT_OFF 0x63
00073 #define DISEQC_CMD_LMT_E 0x66
00074 #define DISEQC_CMD_LMT_W 0x67
00075 #define DISEQC_CMD_DRIVE_E 0x68
00076 #define DISEQC_CMD_DRIVE_W 0x69
00077 #define DISEQC_CMD_STORE_POS 0x6a
00078 #define DISEQC_CMD_GOTO_POS 0x6b
00079 #define DISEQC_CMD_GOTO_X 0x6e
00080
00081 #define TO_RADS (M_PI / 180.0)
00082 #define TO_DEC (180.0 / M_PI)
00083
00084 #define LOC QString("DiSEqCDevTree: ")
00085 #define LOC_WARN QString("DiSEqCDevTree, Warning: ")
00086 #define LOC_ERR QString("DiSEqCDevTree, Error: ")
00087
00088 QString DiSEqCDevDevice::TableToString(uint type, const TypeTable *table)
00089 {
00090 for (; !table->name.isEmpty(); table++)
00091 {
00092 if (type == table->value)
00093 return QDeepCopy<QString>(table->name);
00094 }
00095 return QString::null;
00096 }
00097
00098 uint DiSEqCDevDevice::TableFromString(const QString &type,
00099 const TypeTable *table)
00100 {
00101 uint first_val = table->value;
00102 for (; !table->name.isEmpty(); table++)
00103 {
00104 if (type == table->name)
00105 return table->value;
00106 }
00107 return first_val;
00108 }
00109
00111
00119 DiSEqCDevSettings::DiSEqCDevSettings()
00120 : m_input_id((uint) -1)
00121 {
00122 }
00123
00129 bool DiSEqCDevSettings::Load(uint card_input_id)
00130 {
00131 if (card_input_id == m_input_id)
00132 return true;
00133
00134 m_config.clear();
00135
00136
00137 MSqlQuery query(MSqlQuery::InitCon());
00138 query.prepare(
00139 "SELECT diseqcid, value "
00140 "FROM diseqc_config "
00141 "WHERE cardinputid = :INPUTID");
00142
00143 query.bindValue(":INPUTID", card_input_id);
00144 if (!query.exec() || !query.isActive())
00145 {
00146 MythContext::DBError("DiSEqCDevSettings::Load", query);
00147 return false;
00148 }
00149
00150 while (query.next())
00151 m_config[query.value(0).toUInt()] = query.value(1).toDouble();
00152
00153 m_input_id = card_input_id;
00154
00155 return true;
00156 }
00157
00163 bool DiSEqCDevSettings::Store(uint card_input_id) const
00164 {
00165 MSqlQuery query(MSqlQuery::InitCon());
00166
00167
00168 query.prepare(
00169 "DELETE from diseqc_config "
00170 "WHERE cardinputid = :INPUTID");
00171 query.bindValue(":INPUTID", card_input_id);
00172
00173 if (!query.exec() || !query.isActive())
00174 {
00175 MythContext::DBError("DiSEqCDevSettings::Store 1", query);
00176 return false;
00177 }
00178
00179
00180 query.prepare(
00181 "INSERT INTO diseqc_config "
00182 " ( cardinputid, diseqcid, value) "
00183 "VALUES (:INPUTID, :DEVID, :VALUE) ");
00184
00185 uint_to_dbl_t::const_iterator it = m_config.begin();
00186 for (; it != m_config.end(); ++it)
00187 {
00188 query.bindValue(":INPUTID", card_input_id);
00189 query.bindValue(":DEVID", it.key());
00190 query.bindValue(":VALUE", *it);
00191 if (!query.exec() || !query.isActive())
00192 {
00193 MythContext::DBError("DiSEqCDevSettings::Store 2", query);
00194 return false;
00195 }
00196 }
00197
00198 return true;
00199 }
00200
00206 double DiSEqCDevSettings::GetValue(uint devid) const
00207 {
00208 uint_to_dbl_t::const_iterator it = m_config.find(devid);
00209
00210 if (it != m_config.end())
00211 return *it;
00212
00213 return 0.0;
00214 }
00215
00221 void DiSEqCDevSettings::SetValue(uint devid, double value)
00222 {
00223 m_config[devid] = value;
00224 m_input_id = (uint) -1;
00225 }
00226
00228
00233 DiSEqCDevTrees DiSEqCDev::m_trees;
00234
00240 DiSEqCDevTree *DiSEqCDev::FindTree(uint cardid)
00241 {
00242 return m_trees.FindTree(cardid);
00243 }
00244
00248 void DiSEqCDev::InvalidateTrees(void)
00249 {
00250 m_trees.InvalidateTrees();
00251 }
00252
00254
00259 DiSEqCDevTrees::~DiSEqCDevTrees()
00260 {
00261 InvalidateTrees();
00262 }
00263
00269 DiSEqCDevTree *DiSEqCDevTrees::FindTree(uint cardid)
00270 {
00271 QMutexLocker lock(&m_trees_lock);
00272
00273 cardid_to_diseqc_tree_t::iterator it = m_trees.find(cardid);
00274 if (it != m_trees.end())
00275 return *it;
00276
00277 DiSEqCDevTree *tree = new DiSEqCDevTree;
00278 tree->Load(cardid);
00279 m_trees[cardid] = tree;
00280
00281 return tree;
00282 }
00283
00287 void DiSEqCDevTrees::InvalidateTrees(void)
00288 {
00289 QMutexLocker lock(&m_trees_lock);
00290
00291 cardid_to_diseqc_tree_t::iterator it = m_trees.begin();
00292 for (; it != m_trees.end(); ++it)
00293 delete *it;
00294
00295 m_trees.clear();
00296 }
00297
00299
00304 const uint DiSEqCDevTree::kFirstFakeDiSEqCID = 0xf0000000;
00305
00306 DiSEqCDevTree::DiSEqCDevTree() :
00307 m_fd_frontend(-1), m_root(NULL),
00308 m_previous_fake_diseqcid(kFirstFakeDiSEqCID)
00309 {
00310 Reset();
00311 }
00312
00313 DiSEqCDevTree::~DiSEqCDevTree()
00314 {
00315 delete m_root;
00316 }
00317
00323 bool DiSEqCDevTree::Load(uint cardid)
00324 {
00325
00326 delete m_root;
00327 m_delete.clear();
00328 m_root = NULL;
00329
00330
00331 MSqlQuery query(MSqlQuery::InitCon());
00332 query.prepare(
00333 "SELECT diseqcid "
00334 "FROM capturecard "
00335 "WHERE cardid = :CARDID");
00336 query.bindValue(":CARDID", cardid);
00337
00338 if (!query.exec() || !query.isActive())
00339 {
00340 MythContext::DBError("DiSEqCDevTree::Load", query);
00341 }
00342 else if (query.next() && query.value(0).toUInt())
00343 {
00344 m_root = DiSEqCDevDevice::CreateById(*this, query.value(0).toUInt());
00345 }
00346 else
00347 {
00348 VERBOSE(VB_IMPORTANT, LOC_WARN +
00349 QString("No device tree for cardid %1").arg(cardid));
00350 }
00351
00352 return m_root;
00353 }
00354
00360 bool DiSEqCDevTree::Store(uint cardid)
00361 {
00362 MSqlQuery query0(MSqlQuery::InitCon());
00363
00364
00365 if (!m_delete.empty())
00366 {
00367 MSqlQuery query1(MSqlQuery::InitCon());
00368
00369 query0.prepare(
00370 "DELETE FROM diseqc_tree "
00371 "WHERE diseqcid = :DEVID");
00372 query1.prepare(
00373 "DELETE FROM diseqc_config "
00374 "WHERE diseqcid = :DEVID");
00375
00376 vector<uint>::const_iterator it = m_delete.begin();
00377 for (; it != m_delete.end(); ++it)
00378 {
00379 query0.bindValue(":DEVID", *it);
00380 if (!query0.exec())
00381 MythContext::DBError("DiSEqCDevTree::Store 1", query0);
00382
00383 query1.bindValue(":DEVID", *it);
00384 if (!query1.exec())
00385 MythContext::DBError("DiSEqCDevTree::Store 2", query1);
00386
00387 }
00388 m_delete.clear();
00389 }
00390
00391
00392 uint devid = 0;
00393 if (m_root && m_root->Store())
00394 devid = m_root->GetDeviceID();
00395 else if (m_root)
00396 {
00397 VERBOSE(VB_IMPORTANT, "Failed to save DiSEqC tree.");
00398 return false;
00399 }
00400
00401
00402 query0.prepare(
00403 "UPDATE capturecard "
00404 "SET diseqcid = :DEVID "
00405 "WHERE cardid = :CARDID");
00406 query0.bindValue(":DEVID", devid);
00407 query0.bindValue(":CARDID", cardid);
00408 if (!query0.exec())
00409 {
00410 MythContext::DBError("DiSEqCDevTree::Store 3", query0);
00411 return false;
00412 }
00413
00414 return true;
00415 }
00416
00417 bool DiSEqCDevTree::SetTone(bool on)
00418 {
00419 (void) on;
00420
00421 bool success = false;
00422
00423 #ifdef USING_DVB
00424 for (uint retry = 0; !success && (retry < TIMEOUT_RETRIES); retry++)
00425 {
00426 if (ioctl(m_fd_frontend, FE_SET_TONE,
00427 on ? SEC_TONE_ON : SEC_TONE_OFF) == 0)
00428 success = true;
00429 else
00430 usleep(TIMEOUT_WAIT);
00431 }
00432 #endif // USING_DVB
00433
00434 if (!success)
00435 VERBOSE(VB_IMPORTANT, LOC_ERR + "FE_SET_TONE failed" + ENO);
00436
00437 return success;
00438 }
00439
00446 bool DiSEqCDevTree::Execute(const DiSEqCDevSettings &settings,
00447 const DTVMultiplex &tuning)
00448 {
00449 if (!m_root)
00450 {
00451 VERBOSE(VB_IMPORTANT, LOC_ERR + "No root device tree node!");
00452 return false;
00453 }
00454
00455
00456 ApplyVoltage(settings, tuning);
00457
00458
00459 if (m_root->IsCommandNeeded(settings, tuning))
00460 {
00461 SetTone(false);
00462 usleep(DISEQC_SHORT_WAIT);
00463 }
00464
00465 return m_root->Execute(settings, tuning);
00466 }
00467
00473 void DiSEqCDevTree::Reset(void)
00474 {
00475 if (m_root)
00476 m_root->Reset();
00477
00478 m_last_voltage = (uint) -1;
00479 }
00480
00487 DiSEqCDevRotor *DiSEqCDevTree::FindRotor(const DiSEqCDevSettings &settings, uint index)
00488 {
00489 DiSEqCDevDevice *node = m_root;
00490 DiSEqCDevRotor *rotor = NULL;
00491
00492 for (uint count = 0; node;)
00493 {
00494 rotor = dynamic_cast<DiSEqCDevRotor*>(node);
00495
00496 if (rotor && (++count > index))
00497 break;
00498
00499 node = node->GetSelectedChild(settings);
00500 }
00501
00502 return rotor;
00503 }
00504
00510 DiSEqCDevLNB *DiSEqCDevTree::FindLNB(const DiSEqCDevSettings &settings)
00511 {
00512 DiSEqCDevDevice *node = m_root;
00513 DiSEqCDevLNB *lnb = NULL;
00514
00515 while (node)
00516 {
00517 lnb = dynamic_cast<DiSEqCDevLNB*>(node);
00518
00519 if (lnb)
00520 break;
00521
00522 node = node->GetSelectedChild(settings);
00523 }
00524
00525 return lnb;
00526 }
00527
00528
00534 DiSEqCDevDevice *DiSEqCDevTree::FindDevice(uint dev_id)
00535 {
00536 if (m_root)
00537 return m_root->FindDevice(dev_id);
00538
00539 return NULL;
00540 }
00541
00546 void DiSEqCDevTree::SetRoot(DiSEqCDevDevice *root)
00547 {
00548 DiSEqCDevDevice *old_root = m_root;
00549
00550 m_root = root;
00551
00552 if (old_root)
00553 delete old_root;
00554 }
00555
00556 #ifdef USING_DVB
00557 static bool send_diseqc(int fd, const dvb_diseqc_master_cmd &cmd)
00558 {
00559 (void) fd;
00560 (void) cmd;
00561
00562 bool success = false;
00563
00564 for (uint retry = 0; !success && (retry < TIMEOUT_RETRIES); retry++)
00565 {
00566 if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd) == 0)
00567 success = true;
00568 else
00569 usleep(TIMEOUT_WAIT);
00570 }
00571
00572 if (!success)
00573 {
00574 VERBOSE(VB_IMPORTANT,
00575 "send_diseqc FE_DISEQC_SEND_MASTER_CMD failed" + ENO);
00576 }
00577
00578 return success;
00579 }
00580 #endif //USING_DVB
00581
00590 bool DiSEqCDevTree::SendCommand(uint adr, uint cmd, uint repeats,
00591 uint data_len, unsigned char *data)
00592 {
00593
00594 if (data_len > 3 || (data_len > 0 && !data))
00595 {
00596 VERBOSE(VB_IMPORTANT, LOC_ERR + "Bad DiSEqC command");
00597 return false;
00598 }
00599
00600 #ifndef USING_DVB
00601
00602 (void) adr;
00603 (void) cmd;
00604 (void) repeats;
00605 return false;
00606
00607 #else // if USING_DVB
00608
00609
00610 dvb_diseqc_master_cmd mcmd;
00611 mcmd.msg[0] = DISEQC_FRM;
00612 mcmd.msg[1] = adr;
00613 mcmd.msg[2] = cmd;
00614 mcmd.msg_len = data_len + 3;
00615
00616 if (data_len > 0)
00617 memcpy(mcmd.msg + 3, data, data_len);
00618
00619
00620 QString cmdstr;
00621 for (uint byte = 0; byte < mcmd.msg_len; byte++)
00622 cmdstr += QString("%1 ").arg(mcmd.msg[byte], 2, 16);
00623
00624 VERBOSE(VB_CHANNEL, LOC + "Sending DiSEqC Command: " + cmdstr);
00625
00626
00627 for (uint i = 0; i <= repeats; i++)
00628 {
00629 if (!send_diseqc(GetFD(), mcmd))
00630 {
00631 VERBOSE(VB_IMPORTANT, LOC_ERR + "DiSEqC command failed" + ENO);
00632 return false;
00633 }
00634
00635 mcmd.msg[0] |= DISEQC_FRM_REPEAT;
00636 usleep(DISEQC_SHORT_WAIT);
00637 }
00638
00639 return true;
00640
00641 #endif // USING_DVB
00642 }
00643
00649 bool DiSEqCDevTree::ResetDiseqc(bool hard_reset)
00650 {
00651 Reset();
00652
00653
00654
00655 if (hard_reset)
00656 {
00657 VERBOSE(VB_CHANNEL, LOC + "Power-cycling DiSEqC Bus");
00658
00659 SetVoltage(SEC_VOLTAGE_OFF);
00660 usleep(DISEQC_POWER_OFF_WAIT);
00661 }
00662
00663
00664 SetVoltage(SEC_VOLTAGE_18);
00665 usleep(DISEQC_POWER_ON_WAIT);
00666
00667
00668 VERBOSE(VB_CHANNEL, LOC + "Resetting DiSEqC Bus");
00669 if (!SendCommand(DISEQC_ADR_ALL, DISEQC_CMD_RESET))
00670 {
00671 VERBOSE(VB_IMPORTANT, LOC_ERR +
00672 "DiSEqC reset failed" + ENO);
00673 return false;
00674 }
00675
00676 usleep(DISEQC_LONG_WAIT);
00677
00678 return true;
00679 }
00680
00681 void DiSEqCDevTree::Open(int fd_frontend)
00682 {
00683 m_fd_frontend = fd_frontend;
00684
00685
00686 ResetDiseqc(false );
00687 }
00688
00689 bool DiSEqCDevTree::SetVoltage(uint voltage)
00690 {
00691
00692 if (voltage == m_last_voltage)
00693 return true;
00694
00695 int volts = ((voltage == SEC_VOLTAGE_18) ? 18 :
00696 ((voltage == SEC_VOLTAGE_13) ? 13 : 0));
00697
00698 VERBOSE(VB_CHANNEL, LOC + "Changing LNB voltage to " +
00699 QString("%1V").arg(volts));
00700
00701 bool success = false;
00702
00703 #ifdef USING_DVB
00704 for (uint retry = 0; !success && retry < TIMEOUT_RETRIES; retry++)
00705 {
00706 if (ioctl(m_fd_frontend, FE_SET_VOLTAGE, voltage) == 0)
00707 success = true;
00708 else
00709 usleep(TIMEOUT_WAIT);
00710 }
00711 #endif // USING_DVB
00712
00713 if (!success)
00714 {
00715 VERBOSE(VB_IMPORTANT, LOC_ERR + "FE_SET_VOLTAGE failed" + ENO);
00716 return false;
00717 }
00718
00719 m_last_voltage = voltage;
00720 return true;
00721 }
00722
00723 bool DiSEqCDevTree::IsInNeedOfConf(void) const
00724 {
00725 if (m_root)
00726 return m_root->GetDeviceType() != DiSEqCDevDevice::kTypeLNB;
00727
00728 return false;
00729 }
00730
00731 bool DiSEqCDevTree::ApplyVoltage(const DiSEqCDevSettings &settings,
00732 const DTVMultiplex &tuning)
00733 {
00734 uint voltage = SEC_VOLTAGE_18;
00735
00736 if (m_root)
00737 voltage = m_root->GetVoltage(settings, tuning);
00738
00739 return SetVoltage(voltage);
00740 }
00741
00743
00748 const DiSEqCDevDevice::TypeTable DiSEqCDevDevice::dvbdev_lookup[4] =
00749 {
00750 { "switch", kTypeSwitch },
00751 { "rotor", kTypeRotor },
00752 { "lnb", kTypeLNB },
00753 { QString::null, kTypeLNB },
00754 };
00755
00756
00761 DiSEqCDevDevice::DiSEqCDevDevice(DiSEqCDevTree &tree, uint devid)
00762 : m_devid(devid), m_dev_type(kTypeLNB),
00763 m_desc(QString::null), m_tree(tree),
00764 m_parent(NULL), m_ordinal(0),
00765 m_repeat(1)
00766 {
00767 }
00768
00769 DiSEqCDevDevice::~DiSEqCDevDevice()
00770 {
00771 if (IsRealDeviceID())
00772 m_tree.AddDeferredDelete(GetDeviceID());
00773 }
00774
00775 DiSEqCDevDevice *DiSEqCDevDevice::FindDevice(uint dev_id)
00776 {
00777 DiSEqCDevDevice *dev = NULL;
00778
00779 if (GetDeviceID() == dev_id)
00780 dev = this;
00781
00782 uint num_children = GetChildCount();
00783
00784 for (uint ch = 0; !dev && ch < num_children; ch++)
00785 {
00786 DiSEqCDevDevice *child = GetChild(ch);
00787 if (child)
00788 {
00789 if (child->GetDeviceID() == dev_id)
00790 dev = child;
00791 else
00792 dev = child->FindDevice(dev_id);
00793 }
00794 }
00795
00796 return dev;
00797 }
00798
00799 DiSEqCDevDevice *DiSEqCDevDevice::CreateById(DiSEqCDevTree &tree, uint devid)
00800 {
00801
00802 MSqlQuery query(MSqlQuery::InitCon());
00803 query.prepare(
00804 "SELECT type, description "
00805 "FROM diseqc_tree "
00806 "WHERE diseqcid = :DEVID");
00807 query.bindValue(":DEVID", devid);
00808
00809 if (!query.exec() || !query.isActive())
00810 {
00811 MythContext::DBError("DiSEqCDevDevice::CreateById", query);
00812 return NULL;
00813 }
00814 else if (!query.next())
00815 {
00816 VERBOSE(VB_IMPORTANT, LOC + "CreateById failed to find dtv dev " +
00817 QString("%1").arg(devid));
00818
00819 return NULL;
00820 }
00821
00822 dvbdev_t type = DevTypeFromString(query.value(0).toString());
00823 QString desc = query.value(1).toString();
00824 DiSEqCDevDevice *node = CreateByType(tree, type, devid);
00825
00826 if (node)
00827 {
00828 node->SetDescription(desc);
00829 node->Load();
00830 }
00831
00832 return node;
00833 }
00834
00835 DiSEqCDevDevice *DiSEqCDevDevice::CreateByType(DiSEqCDevTree &tree,
00836 dvbdev_t type,
00837 uint dev_id)
00838 {
00839 if (!dev_id)
00840 dev_id = tree.CreateFakeDiSEqCID();
00841
00842 DiSEqCDevDevice *node = NULL;
00843 switch (type)
00844 {
00845 case kTypeSwitch:
00846 node = new DiSEqCDevSwitch(tree, dev_id);
00847 if (node)
00848 node->SetDescription("Switch");
00849 break;
00850 case kTypeRotor:
00851 node = new DiSEqCDevRotor(tree, dev_id);
00852 if (node)
00853 node->SetDescription("Rotor");
00854 break;
00855 case kTypeLNB:
00856 node = new DiSEqCDevLNB(tree, dev_id);
00857 if (node)
00858 node->SetDescription("LNB");
00859 break;
00860 default:
00861 break;
00862 }
00863
00864 if (node)
00865 node->SetDeviceType(type);
00866
00867 return node;
00868 }
00869
00938
00939
00944 const DiSEqCDevDevice::TypeTable DiSEqCDevSwitch::SwitchTypeTable[9] =
00945 {
00946 { "legacy_sw21", kTypeLegacySW21 },
00947 { "legacy_sw42", kTypeLegacySW42 },
00948 { "legacy_sw64", kTypeLegacySW64 },
00949 { "tone", kTypeTone },
00950 { "diseqc", kTypeDiSEqCCommitted },
00951 { "diseqc_uncom", kTypeDiSEqCUncommitted },
00952 { "voltage", kTypeVoltage },
00953 { "mini_diseqc", kTypeMiniDiSEqC },
00954 { QString::null, kTypeTone },
00955 };
00956
00957 DiSEqCDevSwitch::DiSEqCDevSwitch(DiSEqCDevTree &tree, uint devid)
00958 : DiSEqCDevDevice(tree, devid),
00959 m_type(kTypeTone), m_num_ports(2)
00960 {
00961 m_children.resize(m_num_ports);
00962
00963 for (uint i = 0; i < m_num_ports; i++)
00964 m_children[i] = NULL;
00965
00966 Reset();
00967 }
00968
00969 DiSEqCDevSwitch::~DiSEqCDevSwitch()
00970 {
00971 dvbdev_vec_t::iterator it = m_children.begin();
00972 for (; it != m_children.end(); ++it)
00973 {
00974 if (*it)
00975 delete *it;
00976 }
00977 }
00978
00979 bool DiSEqCDevSwitch::Execute(const DiSEqCDevSettings &settings,
00980 const DTVMultiplex &tuning)
00981 {
00982 bool success = true;
00983
00984
00985 int pos = GetPosition(settings);
00986 if (pos < 0)
00987 return false;
00988
00989
00990 if (ShouldSwitch(settings, tuning))
00991 {
00992 switch (m_type)
00993 {
00994 case kTypeTone:
00995 success = ExecuteTone(settings, tuning, pos);
00996 break;
00997 case kTypeDiSEqCCommitted:
00998 case kTypeDiSEqCUncommitted:
00999 success = ExecuteDiseqc(settings, tuning, pos);
01000 break;
01001 case kTypeLegacySW21:
01002 case kTypeLegacySW42:
01003 case kTypeLegacySW64:
01004 success = ExecuteLegacy(settings, tuning, pos);
01005 break;
01006 case kTypeVoltage:
01007 success = ExecuteVoltage(settings, tuning, pos);
01008 break;
01009 case kTypeMiniDiSEqC:
01010 success = ExecuteMiniDiSEqC(settings, tuning, pos);
01011 break;
01012 default:
01013 success = false;
01014 VERBOSE(VB_IMPORTANT, LOC_ERR +
01015 QString("Unknown switch type (%1)")
01016 .arg((uint)m_type));
01017 break;
01018 }
01019
01020
01021 if (m_children[pos]->IsCommandNeeded(settings, tuning))
01022 {
01023 VERBOSE(VB_CHANNEL, LOC + "Waiting for switch");
01024 usleep(DISEQC_LONG_WAIT);
01025 }
01026
01027 m_last_pos = pos;
01028 }
01029
01030
01031 if (success)
01032 success = m_children[pos]->Execute(settings, tuning);
01033
01034 return success;
01035 }
01036
01037 void DiSEqCDevSwitch::Reset(void)
01038 {
01039 m_last_pos = (uint) -1;
01040 m_last_high_band = (uint) -1;
01041 m_last_horizontal = (uint) -1;
01042 dvbdev_vec_t::iterator it = m_children.begin();
01043 for (; it != m_children.end(); ++it)
01044 {
01045 if (*it)
01046 (*it)->Reset();
01047 }
01048 }
01049
01050 bool DiSEqCDevSwitch::IsCommandNeeded(const DiSEqCDevSettings &settings,
01051 const DTVMultiplex &tuning) const
01052 {
01053 int pos = GetPosition(settings);
01054 if (pos < 0)
01055 return false;
01056
01057 return (ShouldSwitch(settings, tuning) ||
01058 m_children[pos]->IsCommandNeeded(settings, tuning));
01059 }
01060
01061 DiSEqCDevDevice *DiSEqCDevSwitch::GetSelectedChild(const DiSEqCDevSettings &settings) const
01062 {
01063
01064 int pos = GetPosition(settings);
01065 if (pos < 0)
01066 return NULL;
01067
01068 return m_children[pos];
01069 }
01070
01071 uint DiSEqCDevSwitch::GetChildCount(void) const
01072 {
01073 return m_num_ports;
01074 }
01075
01076 DiSEqCDevDevice *DiSEqCDevSwitch::GetChild(uint ordinal)
01077 {
01078 if (ordinal < m_children.size())
01079 return m_children[ordinal];
01080
01081 return NULL;
01082 }
01083
01084 bool DiSEqCDevSwitch::SetChild(uint ordinal, DiSEqCDevDevice *device)
01085 {
01086 if (ordinal >= m_children.size())
01087 return false;
01088
01089 if (m_children[ordinal])
01090 delete m_children[ordinal];
01091
01092 m_children[ordinal] = device;
01093 if (device)
01094 {
01095 device->SetOrdinal(ordinal);
01096 device->SetParent(this);
01097 }
01098
01099 return true;
01100 }
01101
01102 uint DiSEqCDevSwitch::GetVoltage(const DiSEqCDevSettings &settings,
01103 const DTVMultiplex &tuning) const
01104 {
01105 uint voltage = SEC_VOLTAGE_18;
01106 DiSEqCDevDevice *child = GetSelectedChild(settings);
01107
01108 if (child)
01109 voltage = child->GetVoltage(settings, tuning);
01110
01111 return voltage;
01112 }
01113
01114 bool DiSEqCDevSwitch::Load(void)
01115 {
01116
01117 dvbdev_vec_t::iterator it = m_children.begin();
01118 for (; it != m_children.end(); ++it)
01119 {
01120 if (*it)
01121 delete *it;
01122 }
01123
01124 m_children.clear();
01125
01126
01127 MSqlQuery query(MSqlQuery::InitCon());
01128 query.prepare(
01129 "SELECT subtype, switch_ports, cmd_repeat "
01130 "FROM diseqc_tree "
01131 "WHERE diseqcid = :DEVID");
01132 query.bindValue(":DEVID", GetDeviceID());
01133
01134 if (!query.exec() || !query.isActive())
01135 {
01136 MythContext::DBError("DiSEqCDevSwitch::Load 1", query);
01137 return false;
01138 }
01139 else if (query.next())
01140 {
01141 m_type = SwitchTypeFromString(query.value(0).toString());
01142 m_num_ports = query.value(1).toUInt();
01143 m_repeat = query.value(2).toUInt();
01144 m_children.resize(m_num_ports);
01145 for (uint i = 0; i < m_num_ports; i++)
01146 m_children[i] = NULL;
01147 }
01148
01149
01150 query.prepare(
01151 "SELECT diseqcid, ordinal "
01152 "FROM diseqc_tree "
01153 "WHERE parentid = :DEVID");
01154 query.bindValue(":DEVID", GetDeviceID());
01155 if (!query.exec() || !query.isActive())
01156 {
01157 MythContext::DBError("DiSEqCDevSwitch::Load 2", query);
01158 return false;
01159 }
01160
01161 while (query.next())
01162 {
01163 uint child_dev_id = query.value(0).toUInt();
01164 uint ordinal = query.value(1).toUInt();
01165 DiSEqCDevDevice *child = CreateById(m_tree, child_dev_id);
01166 if (child && !SetChild(ordinal, child))
01167 {
01168 VERBOSE(VB_IMPORTANT, LOC_ERR +
01169 QString("Switch port out of range (%1 > %2)")
01170 .arg(ordinal + 1).arg(m_num_ports));
01171 delete child;
01172 }
01173 }
01174
01175 return true;
01176 }
01177
01178 bool DiSEqCDevSwitch::Store(void) const
01179 {
01180 QString type = SwitchTypeToString(m_type);
01181 MSqlQuery query(MSqlQuery::InitCon());
01182
01183
01184 if (IsRealDeviceID())
01185 {
01186 query.prepare(
01187 "UPDATE diseqc_tree "
01188 "SET parentid = :PARENT, "
01189 " ordinal = :ORDINAL, "
01190 " type = 'switch', "
01191 " description = :DESC, "
01192 " subtype = :TYPE, "
01193 " switch_ports = :PORTS, "
01194 " cmd_repeat = :REPEAT "
01195 "WHERE diseqcid = :DEVID");
01196 }
01197 else
01198 {
01199 query.prepare(
01200 "INSERT INTO diseqc_tree"
01201 " ( parentid, ordinal, type, "
01202 " description, subtype, switch_ports, "
01203 " cmd_repeat )"
01204 "VALUES "
01205 " (:PARENT, :ORDINAL, 'switch', "
01206 " :DESC, :TYPE, :PORTS, "
01207 " :REPEAT )");
01208 }
01209
01210 if (m_parent)
01211 query.bindValue(":PARENT", m_parent->GetDeviceID());
01212
01213 query.bindValue(":ORDINAL", m_ordinal);
01214 query.bindValue(":DESC", GetDescription());
01215 query.bindValue(":TYPE", type);
01216 query.bindValue(":PORTS", m_num_ports);
01217 query.bindValue(":REPEAT", m_repeat);
01218 query.bindValue(":DEVID", GetDeviceID());
01219
01220 if (!query.exec())
01221 {
01222 MythContext::DBError("DiSEqCDevSwitch::Store", query);
01223 return false;
01224 }
01225
01226
01227 if (!IsRealDeviceID())
01228 SetDeviceID(query.lastInsertId().toUInt());
01229
01230
01231 bool success = true;
01232 for (uint ch = 0; ch < m_children.size(); ch++)
01233 {
01234 if (m_children[ch])
01235 success &= m_children[ch]->Store();
01236 }
01237
01238 return success;
01239 }
01240
01241 void DiSEqCDevSwitch::SetNumPorts(uint num_ports)
01242 {
01243 uint old_num = m_children.size();
01244
01245 if (old_num > num_ports)
01246 {
01247 for (uint ch = num_ports; ch < old_num; ch++)
01248 {
01249 if (m_children[ch])
01250 delete m_children[ch];
01251 }
01252 m_children.resize(num_ports);
01253 }
01254 else if (old_num < num_ports)
01255 {
01256 m_children.resize(num_ports);
01257 for (uint ch = old_num; ch < num_ports; ch++)
01258 m_children[ch] = NULL;
01259 }
01260
01261 m_num_ports = num_ports;
01262 }
01263
01264 bool DiSEqCDevSwitch::ExecuteLegacy(const DiSEqCDevSettings &settings,
01265 const DTVMultiplex &tuning,
01266 uint pos)
01267 {
01268 (void) settings;
01269 (void) tuning;
01270 (void) pos;
01271
01272 #if defined(USING_DVB) && defined(FE_DISHNETWORK_SEND_LEGACY_CMD)
01273 static const unsigned char sw21_cmds[] = { 0x34, 0x65, };
01274 static const unsigned char sw42_cmds[] = { 0x46, 0x17, };
01275 static const unsigned char sw64_v_cmds[] = { 0x39, 0x4b, 0x0d, };
01276 static const unsigned char sw64_h_cmds[] = { 0x1a, 0x5c, 0x2e, };
01277
01278 const unsigned char *cmds = NULL;
01279 unsigned char horizcmd = 0x00;
01280 uint num_ports = 0;
01281
01282
01283 bool horizontal = false;
01284 DiSEqCDevLNB *lnb = m_tree.FindLNB(settings);
01285 if (lnb)
01286 horizontal = lnb->IsHorizontal(tuning);
01287
01288
01289 switch (m_type)
01290 {
01291 case kTypeLegacySW21:
01292 cmds = sw21_cmds;
01293 num_ports = 2;
01294 if (horizontal)
01295 horizcmd = 0x80;
01296 break;
01297 case kTypeLegacySW42:
01298 cmds = sw42_cmds;
01299 num_ports = 2;
01300 break;
01301 case kTypeLegacySW64:
01302 if (horizontal)
01303 cmds = sw64_h_cmds;
01304 else
01305 cmds = sw64_v_cmds;
01306 num_ports = 3;
01307 break;
01308 default:
01309 return false;
01310 }
01311 if (num_ports)
01312 pos %= num_ports;
01313
01314 VERBOSE(VB_CHANNEL, LOC + QString("Changing to Legacy switch port %1/%2")
01315 .arg(pos + 1).arg(num_ports));
01316
01317
01318 if (ioctl(m_tree.GetFD(), FE_DISHNETWORK_SEND_LEGACY_CMD,
01319 cmds[pos] | horizcmd) == -1)
01320 {
01321 VERBOSE(VB_IMPORTANT, LOC_ERR +
01322 "FE_DISHNETWORK_SEND_LEGACY_CMD failed" + ENO);
01323
01324 return false;
01325 }
01326
01327 return true;
01328
01329 #else // !FE_DISHNETWORK_SEND_LEGACY_CMD
01330
01331 VERBOSE(VB_IMPORTANT, LOC_ERR + "You must compile with a newer "
01332 "version of the linux headers for DishNet Legacy switch support.");
01333 return false;
01334
01335 #endif // !FE_DISHNETWORK_SEND_LEGACY_CMD
01336 }
01337
01338 #ifdef USING_DVB
01339 static bool set_tone(int fd, fe_sec_tone_mode tone)
01340 {
01341 (void) fd;
01342 (void) tone;
01343
01344 bool success = false;
01345
01346 for (uint retry = 0; !success && (retry < TIMEOUT_RETRIES); retry++)
01347 {
01348 if (ioctl(fd, FE_SET_TONE, tone) == 0)
01349 success = true;
01350 else
01351 usleep(TIMEOUT_WAIT);
01352 }
01353
01354 if (!success)
01355 {
01356 VERBOSE(VB_IMPORTANT, "set_tone failed" + ENO);
01357 }
01358
01359 return success;
01360 }
01361 #endif // USING_DVB
01362
01363 #ifdef USING_DVB
01364 static bool set_voltage(int fd, fe_sec_voltage volt)
01365 {
01366 (void) fd;
01367 (void) volt;
01368
01369 bool success = false;
01370
01371 for (uint retry = 0; !success && (retry < TIMEOUT_RETRIES); retry++)
01372 {
01373 if (0 == ioctl(fd, FE_SET_VOLTAGE, volt))
01374 success = true;
01375 else
01376 usleep(TIMEOUT_WAIT);
01377 }
01378
01379 if (!success)
01380 {
01381 VERBOSE(VB_IMPORTANT, "FE_SET_VOLTAGE failed" + ENO);
01382 }
01383
01384 return success;
01385 }
01386 #endif // USING_DVB
01387
01388 #ifdef USING_DVB
01389 static bool mini_diseqc(int fd, fe_sec_mini_cmd cmd)
01390 {
01391 (void) fd;
01392 (void) cmd;
01393
01394 bool success = false;
01395
01396 for (uint retry = 0; !success && (retry < TIMEOUT_RETRIES); retry++)
01397 {
01398 if (ioctl(fd, FE_DISEQC_SEND_BURST, cmd) == 0)
01399 success = true;
01400 else
01401 usleep(TIMEOUT_WAIT);
01402 }
01403
01404 if (!success)
01405 {
01406 VERBOSE(VB_IMPORTANT, "mini_diseqc FE_DISEQC_SEND_BURST failed" + ENO);
01407 }
01408
01409 return success;
01410 }
01411 #endif // USING_DVB
01412
01413 bool DiSEqCDevSwitch::ExecuteTone(const DiSEqCDevSettings &,
01414 const DTVMultiplex &,
01415 uint pos)
01416 {
01417 VERBOSE(VB_CHANNEL, LOC + "Changing to Tone switch port " +
01418 QString("%1/2").arg(pos + 1));
01419
01420 #ifdef USING_DVB
01421 if (set_tone(m_tree.GetFD(), (0 == pos) ? SEC_TONE_OFF : SEC_TONE_ON))
01422 return true;
01423 #endif // USING_DVB
01424
01425 VERBOSE(VB_IMPORTANT, LOC_ERR + "Setting Tone Switch failed." + ENO);
01426 return false;
01427 }
01428
01429 bool DiSEqCDevSwitch::ExecuteVoltage(const DiSEqCDevSettings &settings,
01430 const DTVMultiplex &tuning, uint pos)
01431 {
01432 (void) settings;
01433 (void) tuning;
01434
01435 VERBOSE(VB_CHANNEL, LOC + "Changing to Voltage Switch port " +
01436 QString("%1/2").arg(pos + 1));
01437
01438 #ifdef USING_DVB
01439 if (set_voltage(m_tree.GetFD(),
01440 (0 == pos) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18))
01441 {
01442 return true;
01443 }
01444 #endif // USING_DVB
01445
01446 VERBOSE(VB_IMPORTANT, LOC_ERR + "Setting Voltage Switch failed." + ENO);
01447
01448 return false;
01449 }
01450
01451 bool DiSEqCDevSwitch::ExecuteMiniDiSEqC(const DiSEqCDevSettings &settings,
01452 const DTVMultiplex &tuning, uint pos)
01453 {
01454 (void) settings;
01455 (void) tuning;
01456
01457 VERBOSE(VB_CHANNEL, LOC + "Changing to MiniDiSEqC Switch port " +
01458 QString("%1/2").arg(pos + 1));
01459
01460 #ifdef USING_DVB
01461 if (mini_diseqc(m_tree.GetFD(), (0 == pos) ? SEC_MINI_A : SEC_MINI_B))
01462 return true;
01463 #endif // USING_DVB
01464
01465 VERBOSE(VB_IMPORTANT, LOC_ERR +
01466 "Setting Mini DiSEqC Switch failed." + ENO);
01467
01468 return false;
01469 }
01470
01471 bool DiSEqCDevSwitch::ShouldSwitch(const DiSEqCDevSettings &settings,
01472 const DTVMultiplex &tuning) const
01473 {
01474 int pos = GetPosition(settings);
01475 if (pos < 0)
01476 return false;
01477
01478
01479 if (kTypeDiSEqCCommitted == m_type)
01480 {
01481
01482 bool high_band = false;
01483 bool horizontal = false;
01484 DiSEqCDevLNB *lnb = m_tree.FindLNB(settings);
01485 if (lnb)
01486 {
01487 high_band = lnb->IsHighBand(tuning);
01488 horizontal = lnb->IsHorizontal(tuning);
01489 }
01490
01491 if(high_band != m_last_high_band ||
01492 horizontal != m_last_horizontal)
01493 return true;
01494 }
01495 else if (kTypeLegacySW42 == m_type ||
01496 kTypeLegacySW64 == m_type)
01497 {
01498
01499 bool horizontal = false;
01500 DiSEqCDevLNB *lnb = m_tree.FindLNB(settings);
01501 if (lnb)
01502 horizontal = lnb->IsHorizontal(tuning);
01503
01504 if (horizontal != m_last_horizontal)
01505 return true;
01506 }
01507 else if (kTypeTone == m_type)
01508 return true;
01509
01510 return m_last_pos != (uint)pos;
01511 }
01512
01513 bool DiSEqCDevSwitch::ExecuteDiseqc(const DiSEqCDevSettings &settings,
01514 const DTVMultiplex &tuning,
01515 uint pos)
01516 {
01517
01518 bool high_band = false;
01519 bool horizontal = false;
01520 DiSEqCDevLNB *lnb = m_tree.FindLNB(settings);
01521 if (lnb)
01522 {
01523 high_band = lnb->IsHighBand(tuning);
01524 horizontal = lnb->IsHorizontal(tuning);
01525 }
01526
01527
01528 if ((kTypeDiSEqCCommitted == m_type) && (m_num_ports > 4) ||
01529 (kTypeDiSEqCUncommitted == m_type) && (m_num_ports > 16))
01530 {
01531 VERBOSE(VB_IMPORTANT, LOC_ERR +
01532 QString("Invalid number of ports for DiSEqC 1.x Switch (%1)")
01533 .arg(m_num_ports));
01534 return false;
01535 }
01536
01537
01538 uint cmd = DISEQC_CMD_WRITE_N1;
01539 unsigned char data = pos;
01540 if (kTypeDiSEqCUncommitted != m_type)
01541 {
01542 cmd = DISEQC_CMD_WRITE_N0;
01543 data = ((pos << 2) | (horizontal ? 2 : 0) | (high_band ? 1 : 0));
01544 }
01545 data |= 0xf0;
01546
01547 VERBOSE(VB_CHANNEL, LOC + "Changing to DiSEqC switch port " +
01548 QString("%1/%2").arg(pos + 1).arg(m_num_ports));
01549
01550 bool ret = m_tree.SendCommand(DISEQC_ADR_SW_ALL, cmd, m_repeat, 1, &data);
01551 if(ret)
01552 {
01553 m_last_high_band = high_band;
01554 m_last_horizontal = horizontal;
01555 }
01556 return ret;
01557 }
01558
01559 int DiSEqCDevSwitch::GetPosition(const DiSEqCDevSettings &settings) const
01560 {
01561 int pos = (int) settings.GetValue(GetDeviceID());
01562
01563 if (pos >= (int)m_num_ports)
01564 {
01565 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Port %1 ").arg(pos + 1) +
01566 QString("is not in range [0..%1)").arg(m_num_ports));
01567
01568 return -1;
01569 }
01570
01571 if ((pos >= 0) && !m_children[pos])
01572 {
01573 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Port %1 ").arg(pos + 1) +
01574 "has no connected devices configured.");
01575
01576 return -1;
01577 }
01578
01579 return pos;
01580 }
01581
01583
01584 static double GetCurTimeFloating(void)
01585 {
01586 struct timeval curtime;
01587 gettimeofday(&curtime, NULL);
01588 return (double)curtime.tv_sec + (((double)curtime.tv_usec) / 1000000);
01589 }
01590
01595 const DiSEqCDevDevice::TypeTable DiSEqCDevRotor::RotorTypeTable[] =
01596 {
01597 { "diseqc_1_2", kTypeDiSEqC_1_2 },
01598 { "diseqc_1_3", kTypeDiSEqC_1_3 },
01599 { NULL, kTypeDiSEqC_1_3 }
01600 };
01601
01602 DiSEqCDevRotor::DiSEqCDevRotor(DiSEqCDevTree &tree, uint devid)
01603 : DiSEqCDevDevice(tree, devid),
01604 m_type(kTypeDiSEqC_1_3),
01605 m_speed_hi(2.5), m_speed_lo(1.9),
01606 m_child(NULL),
01607 m_last_position(0.0), m_desired_azimuth(0.0),
01608 m_reset(true), m_move_time(0.0),
01609 m_last_pos_known(false), m_last_azimuth(0.0)
01610 {
01611 Reset();
01612 }
01613
01614 DiSEqCDevRotor::~DiSEqCDevRotor()
01615 {
01616 if (m_child)
01617 delete m_child;
01618 }
01619
01620 bool DiSEqCDevRotor::Execute(const DiSEqCDevSettings &settings,
01621 const DTVMultiplex &tuning)
01622 {
01623 bool success = true;
01624
01625 double position = settings.GetValue(GetDeviceID());
01626 if (m_reset || (position != m_last_position))
01627 {
01628 switch (m_type)
01629 {
01630 case kTypeDiSEqC_1_2:
01631 success = ExecuteRotor(settings, tuning, position);
01632 break;
01633 case kTypeDiSEqC_1_3:
01634 success = ExecuteUSALS(settings, tuning, position);
01635 break;
01636 default:
01637 success = false;
01638 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unknown rotor type " +
01639 QString("(%1)").arg((uint) m_type));
01640 break;
01641 }
01642
01643 m_last_position = position;
01644 m_reset = false;
01645 }
01646
01647
01648 if (success && m_child)
01649 success = m_child->Execute(settings, tuning);
01650
01651 return success;
01652 }
01653
01654 void DiSEqCDevRotor::Reset(void)
01655 {
01656 m_reset = true;
01657 if (m_child)
01658 m_child->Reset();
01659 }
01660
01661 bool DiSEqCDevRotor::IsCommandNeeded(const DiSEqCDevSettings &settings,
01662 const DTVMultiplex &tuning) const
01663 {
01664 double position = settings.GetValue(GetDeviceID());
01665
01666 if (m_reset || (position != m_last_position))
01667 return true;
01668
01669 if (m_child)
01670 return m_child->IsCommandNeeded(settings, tuning);
01671
01672 return false;
01673 }
01674
01675 DiSEqCDevDevice *DiSEqCDevRotor::GetSelectedChild(const DiSEqCDevSettings&) const
01676 {
01677 return m_child;
01678 }
01679
01680 bool DiSEqCDevRotor::SetChild(uint ordinal, DiSEqCDevDevice *device)
01681 {
01682 if (ordinal)
01683 return false;
01684
01685 DiSEqCDevDevice *old_child = m_child;
01686 m_child = NULL;
01687 if (old_child)
01688 delete old_child;
01689
01690 m_child = device;
01691 if (m_child)
01692 {
01693 m_child->SetOrdinal(ordinal);
01694 m_child->SetParent(this);
01695 }
01696
01697 return true;
01698 }
01699
01700 bool DiSEqCDevRotor::IsMoving(const DiSEqCDevSettings &settings) const
01701 {
01702 double position = settings.GetValue(GetDeviceID());
01703 double completed = GetProgress();
01704 bool moving = (completed < 1.0) || (position != m_last_position);
01705
01706 return (m_last_pos_known && moving);
01707 }
01708
01709 uint DiSEqCDevRotor::GetVoltage(const DiSEqCDevSettings &settings,
01710 const DTVMultiplex &tuning) const
01711 {
01712
01713 if (IsMoving(settings))
01714 {
01715 VERBOSE(VB_CHANNEL, LOC +
01716 "Overriding voltage to 18V for faster rotor movement");
01717 }
01718 else if (m_child)
01719 {
01720 return m_child->GetVoltage(settings, tuning);
01721 }
01722
01723 return SEC_VOLTAGE_18;
01724 }
01725
01726 bool DiSEqCDevRotor::Load(void)
01727 {
01728
01729 MSqlQuery query(MSqlQuery::InitCon());
01730 query.prepare(
01731 "SELECT subtype, rotor_positions, "
01732 " rotor_hi_speed, rotor_lo_speed, "
01733 " cmd_repeat "
01734 "FROM diseqc_tree "
01735 "WHERE diseqcid = :DEVID");
01736 query.bindValue(":DEVID", GetDeviceID());
01737
01738 if (!query.exec() || !query.isActive())
01739 {
01740 MythContext::DBError("DiSEqCDevRotor::Load 1", query);
01741 return false;
01742 }
01743 else if (query.next())
01744 {
01745 m_type = RotorTypeFromString(query.value(0).toString());
01746 m_speed_hi = query.value(2).toDouble();
01747 m_speed_lo = query.value(3).toDouble();
01748 m_repeat = query.value(4).toUInt();
01749
01750
01751 QString positions = query.value(1).toString();
01752 QStringList pos = QStringList::split(":", positions);
01753 for (uint i = 0; i < pos.count(); i++)
01754 {
01755 QStringList eq = QStringList::split("=", pos[i]);
01756 if (eq.count() == 2)
01757 m_posmap[eq[0].toFloat()] = eq[1].toUInt();
01758 }
01759 }
01760
01761
01762 if (m_child)
01763 {
01764 delete m_child;
01765 m_child = NULL;
01766 }
01767
01768 query.prepare(
01769 "SELECT diseqcid "
01770 "FROM diseqc_tree "
01771 "WHERE parentid = :DEVID");
01772 query.bindValue(":DEVID", GetDeviceID());
01773
01774 if (!query.exec() || !query.isActive())
01775 {
01776 MythContext::DBError("DiSEqCDevRotor::Load 2", query);
01777 return false;
01778 }
01779 else if (query.next())
01780 {
01781 uint child_dev_id = query.value(0).toUInt();
01782 SetChild(0, CreateById(m_tree, child_dev_id));
01783 }
01784
01785 return true;
01786 }
01787
01788 bool DiSEqCDevRotor::Store(void) const
01789 {
01790 QString posmap = "";
01791 QString type = RotorTypeToString(m_type);
01792
01793 if (!m_posmap.empty())
01794 {
01795 QStringList pos;
01796
01797 dbl_to_uint_t::const_iterator it = m_posmap.begin();
01798 for (; it != m_posmap.end(); ++it)
01799 pos.push_back(QString("%1=%2").arg(it.key()).arg(*it));
01800
01801 posmap = pos.join(":");
01802 }
01803
01804 MSqlQuery query(MSqlQuery::InitCon());
01805
01806
01807 if (IsRealDeviceID())
01808 {
01809 query.prepare(
01810 "UPDATE diseqc_tree "
01811 "SET parentid = :PARENT, "
01812 " ordinal = :ORDINAL, "
01813 " type = 'rotor', "
01814 " description = :DESC, "
01815 " subtype = :TYPE, "
01816 " rotor_hi_speed = :HISPEED, "
01817 " rotor_lo_speed = :LOSPEED, "
01818 " rotor_positions = :POSMAP, "
01819 " cmd_repeat = :REPEAT "
01820 "WHERE diseqcid = :DEVID");
01821 }
01822 else
01823 {
01824 query.prepare(
01825 "INSERT INTO diseqc_tree "
01826 " ( parentid, ordinal, type, "
01827 " description, subtype, rotor_hi_speed, "
01828 " rotor_lo_speed, rotor_positions, cmd_repeat ) "
01829 "VALUES "
01830 " (:PARENT, :ORDINAL, 'rotor', "
01831 " :DESC, :TYPE, :HISPEED, "
01832 " :LOSPEED, :POSMAP, :REPEAT )");
01833 }
01834
01835 if (m_parent)
01836 query.bindValue(":PARENT", m_parent->GetDeviceID());
01837
01838 query.bindValue(":ORDINAL", m_ordinal);
01839 query.bindValue(":DESC", GetDescription());
01840 query.bindValue(":TYPE", type);
01841 query.bindValue(":HISPEED", m_speed_hi);
01842 query.bindValue(":LOSPEED", m_speed_lo);
01843 query.bindValue(":POSMAP", posmap);
01844 query.bindValue(":REPEAT", m_repeat);
01845 query.bindValue(":DEVID", GetDeviceID());
01846
01847 if (!query.exec())
01848 {
01849 MythContext::DBError("DiSEqCDevRotor::Store", query);
01850 return false;
01851 }
01852
01853
01854 if (!IsRealDeviceID())
01855 SetDeviceID(query.lastInsertId().toUInt());
01856
01857
01858 if (m_child)
01859 return m_child->Store();
01860
01861 return true;
01862 }
01863
01869 double DiSEqCDevRotor::GetProgress(void) const
01870 {
01871 if (m_move_time == 0.0)
01872 return 1.0;
01873
01874
01875 double speed = ((m_tree.GetVoltage() == SEC_VOLTAGE_18) ?
01876 m_speed_hi : m_speed_lo);
01877 double change = abs(m_desired_azimuth - m_last_azimuth);
01878 double duration = change / speed;
01879
01880
01881 double time_since_move = GetCurTimeFloating() - m_move_time;
01882 double completed = time_since_move / duration;
01883 if(completed > 1.0)
01884 {
01885 RotationComplete();
01886 completed = 1.0;
01887 }
01888
01889 return completed;
01890 }
01891
01899 bool DiSEqCDevRotor::IsPositionKnown(void) const
01900 {
01901 return m_last_pos_known;
01902 }
01903
01904 uint_to_dbl_t DiSEqCDevRotor::GetPosMap(void) const
01905 {
01906 uint_to_dbl_t inv_posmap;
01907 dbl_to_uint_t::const_iterator it;
01908 for (it = m_posmap.begin(); it != m_posmap.end(); ++it)
01909 inv_posmap[*it] = it.key();
01910
01911 return inv_posmap;
01912 }
01913
01914 void DiSEqCDevRotor::SetPosMap(const uint_to_dbl_t &inv_posmap)
01915 {
01916 m_posmap.clear();
01917
01918 uint_to_dbl_t::const_iterator it;
01919 for (it = inv_posmap.begin(); it != inv_posmap.end(); ++it)
01920 m_posmap[*it] = it.key();
01921 }
01922
01923 bool DiSEqCDevRotor::ExecuteRotor(const DiSEqCDevSettings&, const DTVMultiplex&,
01924 double angle)
01925 {
01926
01927 dbl_to_uint_t::const_iterator it = m_posmap.find(angle);
01928 unsigned char index = (uint) angle;
01929 if (it != m_posmap.end())
01930 {
01931 index = *it;
01932 StartRotorPositionTracking(CalculateAzimuth(angle));
01933 }
01934
01935 VERBOSE(VB_CHANNEL, LOC + "Rotor - " +
01936 QString("Goto Stored Position %1").arg(index));
01937
01938 return m_tree.SendCommand(DISEQC_ADR_POS_AZ, DISEQC_CMD_GOTO_POS,
01939 m_repeat, 1, &index);
01940 }
01941
01942 bool DiSEqCDevRotor::ExecuteUSALS(const DiSEqCDevSettings&, const DTVMultiplex&,
01943 double angle)
01944 {
01945 double azimuth = CalculateAzimuth(angle);
01946 StartRotorPositionTracking(azimuth);
01947
01948 VERBOSE(VB_CHANNEL, LOC + "USALS Rotor - " +
01949 QString("Goto %1 (Azimuth %2)").arg(angle).arg(azimuth));
01950
01951 uint az16 = (uint) (abs(azimuth) * 16.0);
01952 unsigned char cmd[2];
01953 cmd[0] = ((azimuth > 0.0) ? 0xE0 : 0xD0) | ((az16 >> 8) &0x0f);
01954 cmd[1] = (az16 &0xff);
01955
01956 return m_tree.SendCommand(DISEQC_ADR_POS_AZ, DISEQC_CMD_GOTO_X,
01957 m_repeat, 2, cmd);
01958 }
01959
01960 double DiSEqCDevRotor::CalculateAzimuth(double angle) const
01961 {
01962
01963
01964
01965
01966 double P = gContext->GetSetting("Latitude", "").toFloat() * TO_RADS;
01967 double Ue = gContext->GetSetting("Longitude", "").toFloat() * TO_RADS;
01968
01969
01970 double Us = angle * TO_RADS;
01971
01972 double az = M_PI + atan( tan(Us - Ue) / sin(P) );
01973 double x = acos( cos(Us - Ue) *cos(P) );
01974 double el = atan( (cos(x) - 0.1513) / sin(x) );
01975 double tmp_a = -cos(el) *sin(az);
01976 double tmp_b = (sin(el) *cos(P)) - (cos(el) *sin(P) *cos(az));
01977 double azimuth = atan(tmp_a / tmp_b) *TO_DEC;
01978
01979 return azimuth;
01980 }
01981
01982 double DiSEqCDevRotor::GetApproxAzimuth(void) const
01983 {
01984 if (m_move_time == 0.0)
01985 return m_last_azimuth;
01986
01987 double change = m_desired_azimuth - m_last_azimuth;
01988 return m_last_azimuth + (change * GetProgress());
01989 }
01990
01991 void DiSEqCDevRotor::StartRotorPositionTracking(double azimuth)
01992 {
01993
01994 m_desired_azimuth = azimuth;
01995
01996
01997 if (m_last_pos_known || m_move_time > 0.0)
01998 m_last_azimuth = GetApproxAzimuth();
01999 else
02000 m_last_azimuth = azimuth > 0.0 ? -75.0 : 75.0;
02001
02002 m_move_time = GetCurTimeFloating();
02003 }
02004
02005 void DiSEqCDevRotor::RotationComplete(void) const
02006 {
02007 m_move_time = 0.0;
02008 m_last_pos_known = true;
02009 m_last_azimuth = m_desired_azimuth;
02010 }
02011
02013
02018 const DiSEqCDevDevice::TypeTable DiSEqCDevLNB::LNBTypeTable[5] =
02019 {
02020 { "fixed", kTypeFixed },
02021 { "voltage", kTypeVoltageControl },
02022 { "voltage_tone", kTypeVoltageAndToneControl },
02023 { "bandstacked", kTypeBandstacked },
02024 { QString::null, kTypeVoltageAndToneControl },
02025 };
02026
02027 DiSEqCDevLNB::DiSEqCDevLNB(DiSEqCDevTree &tree, uint devid)
02028 : DiSEqCDevDevice(tree, devid),
02029 m_type(kTypeVoltageAndToneControl), m_lof_switch(11700000),
02030 m_lof_hi(10600000), m_lof_lo(9750000),
02031 m_pol_inv(false)
02032 {
02033 Reset();
02034 }
02035
02036 bool DiSEqCDevLNB::Execute(const DiSEqCDevSettings&, const DTVMultiplex &tuning)
02037 {
02038
02039 if (m_type == kTypeVoltageAndToneControl)
02040 m_tree.SetTone(IsHighBand(tuning));
02041
02042 return true;
02043 }
02044
02045 uint DiSEqCDevLNB::GetVoltage(const DiSEqCDevSettings&,
02046 const DTVMultiplex &tuning) const
02047 {
02048 uint voltage = SEC_VOLTAGE_18;
02049
02050 if ((kTypeVoltageControl == m_type) ||
02051 (kTypeVoltageAndToneControl == m_type))
02052 {
02053 voltage = (IsHorizontal(tuning) ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13);
02054 }
02055
02056 return voltage;
02057 }
02058
02059 bool DiSEqCDevLNB::Load(void)
02060 {
02061
02062 MSqlQuery query(MSqlQuery::InitCon());
02063 query.prepare(
02064 "SELECT subtype, lnb_lof_switch, "
02065 " lnb_lof_hi, lnb_lof_lo, "
02066 " lnb_pol_inv, cmd_repeat "
02067 "FROM diseqc_tree "
02068 "WHERE diseqcid = :DEVID");
02069 query.bindValue(":DEVID", GetDeviceID());
02070
02071 if (!query.exec() || !query.isActive())
02072 {
02073 MythContext::DBError("DiSEqCDevLNB::Load", query);
02074 return false;
02075 }
02076 else if (query.next())
02077 {
02078 m_type = LNBTypeFromString(query.value(0).toString());
02079 m_lof_switch = query.value(1).toInt();
02080 m_lof_hi = query.value(2).toInt();
02081 m_lof_lo = query.value(3).toInt();
02082 m_pol_inv = query.value(4).toUInt();
02083 m_repeat = query.value(5).toUInt();
02084 }
02085
02086 return true;
02087 }
02088
02089 bool DiSEqCDevLNB::Store(void) const
02090 {
02091 QString type = LNBTypeToString(m_type);
02092 MSqlQuery query(MSqlQuery::InitCon());
02093
02094
02095 if (IsRealDeviceID())
02096 {
02097 query.prepare(
02098 "UPDATE diseqc_tree "
02099 "SET parentid = :PARENT, "
02100 " ordinal = :ORDINAL, "
02101 " type = 'lnb', "
02102 " description = :DESC, "
02103 " subtype = :TYPE, "
02104 " lnb_lof_switch = :LOFSW, "
02105 " lnb_lof_lo = :LOFLO, "
02106 " lnb_lof_hi = :LOFHI, "
02107 " lnb_pol_inv = :POLINV, "
02108 " cmd_repeat = :REPEAT "
02109 "WHERE diseqcid = :DEVID");
02110 }
02111 else
02112 {
02113 query.prepare(
02114 "INSERT INTO diseqc_tree"
02115 " ( parentid, ordinal, type, "
02116 " description, subtype, lnb_lof_switch, "
02117 " lnb_lof_lo, lnb_lof_hi, lnb_pol_inv, "
02118 " cmd_repeat ) "
02119 "VALUES "
02120 " (:PARENT, :ORDINAL, 'lnb', "
02121 " :DESC, :TYPE, :LOFSW, "
02122 " :LOFLO, :LOFHI, :POLINV, "
02123 " :REPEAT ) ");
02124 }
02125
02126 if (m_parent)
02127 query.bindValue(":PARENT", m_parent->GetDeviceID());
02128
02129 query.bindValue(":ORDINAL", m_ordinal);
02130 query.bindValue(":DESC", GetDescription());
02131 query.bindValue(":TYPE", type);
02132 query.bindValue(":LOFSW", m_lof_switch);
02133 query.bindValue(":LOFLO", m_lof_lo);
02134 query.bindValue(":LOFHI", m_lof_hi);
02135 query.bindValue(":POLINV", m_pol_inv);
02136 query.bindValue(":REPEAT", m_repeat);
02137 query.bindValue(":DEVID", GetDeviceID());
02138
02139
02140 if (!query.exec())
02141 {
02142 MythContext::DBError("DiSEqCDevLNB::Store", query);
02143 return false;
02144 }
02145
02146
02147 if (!IsRealDeviceID())
02148 SetDeviceID(query.lastInsertId().toUInt());
02149
02150 return true;
02151 }
02152
02159 bool DiSEqCDevLNB::IsHighBand(const DTVMultiplex &tuning) const
02160 {
02161 switch (m_type)
02162 {
02163 case kTypeVoltageAndToneControl:
02164 return (tuning.frequency > m_lof_switch);
02165 case kTypeBandstacked:
02166 return IsHorizontal(tuning);
02167 default:
02168 return false;
02169 }
02170
02171 return false;
02172 }
02173
02179 bool DiSEqCDevLNB::IsHorizontal(const DTVMultiplex &tuning) const
02180 {
02181 QString pol = tuning.polarity.toString().lower();
02182 return (pol == "h" || pol == "l") ^ IsPolarityInverted();
02183 }
02184
02193 uint32_t DiSEqCDevLNB::GetIntermediateFrequency(
02194 const DiSEqCDevSettings&, const DTVMultiplex &tuning) const
02195 {
02196 (void) tuning;
02197
02198 uint64_t abs_freq = tuning.frequency;
02199 uint lof = (IsHighBand(tuning)) ? m_lof_hi : m_lof_lo;
02200
02201 return (lof > abs_freq) ? (lof - abs_freq) : (abs_freq - lof);
02202 }