| 1 | /* |
| 2 | * \file dvbdevtree.cpp |
| 3 | * \brief DVB-S Device Tree Control Classes. |
| 4 | * \author Copyright (C) 2006, Yeasah Pell |
| 5 | */ |
| 6 | |
| 7 | #include <sys/time.h> |
| 8 | #include <string.h> |
| 9 | #include <cmath> |
| 10 | #include "mythcontext.h" |
| 11 | #include "mythdbcon.h" |
| 12 | #include "dvbtypes.h" |
| 13 | #include "dvbdevtree.h" |
| 14 | |
| 15 | #define LOC QString("DVBDevTree: ") |
| 16 | #define LOC_ERR QString("DVBDevTree: ") |
| 17 | |
| 18 | //////////////////////////////////////// DVBDevSettings |
| 19 | |
| 20 | DVBDevSettings::DVBDevSettings() |
| 21 | : m_input_id((unsigned int)-1) |
| 22 | { |
| 23 | } |
| 24 | |
| 25 | bool DVBDevSettings::Load(unsigned int card_input_id) |
| 26 | { |
| 27 | if(card_input_id != m_input_id) |
| 28 | { |
| 29 | m_config.clear(); |
| 30 | |
| 31 | // load settings from DB |
| 32 | MSqlQuery query(MSqlQuery::InitCon()); |
| 33 | query.prepare("SELECT dtv_dev_id, value " |
| 34 | "FROM dtv_device_config " |
| 35 | "WHERE cardinputid = :INPUTID"); |
| 36 | query.bindValue(":INPUTID", card_input_id); |
| 37 | if(query.exec() && query.isActive()) |
| 38 | while(query.next()) |
| 39 | m_config[query.value(0).toInt()] = query.value(1).toDouble(); |
| 40 | |
| 41 | m_input_id = card_input_id; |
| 42 | } |
| 43 | |
| 44 | return true; |
| 45 | } |
| 46 | |
| 47 | bool DVBDevSettings::Store(unsigned int card_input_id) const |
| 48 | { |
| 49 | { |
| 50 | // clear out previous settings |
| 51 | MSqlQuery query(MSqlQuery::InitCon()); |
| 52 | query.prepare("DELETE from dtv_device_config" |
| 53 | " WHERE cardinputid = :INPUTID"); |
| 54 | query.bindValue(":INPUTID", card_input_id); |
| 55 | if(!query.exec()) |
| 56 | return false; |
| 57 | } |
| 58 | |
| 59 | { |
| 60 | // insert new settings |
| 61 | MSqlQuery query(MSqlQuery::InitCon()); |
| 62 | query.prepare("INSERT INTO dtv_device_config" |
| 63 | " (cardinputid, dtv_dev_id, value) VALUES" |
| 64 | " (:INPUTID, :DEV_ID, :VALUE)"); |
| 65 | for(CONFIG::const_iterator i = m_config.begin(); i != m_config.end(); i++) |
| 66 | { |
| 67 | query.bindValue(":INPUTID", card_input_id); |
| 68 | query.bindValue(":DEV_ID", i->first); |
| 69 | query.bindValue(":VALUE", i->second); |
| 70 | if(!query.exec()) |
| 71 | return false; |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | return true; |
| 76 | } |
| 77 | |
| 78 | double DVBDevSettings::GetValue(int dtv_dev_id) const |
| 79 | { |
| 80 | double ret = 0.0; |
| 81 | CONFIG::const_iterator cfg = m_config.find(dtv_dev_id); |
| 82 | if(cfg != m_config.end()) |
| 83 | ret = cfg->second; |
| 84 | return ret; |
| 85 | } |
| 86 | |
| 87 | void DVBDevSettings::SetValue(int dtv_dev_id, double value) |
| 88 | { |
| 89 | m_config[dtv_dev_id] = value; |
| 90 | m_input_id = (unsigned int)-1; |
| 91 | } |
| 92 | |
| 93 | //////////////////////////////////////// DVBDev |
| 94 | |
| 95 | DVBDevTree* DVBDev::FindTree(unsigned int card_id) |
| 96 | { |
| 97 | return m_trees.FindTree(card_id); |
| 98 | } |
| 99 | |
| 100 | void DVBDev::InvalidateTrees() |
| 101 | { |
| 102 | m_trees.InvalidateTrees(); |
| 103 | } |
| 104 | |
| 105 | DVBDevTrees DVBDev::m_trees; |
| 106 | |
| 107 | //////////////////////////////////////// DVBDevTrees |
| 108 | |
| 109 | DVBDevTrees::~DVBDevTrees() |
| 110 | { |
| 111 | InvalidateTrees(); |
| 112 | } |
| 113 | |
| 114 | DVBDevTree* DVBDevTrees::FindTree(unsigned int card_id) |
| 115 | { |
| 116 | QMutexLocker lock(&m_trees_lock); |
| 117 | |
| 118 | DVBDevTree* tree = NULL; |
| 119 | TREES::iterator i = m_trees.find(card_id); |
| 120 | if(i == m_trees.end()) |
| 121 | { |
| 122 | tree = new DVBDevTree; |
| 123 | tree->Load(card_id); |
| 124 | m_trees.insert(std::make_pair(card_id, tree)); |
| 125 | } |
| 126 | else |
| 127 | tree = i->second; |
| 128 | return tree; |
| 129 | } |
| 130 | |
| 131 | void DVBDevTrees::InvalidateTrees() |
| 132 | { |
| 133 | QMutexLocker lock(&m_trees_lock); |
| 134 | for(TREES::iterator i = m_trees.begin(); i != m_trees.end(); i++) |
| 135 | delete i->second; |
| 136 | m_trees.clear(); |
| 137 | } |
| 138 | |
| 139 | //////////////////////////////////////// DVBDevTree |
| 140 | |
| 141 | DVBDevTree::DVBDevTree() |
| 142 | : m_fd_frontend(-1), m_root(NULL), m_next_cnt(0) |
| 143 | { |
| 144 | Reset(); |
| 145 | } |
| 146 | |
| 147 | DVBDevTree::~DVBDevTree() |
| 148 | { |
| 149 | delete m_root; |
| 150 | } |
| 151 | |
| 152 | bool DVBDevTree::Load(unsigned int card_id) |
| 153 | { |
| 154 | // clear children |
| 155 | delete m_root; |
| 156 | m_delete.clear(); |
| 157 | m_root = NULL; |
| 158 | |
| 159 | // lookup configuration for this card |
| 160 | MSqlQuery query(MSqlQuery::InitCon()); |
| 161 | query.prepare("SELECT dtv_dev_id FROM capturecard " |
| 162 | "WHERE cardid = :CARDID"); |
| 163 | query.bindValue(":CARDID", card_id); |
| 164 | |
| 165 | if(query.exec() && query.next()) |
| 166 | m_root = DVBDevDevice::CreateById(*this, query.value(0).toInt()); |
| 167 | else |
| 168 | VERBOSE(VB_IMPORTANT, LOC_ERR + |
| 169 | QString("No device tree for cardid %1").arg(card_id)); |
| 170 | |
| 171 | return m_root != NULL; |
| 172 | } |
| 173 | |
| 174 | bool DVBDevTree::Store(unsigned int card_id) |
| 175 | { |
| 176 | // apply pending node deletions |
| 177 | if(!m_delete.empty()) |
| 178 | { |
| 179 | MSqlQuery query(MSqlQuery::InitCon()); |
| 180 | query.prepare("DELETE FROM dtv_device_tree WHERE dtv_dev_id = :DEVID"); |
| 181 | MSqlQuery squery(MSqlQuery::InitCon()); |
| 182 | squery.prepare("DELETE FROM dtv_device_config WHERE dtv_dev_id = :DEVID"); |
| 183 | for(list<unsigned int>::const_iterator i = m_delete.begin(); i != m_delete.end(); i++) |
| 184 | { |
| 185 | query.bindValue(":DEVID", *i); |
| 186 | query.exec(); |
| 187 | squery.bindValue(":DEVID", *i); |
| 188 | squery.exec(); |
| 189 | } |
| 190 | m_delete.clear(); |
| 191 | } |
| 192 | |
| 193 | // store changed and new nodes |
| 194 | bool success = true; |
| 195 | if(m_root) |
| 196 | success = m_root->Store(); |
| 197 | MSqlQuery query(MSqlQuery::InitCon()); |
| 198 | query.prepare("UPDATE capturecard" |
| 199 | " SET dtv_dev_id = :DEVID" |
| 200 | " WHERE cardid = :CARDID"); |
| 201 | if(m_root) |
| 202 | query.bindValue(":DEVID", m_root->DeviceID()); |
| 203 | query.bindValue(":CARDID", card_id); |
| 204 | return success && query.exec(); |
| 205 | } |
| 206 | |
| 207 | bool DVBDevTree::SetTone(bool on) |
| 208 | { |
| 209 | bool success = false; |
| 210 | for(unsigned int retry = 0; !success && retry < TIMEOUT_RETRIES; retry++) |
| 211 | { |
| 212 | if (ioctl(m_fd_frontend, FE_SET_TONE, |
| 213 | on ? SEC_TONE_ON : SEC_TONE_OFF) == 0) |
| 214 | success = true; |
| 215 | else |
| 216 | usleep(DISEQC_SHORT_WAIT); |
| 217 | } |
| 218 | if(!success) |
| 219 | VERBOSE(VB_IMPORTANT, LOC_ERR + "FE_SET_TONE failed" + ENO); |
| 220 | return success; |
| 221 | } |
| 222 | |
| 223 | bool DVBDevTree::MiniDiseqc(fe_sec_mini_cmd cmd) |
| 224 | { |
| 225 | bool success = false; |
| 226 | for(unsigned int retry = 0; !success && retry < TIMEOUT_RETRIES; retry++) |
| 227 | { |
| 228 | if (ioctl(m_fd_frontend, FE_DISEQC_SEND_BURST, cmd) == 0) |
| 229 | success = true; |
| 230 | else |
| 231 | usleep(DISEQC_SHORT_WAIT); |
| 232 | } |
| 233 | if(!success) |
| 234 | VERBOSE(VB_IMPORTANT, LOC_ERR + "FE_DISEQC_SEND_BURST failed" + ENO); |
| 235 | return success; |
| 236 | } |
| 237 | |
| 238 | bool DVBDevTree::SendDiseqc(const dvb_diseqc_master_cmd& cmd) |
| 239 | { |
| 240 | bool success = false; |
| 241 | for(unsigned int retry = 0; !success && retry < TIMEOUT_RETRIES; retry++) |
| 242 | { |
| 243 | if (ioctl(m_fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd) == 0) |
| 244 | success = true; |
| 245 | else |
| 246 | usleep(DISEQC_SHORT_WAIT); |
| 247 | } |
| 248 | if(!success) |
| 249 | VERBOSE(VB_IMPORTANT, LOC_ERR + |
| 250 | "FE_DISEQC_SEND_MASTER_CMD failed" + ENO); |
| 251 | return success; |
| 252 | } |
| 253 | |
| 254 | bool DVBDevTree::Execute(const DVBDevSettings& settings, |
| 255 | const DVBTuning& tuning) |
| 256 | { |
| 257 | if(m_root) |
| 258 | { |
| 259 | // apply any voltage change |
| 260 | ApplyVoltage(settings, tuning); |
| 261 | |
| 262 | // turn off tone burst first if commands need to be sent |
| 263 | if(m_root->NeedsCommand(settings)) |
| 264 | { |
| 265 | SetTone(false); |
| 266 | usleep(DISEQC_SHORT_WAIT); |
| 267 | } |
| 268 | |
| 269 | return m_root->Execute(settings, tuning); |
| 270 | } |
| 271 | else |
| 272 | { |
| 273 | VERBOSE(VB_IMPORTANT, LOC_ERR + "No root device tree node!"); |
| 274 | return false; |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | void DVBDevTree::Reset() |
| 279 | { |
| 280 | if(m_root) |
| 281 | m_root->Reset(); |
| 282 | m_last_voltage = (fe_sec_voltage)-1; |
| 283 | } |
| 284 | |
| 285 | DVBDevRotor* DVBDevTree::FindRotor(const DVBDevSettings& settings, |
| 286 | unsigned int index) |
| 287 | { |
| 288 | DVBDevRotor* rotor = NULL; |
| 289 | DVBDevDevice* node = m_root; |
| 290 | unsigned int count = 0; |
| 291 | while(node) |
| 292 | { |
| 293 | rotor = dynamic_cast<DVBDevRotor*>(node); |
| 294 | if(rotor && ++count > index) |
| 295 | break; |
| 296 | node = node->SelectedChild(settings); |
| 297 | } |
| 298 | return rotor; |
| 299 | } |
| 300 | |
| 301 | DVBDevLnb* DVBDevTree::FindLNB(const DVBDevSettings& settings) |
| 302 | { |
| 303 | DVBDevLnb* lnb = NULL; |
| 304 | DVBDevDevice* node = m_root; |
| 305 | while(node) |
| 306 | { |
| 307 | lnb = dynamic_cast<DVBDevLnb*>(node); |
| 308 | if(lnb) |
| 309 | break; |
| 310 | node = node->SelectedChild(settings); |
| 311 | } |
| 312 | return lnb; |
| 313 | } |
| 314 | |
| 315 | DVBDevDevice* DVBDevTree::FindDevice(int dev_id) |
| 316 | { |
| 317 | DVBDevDevice* dev = NULL; |
| 318 | if(m_root) |
| 319 | dev = m_root->FindDevice(dev_id); |
| 320 | return dev; |
| 321 | } |
| 322 | |
| 323 | void DVBDevTree::SetRoot(DVBDevDevice* root) |
| 324 | { |
| 325 | delete m_root; |
| 326 | m_root = root; |
| 327 | } |
| 328 | |
| 329 | bool DVBDevTree::SendCommand(unsigned int adr, |
| 330 | unsigned int cmd, |
| 331 | unsigned int repeats, |
| 332 | unsigned int data_len, |
| 333 | unsigned char* data) |
| 334 | { |
| 335 | // check payload validity |
| 336 | if(data_len > 3 || (data_len > 0 && data == NULL)) |
| 337 | { |
| 338 | VERBOSE(VB_IMPORTANT, LOC_ERR + "Bad DiSEqC command"); |
| 339 | return false; |
| 340 | } |
| 341 | |
| 342 | // prepare command |
| 343 | dvb_diseqc_master_cmd mcmd; |
| 344 | mcmd.msg[0] = DISEQC_FRM; |
| 345 | mcmd.msg[1] = adr; |
| 346 | mcmd.msg[2] = cmd; |
| 347 | mcmd.msg_len = data_len + 3; |
| 348 | if(data_len > 0) |
| 349 | memcpy(mcmd.msg+3, data, data_len); |
| 350 | |
| 351 | // diagnostic |
| 352 | QString cmdstr; |
| 353 | for(unsigned int byte = 0; byte < mcmd.msg_len; byte++) |
| 354 | cmdstr += QString("%1 ").arg(mcmd.msg[byte], 2, 16); |
| 355 | VERBOSE(VB_CHANNEL, LOC + "Sending DiSEqC Command: " + cmdstr); |
| 356 | |
| 357 | // send the command |
| 358 | for(unsigned int i = 0; i <= repeats; i++) |
| 359 | { |
| 360 | if (!SendDiseqc(mcmd)) |
| 361 | { |
| 362 | VERBOSE(VB_IMPORTANT, LOC_ERR + "DiSEqC command failed" + ENO); |
| 363 | return false; |
| 364 | } |
| 365 | mcmd.msg[0] |= DISEQC_FRM_REPEAT; |
| 366 | usleep(DISEQC_SHORT_WAIT); |
| 367 | } |
| 368 | |
| 369 | return true; |
| 370 | } |
| 371 | |
| 372 | bool DVBDevTree::ResetDiseqc(bool hard_reset) |
| 373 | { |
| 374 | Reset(); |
| 375 | |
| 376 | VERBOSE(VB_CHANNEL, LOC + "Resetting DiSEqC Bus"); |
| 377 | |
| 378 | // issue a global reset command |
| 379 | if(!SendCommand(DISEQC_ADR_ALL, DISEQC_CMD_RESET)) |
| 380 | { |
| 381 | VERBOSE(VB_IMPORTANT, LOC_ERR + |
| 382 | "DiSEqC reset failed" + ENO); |
| 383 | return false; |
| 384 | } |
| 385 | usleep(DISEQC_LONG_WAIT); |
| 386 | |
| 387 | // power cycle the bus if requested |
| 388 | if(hard_reset) |
| 389 | { |
| 390 | VERBOSE(VB_CHANNEL, LOC + "Power-cycling DiSEqC Bus"); |
| 391 | SetVoltage(SEC_VOLTAGE_OFF); |
| 392 | usleep(DISEQC_LONG_WAIT); |
| 393 | SetVoltage(SEC_VOLTAGE_18); |
| 394 | usleep(DISEQC_LONG_WAIT); |
| 395 | } |
| 396 | |
| 397 | return true; |
| 398 | } |
| 399 | |
| 400 | void DVBDevTree::Open(int fd_frontend) |
| 401 | { |
| 402 | m_fd_frontend = fd_frontend; |
| 403 | ResetDiseqc(true); |
| 404 | } |
| 405 | |
| 406 | bool DVBDevTree::SetVoltage(fe_sec_voltage voltage) |
| 407 | { |
| 408 | bool success = true; |
| 409 | if(voltage != m_last_voltage) |
| 410 | { |
| 411 | int volts = 0; |
| 412 | if(voltage == SEC_VOLTAGE_18) |
| 413 | volts = 18; |
| 414 | else if(voltage == SEC_VOLTAGE_13) |
| 415 | volts = 13; |
| 416 | VERBOSE(VB_CHANNEL, LOC + |
| 417 | QString("Changing LNB voltage to %1V").arg(volts)); |
| 418 | |
| 419 | success = false; |
| 420 | for(unsigned int retry = 0; !success && retry < TIMEOUT_RETRIES; retry++) |
| 421 | { |
| 422 | if (ioctl(m_fd_frontend, FE_SET_VOLTAGE, voltage) == 0) |
| 423 | success = true; |
| 424 | else |
| 425 | usleep(DISEQC_SHORT_WAIT); |
| 426 | } |
| 427 | |
| 428 | if(!success) |
| 429 | VERBOSE(VB_IMPORTANT, LOC_ERR + "FE_SET_VOLTAGE failed" + ENO); |
| 430 | else |
| 431 | m_last_voltage = voltage; |
| 432 | } |
| 433 | |
| 434 | return success; |
| 435 | } |
| 436 | |
| 437 | bool DVBDevTree::ApplyVoltage(const DVBDevSettings& settings, |
| 438 | const DVBTuning& tuning) |
| 439 | { |
| 440 | fe_sec_voltage voltage = SEC_VOLTAGE_18; |
| 441 | if(m_root) |
| 442 | voltage = m_root->GetVoltage(settings, tuning); |
| 443 | return SetVoltage(voltage); |
| 444 | } |
| 445 | |
| 446 | //////////////////////////////////////// DVBDevDevice |
| 447 | |
| 448 | DVBDevDevice::DVBDevDevice(DVBDevTree& tree, int dtv_dev_id) |
| 449 | : m_dtv_dev_id(dtv_dev_id), m_tree(tree), m_parent(NULL), m_ordinal(0), |
| 450 | m_repeat(0) |
| 451 | { |
| 452 | } |
| 453 | |
| 454 | DVBDevDevice::~DVBDevDevice() |
| 455 | { |
| 456 | if(DeviceID() >= 0) |
| 457 | m_tree.AddDeferredDelete(DeviceID()); |
| 458 | } |
| 459 | |
| 460 | DVBDevDevice* DVBDevDevice::FindDevice(int dev_id) |
| 461 | { |
| 462 | DVBDevDevice* dev = NULL; |
| 463 | |
| 464 | if(m_dtv_dev_id == dev_id) |
| 465 | dev = this; |
| 466 | |
| 467 | unsigned int num_children = NumChildren(); |
| 468 | for(unsigned int ch = 0; !dev && ch < num_children; ch++) |
| 469 | { |
| 470 | DVBDevDevice* child = GetChild(ch); |
| 471 | if(child) |
| 472 | { |
| 473 | if(child->DeviceID() == dev_id) |
| 474 | dev = child; |
| 475 | else |
| 476 | dev = child->FindDevice(dev_id); |
| 477 | } |
| 478 | } |
| 479 | return dev; |
| 480 | } |
| 481 | |
| 482 | DVBDevDevice* DVBDevDevice::CreateById(DVBDevTree& tree, |
| 483 | int dtv_dev_id) |
| 484 | { |
| 485 | DVBDevDevice* node = NULL; |
| 486 | |
| 487 | // load settings from DB |
| 488 | MSqlQuery query(MSqlQuery::InitCon()); |
| 489 | query.prepare("SELECT dtv_dev_type, dtv_dev_descr" |
| 490 | " FROM dtv_device_tree" |
| 491 | " WHERE dtv_dev_id = :DTV_DEV_ID"); |
| 492 | query.bindValue(":DTV_DEV_ID", dtv_dev_id); |
| 493 | |
| 494 | if(query.exec() && query.next()) |
| 495 | { |
| 496 | dvbdev_t type = DevTypeFromString(query.value(0).toString()); |
| 497 | node = CreateByType(tree, type, dtv_dev_id); |
| 498 | |
| 499 | QString descr = query.value(1).toString(); |
| 500 | if(node) |
| 501 | { |
| 502 | node->SetDescription(descr); |
| 503 | node->Load(); |
| 504 | } |
| 505 | } |
| 506 | |
| 507 | return node; |
| 508 | } |
| 509 | |
| 510 | DVBDevDevice* DVBDevDevice::CreateByType(DVBDevTree& tree, |
| 511 | dvbdev_t type, |
| 512 | int dev_id) |
| 513 | { |
| 514 | if(dev_id == -1) |
| 515 | dev_id = tree.NextFakeID(); |
| 516 | |
| 517 | DVBDevDevice* node = NULL; |
| 518 | switch(type) |
| 519 | { |
| 520 | case DVBDEV_SWITCH: |
| 521 | node = new DVBDevSwitch(tree, dev_id); |
| 522 | if(node) |
| 523 | node->SetDescription("Switch"); |
| 524 | break; |
| 525 | case DVBDEV_ROTOR: |
| 526 | node = new DVBDevRotor(tree, dev_id); |
| 527 | if(node) |
| 528 | node->SetDescription("Rotor"); |
| 529 | break; |
| 530 | case DVBDEV_LNB: |
| 531 | node = new DVBDevLnb(tree, dev_id); |
| 532 | if(node) |
| 533 | node->SetDescription("LNB"); |
| 534 | break; |
| 535 | default: |
| 536 | break; |
| 537 | } |
| 538 | if(node) |
| 539 | node->SetDeviceType(type); |
| 540 | return node; |
| 541 | } |
| 542 | |
| 543 | //////////////////////////////////////// DVBDevSwitch |
| 544 | |
| 545 | DVBDevSwitch::DVBDevSwitch(DVBDevTree& tree, |
| 546 | int dtv_dev_id) |
| 547 | : DVBDevDevice(tree, dtv_dev_id), |
| 548 | m_type(SWITCH_TONE), m_num_ports(2) |
| 549 | { |
| 550 | m_children.resize(m_num_ports); |
| 551 | for(unsigned int i = 0; i < m_num_ports; i++) |
| 552 | m_children[i] = NULL; |
| 553 | Reset(); |
| 554 | } |
| 555 | |
| 556 | DVBDevSwitch::~DVBDevSwitch() |
| 557 | { |
| 558 | for(CHILDREN::iterator i = m_children.begin(); i != m_children.end(); i++) |
| 559 | delete *i; |
| 560 | } |
| 561 | |
| 562 | bool DVBDevSwitch::Execute(const DVBDevSettings& settings, |
| 563 | const DVBTuning& tuning) |
| 564 | { |
| 565 | bool success = true; |
| 566 | |
| 567 | // sanity check switch position |
| 568 | unsigned int pos; |
| 569 | if(!GetPosition(settings, pos)) |
| 570 | return false; |
| 571 | |
| 572 | // determine if switch command needs to be sent based on last pos |
| 573 | if(m_last_pos != pos) |
| 574 | { |
| 575 | // perform switching |
| 576 | switch(m_type) |
| 577 | { |
| 578 | case SWITCH_TONE: |
| 579 | success = ExecuteTone(settings, tuning, pos); |
| 580 | break; |
| 581 | case SWITCH_DISEQC_COMMITTED: |
| 582 | case SWITCH_DISEQC_UNCOMMITTED: |
| 583 | success = ExecuteDiseqc(settings, tuning, pos); |
| 584 | break; |
| 585 | case SWITCH_LEGACY_SW21: |
| 586 | case SWITCH_LEGACY_SW42: |
| 587 | case SWITCH_LEGACY_SW64: |
| 588 | success = ExecuteLegacy(settings, tuning, pos); |
| 589 | break; |
| 590 | default: |
| 591 | success = false; |
| 592 | VERBOSE(VB_IMPORTANT, LOC_ERR + |
| 593 | QString("Unknown switch type (%1)") |
| 594 | .arg((unsigned int)m_type)); |
| 595 | break; |
| 596 | } |
| 597 | |
| 598 | // if a child device will be sending a diseqc command, wait 100ms |
| 599 | if(m_children[pos]->NeedsCommand(settings)) |
| 600 | { |
| 601 | VERBOSE(VB_CHANNEL, LOC + "Waiting for switch"); |
| 602 | usleep(DISEQC_LONG_WAIT); |
| 603 | } |
| 604 | |
| 605 | m_last_pos = pos; |
| 606 | } |
| 607 | |
| 608 | // chain to child if the switch was successful |
| 609 | if(success) |
| 610 | success = m_children[pos]->Execute(settings, tuning); |
| 611 | |
| 612 | return success; |
| 613 | } |
| 614 | |
| 615 | void DVBDevSwitch::Reset() |
| 616 | { |
| 617 | m_last_pos = (unsigned int)-1; |
| 618 | for(CHILDREN::iterator i = m_children.begin(); i != m_children.end(); i++) |
| 619 | if(*i) |
| 620 | (*i)->Reset(); |
| 621 | } |
| 622 | |
| 623 | bool DVBDevSwitch::NeedsCommand(const DVBDevSettings& settings) const |
| 624 | { |
| 625 | // sanity check switch position |
| 626 | unsigned int pos; |
| 627 | if(!GetPosition(settings, pos)) |
| 628 | return false; |
| 629 | |
| 630 | // if position is changing, a command is definitely needed |
| 631 | if(pos != m_last_pos) |
| 632 | return true; |
| 633 | |
| 634 | // otherwise, the child that will be selected may need a command |
| 635 | else |
| 636 | return m_children[pos]->NeedsCommand(settings); |
| 637 | } |
| 638 | |
| 639 | DVBDevDevice* DVBDevSwitch::SelectedChild(const DVBDevSettings& settings) const |
| 640 | { |
| 641 | DVBDevDevice* child = NULL; |
| 642 | unsigned int pos; |
| 643 | if(GetPosition(settings, pos)) |
| 644 | child = m_children[pos]; |
| 645 | return child; |
| 646 | } |
| 647 | |
| 648 | unsigned int DVBDevSwitch::NumChildren() const |
| 649 | { |
| 650 | return m_num_ports; |
| 651 | } |
| 652 | |
| 653 | DVBDevDevice* DVBDevSwitch::GetChild(unsigned int ordinal) |
| 654 | { |
| 655 | if(ordinal < m_children.size()) |
| 656 | return m_children[ordinal]; |
| 657 | else |
| 658 | return NULL; |
| 659 | } |
| 660 | |
| 661 | bool DVBDevSwitch::SetChild(unsigned int ordinal, DVBDevDevice* device) |
| 662 | { |
| 663 | if(ordinal < m_children.size()) |
| 664 | { |
| 665 | delete m_children[ordinal]; |
| 666 | m_children[ordinal] = device; |
| 667 | if(device) |
| 668 | { |
| 669 | device->SetOrdinal(ordinal); |
| 670 | device->SetParent(this); |
| 671 | } |
| 672 | return true; |
| 673 | } |
| 674 | return false; |
| 675 | } |
| 676 | |
| 677 | fe_sec_voltage DVBDevSwitch::GetVoltage(const DVBDevSettings& settings, |
| 678 | const DVBTuning& tuning) const |
| 679 | { |
| 680 | fe_sec_voltage voltage = SEC_VOLTAGE_18; |
| 681 | DVBDevDevice* child = SelectedChild(settings); |
| 682 | if(child) |
| 683 | voltage = child->GetVoltage(settings, tuning); |
| 684 | return voltage; |
| 685 | } |
| 686 | |
| 687 | bool DVBDevSwitch::Load() |
| 688 | { |
| 689 | // clear old children |
| 690 | for(CHILDREN::iterator i = m_children.begin(); i != m_children.end(); i++) |
| 691 | delete *i; |
| 692 | m_children.clear(); |
| 693 | |
| 694 | // populate switch parameters from db |
| 695 | { |
| 696 | MSqlQuery query(MSqlQuery::InitCon()); |
| 697 | query.prepare("SELECT dtv_dev_subtype, switch_ports" |
| 698 | " FROM dtv_device_tree" |
| 699 | " WHERE dtv_dev_id = :DTV_DEV_ID"); |
| 700 | query.bindValue(":DTV_DEV_ID", DeviceID()); |
| 701 | |
| 702 | if(query.exec() && query.next()) |
| 703 | { |
| 704 | m_type = SwitchTypeFromString(query.value(0).toString()); |
| 705 | m_num_ports = query.value(1).toInt(); |
| 706 | m_children.resize(m_num_ports); |
| 707 | for(unsigned int i=0; i < m_num_ports; i++) |
| 708 | m_children[i] = NULL; |
| 709 | } |
| 710 | } |
| 711 | |
| 712 | // load children from db |
| 713 | { |
| 714 | MSqlQuery query(MSqlQuery::InitCon()); |
| 715 | query.prepare("SELECT dtv_dev_id, ordinal FROM dtv_device_tree " |
| 716 | "WHERE parent = :DTV_DEV_ID"); |
| 717 | query.bindValue(":DTV_DEV_ID", DeviceID()); |
| 718 | if(query.exec()) |
| 719 | { |
| 720 | while(query.next()) |
| 721 | { |
| 722 | unsigned int child_dev_id = query.value(0).toInt(); |
| 723 | unsigned int ordinal = query.value(1).toInt(); |
| 724 | DVBDevDevice* child = CreateById(m_tree, child_dev_id); |
| 725 | if(!SetChild(ordinal, child)) |
| 726 | { |
| 727 | VERBOSE(VB_IMPORTANT, LOC_ERR + |
| 728 | QString("Switch port out of range (%d > %d)") |
| 729 | .arg(ordinal + 1) |
| 730 | .arg(m_num_ports)); |
| 731 | delete child; |
| 732 | } |
| 733 | } |
| 734 | } |
| 735 | } |
| 736 | |
| 737 | return true; |
| 738 | } |
| 739 | |
| 740 | bool DVBDevSwitch::Store() |
| 741 | { |
| 742 | QString type = SwitchTypeToString(m_type); |
| 743 | MSqlQuery query(MSqlQuery::InitCon()); |
| 744 | |
| 745 | // insert new or update old |
| 746 | if(m_dtv_dev_id >= 0) |
| 747 | { |
| 748 | query.prepare("UPDATE dtv_device_tree" |
| 749 | " SET parent = :PARENT," |
| 750 | " ordinal = :ORDINAL," |
| 751 | " dtv_dev_type = 'switch'," |
| 752 | " dtv_dev_descr = :DESCR," |
| 753 | " dtv_dev_subtype = :TYPE," |
| 754 | " switch_ports = :PORTS" |
| 755 | " WHERE dtv_dev_id = :DTV_DEV_ID"); |
| 756 | } |
| 757 | else |
| 758 | { |
| 759 | query.prepare("INSERT INTO dtv_device_tree" |
| 760 | " (parent, ordinal, dtv_dev_type, dtv_dev_descr," |
| 761 | " dtv_dev_subtype, switch_ports)" |
| 762 | " VALUES (:PARENT, :ORDINAL, 'switch', :DESCR," |
| 763 | " :TYPE, :PORTS)"); |
| 764 | } |
| 765 | if(m_parent) |
| 766 | query.bindValue(":PARENT", m_parent->DeviceID()); |
| 767 | query.bindValue(":ORDINAL", m_ordinal); |
| 768 | query.bindValue(":DESCR", GetDescription()); |
| 769 | query.bindValue(":TYPE", type); |
| 770 | query.bindValue(":PORTS", m_num_ports); |
| 771 | query.bindValue(":DTV_DEV_ID", DeviceID()); |
| 772 | |
| 773 | // chain to children |
| 774 | bool success = query.exec(); |
| 775 | if(success) |
| 776 | { |
| 777 | if(m_dtv_dev_id < 0) |
| 778 | m_dtv_dev_id = query.lastInsertId().toInt(); |
| 779 | for(unsigned int ch = 0; ch < m_children.size(); ch++) |
| 780 | if(m_children[ch]) |
| 781 | success = success && m_children[ch]->Store(); |
| 782 | } |
| 783 | |
| 784 | return success; |
| 785 | } |
| 786 | |
| 787 | void DVBDevSwitch::SetNumPorts(unsigned int num_ports) |
| 788 | { |
| 789 | unsigned int old_num = m_children.size(); |
| 790 | if(old_num > num_ports) |
| 791 | { |
| 792 | for(unsigned int ch = num_ports; ch < old_num; ch++) |
| 793 | delete m_children[ch]; |
| 794 | m_children.resize(num_ports); |
| 795 | } |
| 796 | else if(old_num < num_ports) |
| 797 | { |
| 798 | m_children.resize(num_ports); |
| 799 | for(unsigned int ch = old_num; ch < num_ports; ch++) |
| 800 | m_children[ch] = NULL; |
| 801 | } |
| 802 | m_num_ports = num_ports; |
| 803 | } |
| 804 | |
| 805 | bool DVBDevSwitch::ExecuteLegacy(const DVBDevSettings& settings, |
| 806 | const DVBTuning& tuning, |
| 807 | unsigned int pos) |
| 808 | { |
| 809 | #ifdef FE_DISHNETWORK_SEND_LEGACY_CMD |
| 810 | |
| 811 | static const unsigned char sw21_cmds[] = { 0x34, 0x65 }; |
| 812 | static const unsigned char sw42_cmds[] = { 0x46, 0x17 }; |
| 813 | static const unsigned char sw64_v_cmds[] = { 0x39, 0x4b, 0x0d }; |
| 814 | static const unsigned char sw64_h_cmds[] = { 0x1a, 0x5c, 0x2e }; |
| 815 | |
| 816 | const unsigned char *cmds = NULL; |
| 817 | unsigned int num_ports = 0; |
| 818 | |
| 819 | // determine polarity from lnb |
| 820 | bool horizontal = false; |
| 821 | DVBDevLnb* lnb = m_tree.FindLNB(settings); |
| 822 | if(lnb) |
| 823 | horizontal = lnb->IsHorizontal(tuning); |
| 824 | |
| 825 | // get command table for this switch |
| 826 | switch (m_type) |
| 827 | { |
| 828 | case SWITCH_LEGACY_SW21: |
| 829 | cmds = sw21_cmds; |
| 830 | num_ports = 2; |
| 831 | break; |
| 832 | case SWITCH_LEGACY_SW42: |
| 833 | cmds = sw42_cmds; |
| 834 | num_ports = 2; |
| 835 | break; |
| 836 | case SWITCH_LEGACY_SW64: |
| 837 | if (horizontal) |
| 838 | cmds = sw64_h_cmds; |
| 839 | else |
| 840 | cmds = sw64_v_cmds; |
| 841 | num_ports = 3; |
| 842 | break; |
| 843 | default: |
| 844 | return false; |
| 845 | } |
| 846 | pos %= num_ports; |
| 847 | |
| 848 | VERBOSE(VB_CHANNEL, LOC + QString("Changing to Legacy switch port %1/%2") |
| 849 | .arg(pos+1) |
| 850 | .arg(num_ports)); |
| 851 | |
| 852 | // send command |
| 853 | if (ioctl(m_tree.FrontendFD(), FE_DISHNETWORK_SEND_LEGACY_CMD, cmds[pos]) == -1) |
| 854 | { |
| 855 | VERBOSE(VB_IMPORTANT, LOC_ERR + |
| 856 | "FE_DISHNETWORK_SEND_LEGACY_CMD failed" + ENO); |
| 857 | return false; |
| 858 | } |
| 859 | |
| 860 | return true; |
| 861 | |
| 862 | #else |
| 863 | |
| 864 | VERBOSE(VB_IMPORTANT, LOC_ERR + |
| 865 | "DVB API does not support FE_DISHNETWORK_SEND_LEGACY_CMD."); |
| 866 | return false; |
| 867 | |
| 868 | #endif |
| 869 | } |
| 870 | |
| 871 | bool DVBDevSwitch::ExecuteTone(const DVBDevSettings& /*settings*/, |
| 872 | const DVBTuning& /*tuning*/, |
| 873 | unsigned int pos) |
| 874 | { |
| 875 | VERBOSE(VB_CHANNEL, LOC + QString("Changing to Tone switch port %1/2") |
| 876 | .arg(pos+1)); |
| 877 | |
| 878 | bool success = m_tree.MiniDiseqc(pos == 0 ? SEC_MINI_A : SEC_MINI_B); |
| 879 | if(!success) |
| 880 | VERBOSE(VB_IMPORTANT, LOC_ERR + "Setting Tone Switch failed." + ENO); |
| 881 | return success; |
| 882 | } |
| 883 | |
| 884 | bool DVBDevSwitch::ExecuteDiseqc(const DVBDevSettings& settings, |
| 885 | const DVBTuning& tuning, |
| 886 | unsigned int pos) |
| 887 | { |
| 888 | // retrieve LNB info |
| 889 | bool high_band = false; |
| 890 | bool horizontal = false; |
| 891 | DVBDevLnb* lnb = m_tree.FindLNB(settings); |
| 892 | if(lnb) |
| 893 | { |
| 894 | high_band = lnb->IsHighBand(tuning); |
| 895 | horizontal = lnb->IsHorizontal(tuning); |
| 896 | } |
| 897 | |
| 898 | // check number of ports |
| 899 | if(m_type == SWITCH_DISEQC_COMMITTED && m_num_ports > 4 || |
| 900 | m_type == SWITCH_DISEQC_UNCOMMITTED && m_num_ports > 16) |
| 901 | { |
| 902 | VERBOSE(VB_IMPORTANT, LOC_ERR + |
| 903 | QString("Invalid number of ports for DiSEqC 1.x Switch (%1)") |
| 904 | .arg(m_num_ports)); |
| 905 | return false; |
| 906 | } |
| 907 | |
| 908 | // build command |
| 909 | unsigned int cmd; |
| 910 | unsigned char data; |
| 911 | if(m_type == SWITCH_DISEQC_UNCOMMITTED) |
| 912 | { |
| 913 | cmd = DISEQC_CMD_WRITE_N1; |
| 914 | data = pos; |
| 915 | } |
| 916 | else |
| 917 | { |
| 918 | cmd = DISEQC_CMD_WRITE_N0; |
| 919 | data = ((pos << 2) | |
| 920 | (horizontal ? 2 : 0) | |
| 921 | (high_band ? 1 : 0)); |
| 922 | } |
| 923 | data |= 0xf0; |
| 924 | |
| 925 | VERBOSE(VB_CHANNEL, LOC + |
| 926 | QString("Changing to DiSEqC switch port %1/%2") |
| 927 | .arg(pos+1) |
| 928 | .arg(m_num_ports)); |
| 929 | |
| 930 | return m_tree.SendCommand(DISEQC_ADR_SW_ALL, |
| 931 | cmd, |
| 932 | m_repeat, |
| 933 | 1, |
| 934 | &data); |
| 935 | } |
| 936 | |
| 937 | bool DVBDevSwitch::GetPosition(const DVBDevSettings& settings, |
| 938 | unsigned int& pos) const |
| 939 | { |
| 940 | pos = (unsigned int)settings.GetValue(m_dtv_dev_id); |
| 941 | if(pos >= m_num_ports) |
| 942 | { |
| 943 | VERBOSE(VB_IMPORTANT, LOC_ERR + |
| 944 | QString("Port number out of range (%1 > %2)") |
| 945 | .arg(pos+1) |
| 946 | .arg(m_num_ports)); |
| 947 | return false; |
| 948 | } |
| 949 | if(m_children[pos] == NULL) |
| 950 | { |
| 951 | VERBOSE(VB_IMPORTANT, LOC_ERR + |
| 952 | QString("Port has no connected devices configured (%1)") |
| 953 | .arg(pos+1)); |
| 954 | return false; |
| 955 | } |
| 956 | |
| 957 | return true; |
| 958 | } |
| 959 | |
| 960 | //////////////////////////////////////// DVBDevRotor |
| 961 | |
| 962 | DVBDevRotor::DVBDevRotor(DVBDevTree& tree, |
| 963 | int dtv_dev_id) |
| 964 | : DVBDevDevice(tree, dtv_dev_id), |
| 965 | m_type(ROTOR_DISEQC_1_3), m_speed_hi(2.5), m_speed_lo(1.9), |
| 966 | m_child(NULL), m_last_position(0.0), m_last_azimuth(0.0), |
| 967 | m_move_time(0.0), m_last_pos_known(false) |
| 968 | { |
| 969 | Reset(); |
| 970 | } |
| 971 | |
| 972 | DVBDevRotor::DVBDevRotor::~DVBDevRotor() |
| 973 | { |
| 974 | delete m_child; |
| 975 | } |
| 976 | |
| 977 | bool DVBDevRotor::Execute(const DVBDevSettings& settings, |
| 978 | const DVBTuning& tuning) |
| 979 | { |
| 980 | bool success = true; |
| 981 | |
| 982 | double position = settings.GetValue(m_dtv_dev_id); |
| 983 | if(!m_last_pos_known || position != m_last_position) |
| 984 | { |
| 985 | switch(m_type) |
| 986 | { |
| 987 | case ROTOR_DISEQC_1_2: |
| 988 | success = ExecuteRotor(settings, tuning, position); |
| 989 | break; |
| 990 | case ROTOR_DISEQC_1_3: |
| 991 | success = ExecuteUSALS(settings, tuning, position); |
| 992 | break; |
| 993 | default: |
| 994 | success = false; |
| 995 | VERBOSE(VB_IMPORTANT, LOC_ERR + |
| 996 | QString("Unknown rotor type (%1)") |
| 997 | .arg((unsigned int)m_type)); |
| 998 | break; |
| 999 | } |
| 1000 | |
| 1001 | m_last_position = position; |
| 1002 | } |
| 1003 | |
| 1004 | // chain to child |
| 1005 | if(success && m_child) |
| 1006 | success = m_child->Execute(settings, tuning); |
| 1007 | |
| 1008 | return success; |
| 1009 | } |
| 1010 | |
| 1011 | void DVBDevRotor::Reset() |
| 1012 | { |
| 1013 | if(m_child) |
| 1014 | m_child->Reset(); |
| 1015 | } |
| 1016 | |
| 1017 | bool DVBDevRotor::NeedsCommand(const DVBDevSettings& settings) const |
| 1018 | { |
| 1019 | double position = settings.GetValue(m_dtv_dev_id); |
| 1020 | if(position != m_last_position) |
| 1021 | return true; |
| 1022 | else if(m_child) |
| 1023 | return m_child->NeedsCommand(settings); |
| 1024 | else |
| 1025 | return false; |
| 1026 | } |
| 1027 | |
| 1028 | DVBDevDevice* DVBDevRotor::SelectedChild(const DVBDevSettings& /*settings*/) const |
| 1029 | { |
| 1030 | return m_child; |
| 1031 | } |
| 1032 | |
| 1033 | bool DVBDevRotor::SetChild(unsigned int ordinal, DVBDevDevice* device) |
| 1034 | { |
| 1035 | if(ordinal == 0) |
| 1036 | { |
| 1037 | delete m_child; |
| 1038 | m_child = device; |
| 1039 | if(m_child) |
| 1040 | { |
| 1041 | m_child->SetOrdinal(ordinal); |
| 1042 | m_child->SetParent(this); |
| 1043 | } |
| 1044 | return true; |
| 1045 | } |
| 1046 | return false; |
| 1047 | } |
| 1048 | |
| 1049 | fe_sec_voltage DVBDevRotor::GetVoltage(const DVBDevSettings& settings, |
| 1050 | const DVBTuning& tuning) const |
| 1051 | { |
| 1052 | fe_sec_voltage voltage = SEC_VOLTAGE_18; |
| 1053 | |
| 1054 | // override voltage if the last position is known and the rotor is moving |
| 1055 | if(!(m_last_pos_known && Progress() < 1.0) && m_child) |
| 1056 | voltage = m_child->GetVoltage(settings, tuning); |
| 1057 | |
| 1058 | return voltage; |
| 1059 | } |
| 1060 | |
| 1061 | bool DVBDevRotor::Load() |
| 1062 | { |
| 1063 | // populate switch parameters from db |
| 1064 | { |
| 1065 | MSqlQuery query(MSqlQuery::InitCon()); |
| 1066 | query.prepare("SELECT dtv_dev_subtype," |
| 1067 | " rotor_hi_speed, rotor_lo_speed, rotor_positions" |
| 1068 | " FROM dtv_device_tree" |
| 1069 | " WHERE dtv_dev_id = :DTV_DEV_ID"); |
| 1070 | query.bindValue(":DTV_DEV_ID", DeviceID()); |
| 1071 | |
| 1072 | if(query.exec() && query.next()) |
| 1073 | { |
| 1074 | m_type = RotorTypeFromString(query.value(0).toString()); |
| 1075 | m_speed_hi = query.value(1).toDouble(); |
| 1076 | m_speed_lo = query.value(2).toDouble(); |
| 1077 | |
| 1078 | // form of "angle1=index1:angle2=index2:..." |
| 1079 | QString positions = query.value(3).toString(); |
| 1080 | QStringList pos = QStringList::split(":", positions); |
| 1081 | for(unsigned int i=0; i < pos.count(); i++) |
| 1082 | { |
| 1083 | QStringList eq = QStringList::split("=", pos[i]); |
| 1084 | if(eq.count() == 2) |
| 1085 | m_posmap[eq[0].toFloat()] = eq[1].toUInt(); |
| 1086 | } |
| 1087 | } |
| 1088 | } |
| 1089 | |
| 1090 | // load children from db |
| 1091 | delete m_child; |
| 1092 | m_child = NULL; |
| 1093 | { |
| 1094 | MSqlQuery query(MSqlQuery::InitCon()); |
| 1095 | query.prepare("SELECT dtv_dev_id FROM dtv_device_tree " |
| 1096 | "WHERE parent = :DTV_DEV_ID"); |
| 1097 | query.bindValue(":DTV_DEV_ID", DeviceID()); |
| 1098 | |
| 1099 | if(query.exec() && query.next()) |
| 1100 | { |
| 1101 | int child_dev_id = query.value(0).toInt(); |
| 1102 | SetChild(0, CreateById(m_tree, child_dev_id)); |
| 1103 | } |
| 1104 | } |
| 1105 | |
| 1106 | return true; |
| 1107 | } |
| 1108 | |
| 1109 | bool DVBDevRotor::Store() |
| 1110 | { |
| 1111 | QString type = RotorTypeToString(m_type); |
| 1112 | QString posmap; |
| 1113 | |
| 1114 | if(!m_posmap.empty()) |
| 1115 | { |
| 1116 | QStringList pos; |
| 1117 | for(INTPOSMAP::iterator i = m_posmap.begin(); i != m_posmap.end(); i++) |
| 1118 | pos.push_back(QString("%1=%2").arg(i->first).arg(i->second)); |
| 1119 | posmap = pos.join(":"); |
| 1120 | } |
| 1121 | |
| 1122 | MSqlQuery query(MSqlQuery::InitCon()); |
| 1123 | |
| 1124 | // insert new or update old |
| 1125 | if(m_dtv_dev_id >= 0) |
| 1126 | { |
| 1127 | query.prepare("UPDATE dtv_device_tree" |
| 1128 | " SET parent = :PARENT," |
| 1129 | " ordinal = :ORDINAL," |
| 1130 | " dtv_dev_type = 'rotor'," |
| 1131 | " dtv_dev_descr = :DESCR," |
| 1132 | " dtv_dev_subtype = :TYPE," |
| 1133 | " rotor_hi_speed = :HISPEED," |
| 1134 | " rotor_lo_speed = :LOSPEED," |
| 1135 | " rotor_positions = :POSMAP" |
| 1136 | " WHERE dtv_dev_id = :DTV_DEV_ID"); |
| 1137 | } |
| 1138 | else |
| 1139 | { |
| 1140 | query.prepare("INSERT INTO dtv_device_tree" |
| 1141 | " (parent, ordinal, dtv_dev_type, dtv_dev_descr," |
| 1142 | " dtv_dev_subtype, rotor_hi_speed," |
| 1143 | " rotor_lo_speed, rotor_positions)" |
| 1144 | " VALUES (:PARENT, :ORDINAL, 'rotor', :DESCR," |
| 1145 | " :TYPE, :HISPEED, :LOSPEED, :POSMAP)"); |
| 1146 | } |
| 1147 | if(m_parent) |
| 1148 | query.bindValue(":PARENT", m_parent->DeviceID()); |
| 1149 | query.bindValue(":ORDINAL", m_ordinal); |
| 1150 | query.bindValue(":DESCR", GetDescription()); |
| 1151 | query.bindValue(":TYPE", type); |
| 1152 | query.bindValue(":HISPEED", m_speed_hi); |
| 1153 | query.bindValue(":LOSPEED", m_speed_lo); |
| 1154 | query.bindValue(":POSMAP", posmap); |
| 1155 | query.bindValue(":DTV_DEV_ID", DeviceID()); |
| 1156 | |
| 1157 | // chain to child |
| 1158 | bool success = query.exec(); |
| 1159 | if(success) |
| 1160 | { |
| 1161 | if(m_dtv_dev_id < 0) |
| 1162 | m_dtv_dev_id = query.lastInsertId().toInt(); |
| 1163 | if(m_child) |
| 1164 | success = m_child->Store(); |
| 1165 | } |
| 1166 | |
| 1167 | return success; |
| 1168 | } |
| 1169 | |
| 1170 | double DVBDevRotor::Progress() const |
| 1171 | { |
| 1172 | double completed = 1.0; |
| 1173 | |
| 1174 | if(m_move_time != 0.0) |
| 1175 | { |
| 1176 | // calculate duration of move |
| 1177 | double speed = |
| 1178 | (m_tree.GetVoltage() == SEC_VOLTAGE_18) ? m_speed_hi : m_speed_lo; |
| 1179 | double change = fabs(m_desired_azimuth - m_last_azimuth); |
| 1180 | double duration = change / speed; |
| 1181 | |
| 1182 | // determine completion percentage |
| 1183 | struct timeval curtime; |
| 1184 | gettimeofday(&curtime, NULL); |
| 1185 | double cursecond = curtime.tv_sec + (double)curtime.tv_usec / 1000000; |
| 1186 | double time_since_move = cursecond - m_move_time; |
| 1187 | completed = time_since_move / duration; |
| 1188 | |
| 1189 | // move completed, finish up |
| 1190 | if(completed > 1.0) |
| 1191 | completed = 1.0; |
| 1192 | } |
| 1193 | |
| 1194 | return completed; |
| 1195 | } |
| 1196 | |
| 1197 | DVBDevRotor::POSMAP DVBDevRotor::GetPosMap() const |
| 1198 | { |
| 1199 | POSMAP retposmap; |
| 1200 | INTPOSMAP::const_iterator i; |
| 1201 | for(i = m_posmap.begin(); i != m_posmap.end(); i++) |
| 1202 | retposmap.insert(make_pair(i->second, i->first)); |
| 1203 | return retposmap; |
| 1204 | } |
| 1205 | |
| 1206 | void DVBDevRotor::SetPosMap(const POSMAP& posmap) |
| 1207 | { |
| 1208 | m_posmap.clear(); |
| 1209 | POSMAP::const_iterator i; |
| 1210 | for(i = posmap.begin(); i != posmap.end(); i++) |
| 1211 | m_posmap.insert(make_pair(i->second, i->first)); |
| 1212 | } |
| 1213 | |
| 1214 | bool DVBDevRotor::ExecuteRotor(const DVBDevSettings& /*settings*/, |
| 1215 | const DVBTuning& /*tuning*/, |
| 1216 | double angle) |
| 1217 | { |
| 1218 | // determine stored position from position map |
| 1219 | INTPOSMAP::const_iterator i = m_posmap.find(angle); |
| 1220 | unsigned char index; |
| 1221 | if(i != m_posmap.end()) |
| 1222 | { |
| 1223 | index = i->second; |
| 1224 | RotorMoving(CalculateAzimuth(angle)); |
| 1225 | } |
| 1226 | else |
| 1227 | index = (unsigned int) angle; |
| 1228 | |
| 1229 | VERBOSE(VB_CHANNEL, LOC + QString("Rotor - Goto Stored Position %1") |
| 1230 | .arg(index)); |
| 1231 | |
| 1232 | return m_tree.SendCommand(DISEQC_ADR_POS_AZ, |
| 1233 | DISEQC_CMD_GOTO_POS, |
| 1234 | m_repeat, |
| 1235 | 1, |
| 1236 | &index); |
| 1237 | } |
| 1238 | |
| 1239 | bool DVBDevRotor::ExecuteUSALS(const DVBDevSettings& /*settings*/, |
| 1240 | const DVBTuning& /*tuning*/, |
| 1241 | double angle) |
| 1242 | { |
| 1243 | double azimuth = CalculateAzimuth(angle); |
| 1244 | RotorMoving(azimuth); |
| 1245 | VERBOSE(VB_CHANNEL, LOC + QString("USALS Rotor - Goto %1 (Azimuth %2)") |
| 1246 | .arg(angle) |
| 1247 | .arg(azimuth)); |
| 1248 | |
| 1249 | uint az16 = (unsigned int) (abs(azimuth) * 16.0); |
| 1250 | unsigned char cmd[2]; |
| 1251 | cmd[0] = ((azimuth > 0.0) ? 0xE0 : 0xD0) | ((az16 >> 8) & 0x0f); |
| 1252 | cmd[1] = (az16 & 0xff); |
| 1253 | |
| 1254 | return m_tree.SendCommand(DISEQC_ADR_POS_AZ, |
| 1255 | DISEQC_CMD_GOTO_X, |
| 1256 | m_repeat, |
| 1257 | 2, |
| 1258 | cmd); |
| 1259 | } |
| 1260 | |
| 1261 | #define TO_RADS (M_PI / 180.0) |
| 1262 | #define TO_DEC (180.0 / M_PI) |
| 1263 | |
| 1264 | double DVBDevRotor::CalculateAzimuth(double angle) const |
| 1265 | { |
| 1266 | // Equation lifted from VDR rotor plugin by |
| 1267 | // Thomas Bergwinkl <Thomas.Bergwinkl@t-online.de> |
| 1268 | |
| 1269 | // Earth Station Latitude and Longitude in radians |
| 1270 | double P = gContext->GetSetting("Latitude", "").toFloat() * TO_RADS; |
| 1271 | double Ue = gContext->GetSetting("Longitude", "").toFloat() * TO_RADS; |
| 1272 | |
| 1273 | // Satellite Longitude in radians |
| 1274 | double Us = angle * TO_RADS; |
| 1275 | |
| 1276 | double az = M_PI + atan( tan(Us - Ue) / sin(P) ); |
| 1277 | double x = acos( cos(Us - Ue) * cos(P) ); |
| 1278 | double el = atan( (cos(x) - 0.1513) / sin(x) ); |
| 1279 | double tmp_a = -cos(el) * sin(az); |
| 1280 | double tmp_b = (sin(el) * cos(P)) - (cos(el) * sin(P) * cos(az)); |
| 1281 | double azimuth = atan(tmp_a / tmp_b) * TO_DEC; |
| 1282 | |
| 1283 | return azimuth; |
| 1284 | } |
| 1285 | |
| 1286 | double DVBDevRotor::GetApproxAzimuth() |
| 1287 | { |
| 1288 | double approx = m_last_azimuth; |
| 1289 | |
| 1290 | if(m_move_time != 0.0) |
| 1291 | { |
| 1292 | double change = m_desired_azimuth - m_last_azimuth; |
| 1293 | double progress = Progress(); |
| 1294 | approx += (change * progress); |
| 1295 | if(progress >= 1.0) |
| 1296 | m_move_time = 0.0; |
| 1297 | } |
| 1298 | |
| 1299 | return approx; |
| 1300 | } |
| 1301 | |
| 1302 | void DVBDevRotor::RotorMoving(double azimuth) |
| 1303 | { |
| 1304 | // set last to approximate current position (or worst case if unknown) |
| 1305 | if(m_last_pos_known) |
| 1306 | m_last_azimuth = GetApproxAzimuth(); |
| 1307 | else |
| 1308 | m_last_azimuth = azimuth > 0.0 ? -75.0 : 75.0; |
| 1309 | |
| 1310 | // save time and angle of this command |
| 1311 | m_desired_azimuth = azimuth; |
| 1312 | struct timeval curtime; |
| 1313 | gettimeofday(&curtime, NULL); |
| 1314 | m_move_time = curtime.tv_sec + (double)curtime.tv_usec / 1000000; |
| 1315 | |
| 1316 | m_last_pos_known = true; |
| 1317 | } |
| 1318 | |
| 1319 | //////////////////////////////////////// |
| 1320 | |
| 1321 | DVBDevLnb::DVBDevLnb(DVBDevTree& tree, |
| 1322 | int dtv_dev_id) |
| 1323 | : DVBDevDevice(tree, dtv_dev_id), |
| 1324 | m_type(LNB_VOLTAGE_TONE), |
| 1325 | m_lof_switch(11700000), |
| 1326 | m_lof_hi(10600000), |
| 1327 | m_lof_lo(9750000) |
| 1328 | { |
| 1329 | Reset(); |
| 1330 | } |
| 1331 | |
| 1332 | bool DVBDevLnb::Execute(const DVBDevSettings& /*settings*/, |
| 1333 | const DVBTuning& tuning) |
| 1334 | { |
| 1335 | // set voltage for polarization |
| 1336 | if((m_type == LNB_VOLTAGE || m_type == LNB_VOLTAGE_TONE)) |
| 1337 | { |
| 1338 | bool horiz = IsHorizontal(tuning); |
| 1339 | fe_sec_voltage voltage = (horiz ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13); |
| 1340 | m_tree.SetVoltage(voltage); |
| 1341 | } |
| 1342 | |
| 1343 | // set tone for bandselect |
| 1344 | bool high_band = IsHighBand(tuning); |
| 1345 | if(m_type == LNB_VOLTAGE_TONE) |
| 1346 | m_tree.SetTone(high_band); |
| 1347 | |
| 1348 | return true; |
| 1349 | } |
| 1350 | |
| 1351 | void DVBDevLnb::Reset() |
| 1352 | { |
| 1353 | // i.e. diseqc lnbs would need reset |
| 1354 | } |
| 1355 | |
| 1356 | bool DVBDevLnb::NeedsCommand(const DVBDevSettings& /*settings*/) const |
| 1357 | { |
| 1358 | // i.e. diseqc lnbs would return true |
| 1359 | return false; |
| 1360 | } |
| 1361 | |
| 1362 | fe_sec_voltage DVBDevLnb::GetVoltage(const DVBDevSettings& /*settings*/, |
| 1363 | const DVBTuning& tuning) const |
| 1364 | { |
| 1365 | fe_sec_voltage voltage = SEC_VOLTAGE_18; |
| 1366 | |
| 1367 | if((m_type == LNB_VOLTAGE || m_type == LNB_VOLTAGE_TONE)) |
| 1368 | voltage = (IsHorizontal(tuning) ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13); |
| 1369 | |
| 1370 | return voltage; |
| 1371 | } |
| 1372 | |
| 1373 | bool DVBDevLnb::Load() |
| 1374 | { |
| 1375 | // populate lnb parameters from db |
| 1376 | MSqlQuery query(MSqlQuery::InitCon()); |
| 1377 | query.prepare("SELECT dtv_dev_subtype, lnb_lof_switch," |
| 1378 | " lnb_lof_hi, lnb_lof_lo" |
| 1379 | " FROM dtv_device_tree WHERE dtv_dev_id = :DTV_DEV_ID"); |
| 1380 | query.bindValue(":DTV_DEV_ID", DeviceID()); |
| 1381 | |
| 1382 | if(query.exec() && query.next()) |
| 1383 | { |
| 1384 | m_type = LnbTypeFromString(query.value(0).toString()); |
| 1385 | m_lof_switch = query.value(1).toInt(); |
| 1386 | m_lof_hi = query.value(2).toInt(); |
| 1387 | m_lof_lo = query.value(3).toInt(); |
| 1388 | } |
| 1389 | |
| 1390 | return true; |
| 1391 | } |
| 1392 | |
| 1393 | bool DVBDevLnb::Store() |
| 1394 | { |
| 1395 | QString type = LnbTypeToString(m_type); |
| 1396 | MSqlQuery query(MSqlQuery::InitCon()); |
| 1397 | |
| 1398 | // insert new or update old |
| 1399 | if(m_dtv_dev_id >= 0) |
| 1400 | { |
| 1401 | query.prepare("UPDATE dtv_device_tree" |
| 1402 | " SET parent = :PARENT," |
| 1403 | " ordinal = :ORDINAL," |
| 1404 | " dtv_dev_type = 'lnb'," |
| 1405 | " dtv_dev_descr = :DESCR," |
| 1406 | " dtv_dev_subtype = :TYPE," |
| 1407 | " lnb_lof_switch = :LOFSW," |
| 1408 | " lnb_lof_lo = :LOFLO," |
| 1409 | " lnb_lof_hi = :LOFHI" |
| 1410 | " WHERE dtv_dev_id = :DTV_DEV_ID"); |
| 1411 | } |
| 1412 | else |
| 1413 | { |
| 1414 | query.prepare("INSERT INTO dtv_device_tree" |
| 1415 | " (parent, ordinal, dtv_dev_type, dtv_dev_descr," |
| 1416 | " dtv_dev_subtype, lnb_lof_switch," |
| 1417 | " lnb_lof_lo, lnb_lof_hi)" |
| 1418 | " VALUES (:PARENT, :ORDINAL, 'lnb', :DESCR," |
| 1419 | " :TYPE, :LOFSW, :LOFLO, :LOFHI)"); |
| 1420 | } |
| 1421 | if(m_parent) |
| 1422 | query.bindValue(":PARENT", m_parent->DeviceID()); |
| 1423 | query.bindValue(":ORDINAL", m_ordinal); |
| 1424 | query.bindValue(":DESCR", GetDescription()); |
| 1425 | query.bindValue(":TYPE", type); |
| 1426 | query.bindValue(":LOFSW", m_lof_switch); |
| 1427 | query.bindValue(":LOFLO", m_lof_lo); |
| 1428 | query.bindValue(":LOFHI", m_lof_hi); |
| 1429 | query.bindValue(":DTV_DEV_ID", DeviceID()); |
| 1430 | |
| 1431 | // update dev_id |
| 1432 | bool success = query.exec(); |
| 1433 | if(success && m_dtv_dev_id < 0) |
| 1434 | m_dtv_dev_id = query.lastInsertId().toInt(); |
| 1435 | |
| 1436 | return success; |
| 1437 | } |
| 1438 | |
| 1439 | bool DVBDevLnb::IsHighBand(const DVBTuning& tuning) const |
| 1440 | { |
| 1441 | bool high_band = false; |
| 1442 | if(m_type == LNB_VOLTAGE_TONE) |
| 1443 | high_band = (tuning.params.frequency > m_lof_switch); |
| 1444 | return high_band; |
| 1445 | } |
| 1446 | |
| 1447 | bool DVBDevLnb::IsHorizontal(const DVBTuning& tuning) const |
| 1448 | { |
| 1449 | char pol = tuning.PolarityChar(); |
| 1450 | return (pol == 'h' || pol == 'l'); |
| 1451 | } |
| 1452 | |
| 1453 | __u32 DVBDevLnb::GetIF(const DVBDevSettings& /*settings*/, |
| 1454 | const DVBTuning& tuning) const |
| 1455 | { |
| 1456 | unsigned int abs_freq = tuning.params.frequency; |
| 1457 | unsigned int lof = (IsHighBand(tuning) ? m_lof_hi : m_lof_lo); |
| 1458 | return (lof > abs_freq ? lof - abs_freq : abs_freq - lof); |
| 1459 | } |
| 1460 | |
| 1461 | //////////////////////////////////////// |
| 1462 | |
| 1463 | struct TypeTable |
| 1464 | { |
| 1465 | const char* name; |
| 1466 | unsigned int value; |
| 1467 | }; |
| 1468 | |
| 1469 | static QString TableToString(unsigned int type, const TypeTable* table) |
| 1470 | { |
| 1471 | QString str; |
| 1472 | for( ; table->name != NULL; table++) |
| 1473 | { |
| 1474 | if(type == table->value) |
| 1475 | { |
| 1476 | str = table->name; |
| 1477 | break; |
| 1478 | } |
| 1479 | } |
| 1480 | return str; |
| 1481 | } |
| 1482 | |
| 1483 | static unsigned int TableFromString(const QString& type, const TypeTable*table) |
| 1484 | { |
| 1485 | for( ; table->name != NULL; table++) |
| 1486 | if(type == table->name) |
| 1487 | break; |
| 1488 | return table->value; |
| 1489 | } |
| 1490 | |
| 1491 | static TypeTable DevTypeTable[] = |
| 1492 | { |
| 1493 | { "switch", DVBDEV_SWITCH }, |
| 1494 | { "rotor", DVBDEV_ROTOR }, |
| 1495 | { "lnb", DVBDEV_LNB }, |
| 1496 | { NULL, DVBDEV_LNB } |
| 1497 | }; |
| 1498 | |
| 1499 | static TypeTable SwitchTypeTable[] = |
| 1500 | { |
| 1501 | { "legacy_sw21", SWITCH_LEGACY_SW21 }, |
| 1502 | { "legacy_sw42", SWITCH_LEGACY_SW42 }, |
| 1503 | { "legacy_sw64", SWITCH_LEGACY_SW64 }, |
| 1504 | { "tone", SWITCH_TONE }, |
| 1505 | { "diseqc", SWITCH_DISEQC_COMMITTED }, |
| 1506 | { "diseqc_uncom", SWITCH_DISEQC_UNCOMMITTED }, |
| 1507 | { NULL, SWITCH_TONE } |
| 1508 | }; |
| 1509 | |
| 1510 | static TypeTable RotorTypeTable[] = |
| 1511 | { |
| 1512 | { "diseqc_1_2", ROTOR_DISEQC_1_2 }, |
| 1513 | { "diseqc_1_3", ROTOR_DISEQC_1_3 }, |
| 1514 | { NULL, ROTOR_DISEQC_1_3 } |
| 1515 | }; |
| 1516 | |
| 1517 | static TypeTable LnbTypeTable[] = |
| 1518 | { |
| 1519 | { "fixed", LNB_FIXED }, |
| 1520 | { "voltage", LNB_VOLTAGE }, |
| 1521 | { "voltage_tone", LNB_VOLTAGE_TONE }, |
| 1522 | { NULL, LNB_VOLTAGE_TONE } |
| 1523 | }; |
| 1524 | |
| 1525 | QString DevTypeToString(dvbdev_t type) |
| 1526 | { |
| 1527 | return TableToString((unsigned int)type, DevTypeTable); |
| 1528 | } |
| 1529 | |
| 1530 | dvbdev_t DevTypeFromString(const QString& type) |
| 1531 | { |
| 1532 | return (dvbdev_t)TableFromString(type, DevTypeTable); |
| 1533 | } |
| 1534 | |
| 1535 | QString SwitchTypeToString(dvbdev_switch_t type) |
| 1536 | { |
| 1537 | return TableToString((unsigned int)type, SwitchTypeTable); |
| 1538 | } |
| 1539 | |
| 1540 | dvbdev_switch_t SwitchTypeFromString(const QString& type) |
| 1541 | { |
| 1542 | return (dvbdev_switch_t)TableFromString(type, SwitchTypeTable); |
| 1543 | } |
| 1544 | |
| 1545 | QString RotorTypeToString(dvbdev_rotor_t type) |
| 1546 | { |
| 1547 | return TableToString((unsigned int)type, RotorTypeTable); |
| 1548 | } |
| 1549 | |
| 1550 | dvbdev_rotor_t RotorTypeFromString(const QString& type) |
| 1551 | { |
| 1552 | return (dvbdev_rotor_t)TableFromString(type, RotorTypeTable); |
| 1553 | } |
| 1554 | |
| 1555 | QString LnbTypeToString(dvbdev_lnb_t type) |
| 1556 | { |
| 1557 | return TableToString((unsigned int)type, LnbTypeTable); |
| 1558 | } |
| 1559 | |
| 1560 | dvbdev_lnb_t LnbTypeFromString(const QString& type) |
| 1561 | { |
| 1562 | return (dvbdev_lnb_t)TableFromString(type, LnbTypeTable); |
| 1563 | } |
| 1564 | |
| 1565 | //////////////////////////////////////// Database Upgrade |
| 1566 | |
| 1567 | enum OLD_DISEQC_TYPES |
| 1568 | { |
| 1569 | DISEQC_SINGLE = 0, |
| 1570 | DISEQC_MINI_2 = 1, |
| 1571 | DISEQC_SWITCH_2_1_0 = 2, |
| 1572 | DISEQC_SWITCH_2_1_1 = 3, |
| 1573 | DISEQC_SWITCH_4_1_0 = 4, |
| 1574 | DISEQC_SWITCH_4_1_1 = 5, |
| 1575 | DISEQC_POSITIONER_1_2 = 6, |
| 1576 | DISEQC_POSITIONER_X = 7, |
| 1577 | DISEQC_POSITIONER_1_2_SWITCH_2 = 8, |
| 1578 | DISEQC_POSITIONER_X_SWITCH_2 = 9, |
| 1579 | DISEQC_SW21 = 10, |
| 1580 | DISEQC_SW64 = 11, |
| 1581 | }; |
| 1582 | |
| 1583 | bool DatabaseDiseqcUpgrade() |
| 1584 | { |
| 1585 | bool success = true; |
| 1586 | { |
| 1587 | MSqlQuery query(MSqlQuery::InitCon()); |
| 1588 | query.prepare("CREATE TABLE dtv_device_config (" |
| 1589 | "cardinputid int(11) unsigned NOT NULL," |
| 1590 | "dtv_dev_id int(11) unsigned NOT NULL," |
| 1591 | "value varchar(16) NOT NULL," |
| 1592 | "KEY id (cardinputid) )"); |
| 1593 | success = success && query.exec(); |
| 1594 | } |
| 1595 | { |
| 1596 | MSqlQuery query(MSqlQuery::InitCon()); |
| 1597 | query.prepare("CREATE TABLE dtv_device_tree (" |
| 1598 | "dtv_dev_id int(11) unsigned NOT NULL auto_increment," |
| 1599 | "parent int(11) unsigned default NULL," |
| 1600 | "ordinal tinyint(3) unsigned NOT NULL," |
| 1601 | "dtv_dev_type varchar(16) NOT NULL," |
| 1602 | "dtv_dev_subtype varchar(16) NOT NULL," |
| 1603 | "dtv_dev_descr varchar(32)," |
| 1604 | "switch_ports tinyint(3) unsigned default NULL," |
| 1605 | "rotor_hi_speed float default NULL," |
| 1606 | "rotor_lo_speed float default NULL," |
| 1607 | "rotor_positions varchar(256) default NULL," |
| 1608 | "lnb_lof_switch int(11) default NULL," |
| 1609 | "lnb_lof_hi int(11) default NULL," |
| 1610 | "lnb_lof_lo int(11) default NULL," |
| 1611 | "PRIMARY KEY (dtv_dev_id)," |
| 1612 | "KEY parent (parent) )"); |
| 1613 | success = success && query.exec(); |
| 1614 | } |
| 1615 | { |
| 1616 | MSqlQuery query(MSqlQuery::InitCon()); |
| 1617 | query.prepare("ALTER TABLE capturecard" |
| 1618 | " ADD dtv_dev_id int(10) unsigned default NULL"); |
| 1619 | success = success && query.exec(); |
| 1620 | } |
| 1621 | |
| 1622 | /* Deprecated fields: |
| 1623 | ALTER TABLE capturecard DROP dvb_diseqc_type; |
| 1624 | ALTER TABLE cardinput DROP diseqc_port; |
| 1625 | ALTER TABLE cardinput DROP diseqc_pos; |
| 1626 | ALTER TABLE cardinput DROP lnb_lof_switch; |
| 1627 | ALTER TABLE cardinput DROP lnb_lof_hi; |
| 1628 | ALTER TABLE cardinput DROP lnb_lof_lo; */ |
| 1629 | |
| 1630 | return success; |
| 1631 | } |
| 1632 | |
| 1633 | // import old diseqc configuration into tree |
| 1634 | bool DatabaseDiseqcImport() |
| 1635 | { |
| 1636 | MSqlQuery iquery(MSqlQuery::InitCon()); |
| 1637 | |
| 1638 | iquery.prepare("SELECT cardinputid, diseqc_port, diseqc_pos," |
| 1639 | " lnb_lof_switch, lnb_lof_hi, lnb_lof_lo" |
| 1640 | " FROM cardinput" |
| 1641 | " WHERE cardinput.cardid = :CARDID"); |
| 1642 | |
| 1643 | MSqlQuery cquery(MSqlQuery::InitCon()); |
| 1644 | cquery.prepare("SELECT cardid, dvb_diseqc_type FROM capturecard" |
| 1645 | " WHERE dvb_diseqc_type IS NOT NULL AND" |
| 1646 | " dtv_dev_id IS NULL"); |
| 1647 | |
| 1648 | // iterate through cards |
| 1649 | if(!cquery.exec()) |
| 1650 | return false; |
| 1651 | while(cquery.next()) |
| 1652 | { |
| 1653 | unsigned cardid = cquery.value(0).toUInt(); |
| 1654 | OLD_DISEQC_TYPES type = (OLD_DISEQC_TYPES)cquery.value(1).toUInt(); |
| 1655 | |
| 1656 | DVBDevTree tree; |
| 1657 | DVBDevDevice* root = NULL; |
| 1658 | unsigned int add_lnbs = 0; |
| 1659 | dvbdev_lnb_t lnb_type = LNB_VOLTAGE_TONE; |
| 1660 | |
| 1661 | // create root of tree |
| 1662 | switch(type) |
| 1663 | { |
| 1664 | case DISEQC_SINGLE: |
| 1665 | { |
| 1666 | // single LNB |
| 1667 | root = DVBDevDevice::CreateByType(tree, DVBDEV_LNB); |
| 1668 | break; |
| 1669 | } |
| 1670 | |
| 1671 | case DISEQC_MINI_2: |
| 1672 | { |
| 1673 | // tone switch + 2 LNBs |
| 1674 | root = DVBDevDevice::CreateByType(tree, DVBDEV_SWITCH); |
| 1675 | DVBDevSwitch* sw = dynamic_cast<DVBDevSwitch*>(root); |
| 1676 | sw->SetType(SWITCH_TONE); |
| 1677 | sw->SetNumPorts(2); |
| 1678 | add_lnbs = 2; |
| 1679 | break; |
| 1680 | } |
| 1681 | |
| 1682 | case DISEQC_SWITCH_2_1_0: |
| 1683 | case DISEQC_SWITCH_2_1_1: |
| 1684 | { |
| 1685 | // 2 port diseqc + 2 LNBs |
| 1686 | root = DVBDevDevice::CreateByType(tree, DVBDEV_SWITCH); |
| 1687 | DVBDevSwitch* sw = dynamic_cast<DVBDevSwitch*>(root); |
| 1688 | sw->SetType(SWITCH_DISEQC_COMMITTED); |
| 1689 | sw->SetNumPorts(2); |
| 1690 | add_lnbs = 2; |
| 1691 | break; |
| 1692 | } |
| 1693 | |
| 1694 | case DISEQC_SWITCH_4_1_0: |
| 1695 | case DISEQC_SWITCH_4_1_1: |
| 1696 | { |
| 1697 | // 4 port diseqc + 4 LNBs |
| 1698 | root = DVBDevDevice::CreateByType(tree, DVBDEV_SWITCH); |
| 1699 | DVBDevSwitch* sw = dynamic_cast<DVBDevSwitch*>(root); |
| 1700 | sw->SetType(SWITCH_DISEQC_COMMITTED); |
| 1701 | sw->SetNumPorts(4); |
| 1702 | add_lnbs = 4; |
| 1703 | break; |
| 1704 | } |
| 1705 | |
| 1706 | case DISEQC_POSITIONER_1_2: |
| 1707 | { |
| 1708 | // non-usals positioner + LNB |
| 1709 | root = DVBDevDevice::CreateByType(tree, DVBDEV_ROTOR); |
| 1710 | DVBDevRotor* rotor = dynamic_cast<DVBDevRotor*>(root); |
| 1711 | rotor->SetType(ROTOR_DISEQC_1_2); |
| 1712 | add_lnbs = 1; |
| 1713 | break; |
| 1714 | } |
| 1715 | |
| 1716 | case DISEQC_POSITIONER_X: |
| 1717 | { |
| 1718 | // usals positioner + LNB (diseqc_pos) |
| 1719 | root = DVBDevDevice::CreateByType(tree, DVBDEV_ROTOR); |
| 1720 | DVBDevRotor* rotor = dynamic_cast<DVBDevRotor*>(root); |
| 1721 | rotor->SetType(ROTOR_DISEQC_1_3); |
| 1722 | add_lnbs = 1; |
| 1723 | break; |
| 1724 | } |
| 1725 | |
| 1726 | case DISEQC_POSITIONER_1_2_SWITCH_2: |
| 1727 | { |
| 1728 | // 10 port uncommitted switch + 10 LNBs |
| 1729 | root = DVBDevDevice::CreateByType(tree, DVBDEV_SWITCH); |
| 1730 | DVBDevSwitch* sw = dynamic_cast<DVBDevSwitch*>(root); |
| 1731 | sw->SetType(SWITCH_DISEQC_UNCOMMITTED); |
| 1732 | sw->SetNumPorts(10); |
| 1733 | add_lnbs = 10; |
| 1734 | break; |
| 1735 | } |
| 1736 | |
| 1737 | case DISEQC_SW21: |
| 1738 | { |
| 1739 | // legacy SW21 + 2 fixed lnbs |
| 1740 | root = DVBDevDevice::CreateByType(tree, DVBDEV_SWITCH); |
| 1741 | DVBDevSwitch* sw = dynamic_cast<DVBDevSwitch*>(root); |
| 1742 | sw->SetType(SWITCH_LEGACY_SW21); |
| 1743 | sw->SetNumPorts(2); |
| 1744 | add_lnbs = 2; |
| 1745 | lnb_type = LNB_FIXED; |
| 1746 | break; |
| 1747 | } |
| 1748 | |
| 1749 | case DISEQC_SW64: |
| 1750 | { |
| 1751 | // legacy SW64 + 3 fixed lnbs |
| 1752 | root = DVBDevDevice::CreateByType(tree, DVBDEV_SWITCH); |
| 1753 | DVBDevSwitch* sw = dynamic_cast<DVBDevSwitch*>(root); |
| 1754 | sw->SetType(SWITCH_LEGACY_SW64); |
| 1755 | sw->SetNumPorts(3); |
| 1756 | add_lnbs = 3; |
| 1757 | lnb_type = LNB_FIXED; |
| 1758 | break; |
| 1759 | } |
| 1760 | |
| 1761 | default: |
| 1762 | VERBOSE(VB_IMPORTANT, "Unknown DiSEqC device type, ignoring card"); |
| 1763 | break; |
| 1764 | } |
| 1765 | if(!root) |
| 1766 | continue; |
| 1767 | tree.SetRoot(root); |
| 1768 | |
| 1769 | // create LNBs |
| 1770 | for(unsigned int i=0; i < add_lnbs; i++) |
| 1771 | { |
| 1772 | DVBDevLnb* lnb = dynamic_cast<DVBDevLnb*> |
| 1773 | (DVBDevDevice::CreateByType(tree, DVBDEV_LNB)); |
| 1774 | lnb->SetType(lnb_type); |
| 1775 | lnb->SetDescription(QString("LNB #%1").arg(i+1)); |
| 1776 | if(!root->SetChild(i, lnb)) |
| 1777 | delete lnb; |
| 1778 | } |
| 1779 | |
| 1780 | // save the tree to get real device ids |
| 1781 | tree.Store(cardid); |
| 1782 | |
| 1783 | // iterate inputs |
| 1784 | DVBDevSettings set; |
| 1785 | iquery.bindValue(":CARDID", cardid); |
| 1786 | if(!iquery.exec()) |
| 1787 | return false; |
| 1788 | while(iquery.next()) |
| 1789 | { |
| 1790 | unsigned int inputid = iquery.value(0).toUInt(); |
| 1791 | unsigned int port = iquery.value(1).toUInt(); |
| 1792 | double pos = iquery.value(2).toDouble(); |
| 1793 | DVBDevLnb* lnb = NULL; |
| 1794 | |
| 1795 | // configure LNB and settings |
| 1796 | switch(type) |
| 1797 | { |
| 1798 | case DISEQC_SINGLE: |
| 1799 | lnb = dynamic_cast<DVBDevLnb*>(root); |
| 1800 | break; |
| 1801 | |
| 1802 | case DISEQC_MINI_2: |
| 1803 | case DISEQC_SWITCH_2_1_0: |
| 1804 | case DISEQC_SWITCH_2_1_1: |
| 1805 | case DISEQC_SWITCH_4_1_0: |
| 1806 | case DISEQC_SWITCH_4_1_1: |
| 1807 | case DISEQC_SW21: |
| 1808 | case DISEQC_SW64: |
| 1809 | case DISEQC_POSITIONER_1_2_SWITCH_2: |
| 1810 | lnb = dynamic_cast<DVBDevLnb*>(root->GetChild(port)); |
| 1811 | set.SetValue(root->DeviceID(), port); |
| 1812 | break; |
| 1813 | |
| 1814 | case DISEQC_POSITIONER_1_2: |
| 1815 | case DISEQC_POSITIONER_X: |
| 1816 | lnb = dynamic_cast<DVBDevLnb*>(root->GetChild(0)); |
| 1817 | set.SetValue(root->DeviceID(), pos); |
| 1818 | break; |
| 1819 | |
| 1820 | default: |
| 1821 | break; |
| 1822 | } |
| 1823 | |
| 1824 | // configure lnb |
| 1825 | if(lnb) |
| 1826 | { |
| 1827 | lnb->SetLOFSwitch(iquery.value(3).toUInt()); |
| 1828 | lnb->SetLOFHigh(iquery.value(4).toUInt()); |
| 1829 | lnb->SetLOFLow(iquery.value(5).toUInt()); |
| 1830 | } |
| 1831 | |
| 1832 | // save settings |
| 1833 | set.Store(inputid); |
| 1834 | } |
| 1835 | |
| 1836 | // save any LNB changes |
| 1837 | tree.Store(cardid); |
| 1838 | |
| 1839 | // invalidate cached devices |
| 1840 | DVBDev trees; |
| 1841 | trees.InvalidateTrees(); |
| 1842 | } |
| 1843 | |
| 1844 | return true; |
| 1845 | } |