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