// documented in dvbchannel.h double DVBChannel::GetSignalStrength(bool *ok) const { const DVBChannel *master = GetMasterLock(); if (master != this) { double val = master->GetSignalStrength(ok); ReturnMasterLock(master); return val; } ReturnMasterLock(master); // if we're the master we don't need this lock.. // We use uint16_t for sig because this is correct for DVB API 4.0, // and works better than the correct int16_t for the 3.x API uint16_t sig = 0; int ret = ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &sig); if (ret < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Getting Frontend signal strength failed." + ENO); } if (ok) *ok = (0 == ret); return sig * (1.0 / 65535.0); }
// documented in dvbchannel.h bool DVBChannel::HasLock(bool *ok) const { const DVBChannel *master = GetMasterLock(); if (master != this) { bool haslock = master->HasLock(ok); ReturnMasterLock(master); return haslock; } ReturnMasterLock(master); // if we're the master we don't need this lock.. fe_status_t status; memset(&status, 0, sizeof(status)); int ret = ioctl(fd_frontend, FE_READ_STATUS, &status); if (ret < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Getting Frontend status failed." + ENO); } if (ok) *ok = (0 == ret); return status & FE_HAS_LOCK; }
/** \fn DVBChannel::ProbeTuningParams(DTVMultiplex&) const * \brief Fetches DTVMultiplex params from driver * * Note: Only updates tuning on success. * * \return true on success, false on failure */ bool DVBChannel::ProbeTuningParams(DTVMultiplex &tuning) const { QMutexLocker locker(&hw_lock); if (fd_frontend < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Card not open!"); return false; } const DVBChannel *master = GetMasterLock(); if (master != this) { bool ok = master->ProbeTuningParams(tuning); ReturnMasterLock(master); return ok; } ReturnMasterLock(master); // if we're the master we don't need this lock.. if (diseqc_tree) { // TODO We need to implement the inverse of // lnb->GetIntermediateFrequency() for ProbeTuningParams() // to accurately reflect the frequency before LNB transform. return false; } if (tunerType == DTVTunerType::kTunerTypeDVBS2) { // TODO implement probing of tuning parameters with FE_GET_PROPERTY return false; } dvb_frontend_parameters params; if (ioctl(fd_frontend, FE_GET_FRONTEND, ¶ms) < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Getting Frontend tuning parameters failed." + ENO); return false; } uint mplex = tuning.mplex; QString sistandard = tuning.sistandard; sistandard.detach(); tuning = dvbparams_to_dtvmultiplex(tunerType, params); tuning.mplex = mplex; tuning.sistandard = sistandard; return true; }
bool DVBChannel::IsMaster(void) const { const DVBChannel *master = GetMasterLock(); bool is_master = (master == this); ReturnMasterLock(master); return is_master; }
/** \fn DVBChannel::IsTuningParamsProbeSupported(void) const * \brief Returns true iff tuning info probing is working. */ bool DVBChannel::IsTuningParamsProbeSupported(void) const { QMutexLocker locker(&hw_lock); if (fd_frontend < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Card not open!"); return false; } const DVBChannel *master = GetMasterLock(); if (master != this) { bool ok = master->IsTuningParamsProbeSupported(); ReturnMasterLock(master); return ok; } ReturnMasterLock(master); // if we're the master we don't need this lock.. if (diseqc_tree) { // TODO We need to implement the inverse of // lnb->GetIntermediateFrequency() for ProbeTuningParams() // to accurately reflect the frequency before LNB transform. return false; } dvb_frontend_parameters params; int res = ioctl(fd_frontend, FE_GET_FRONTEND, ¶ms); if (res < 0) { LOG(VB_CHANNEL, LOG_ERR, LOC + "Getting device frontend failed." + ENO); } return (res >= 0); }
void DVBChannel::Close(DVBChannel *who) { LOG(VB_CHANNEL, LOG_INFO, LOC + "Closing DVB channel"); IsOpenMap::iterator it = is_open.find(who); if (it == is_open.end()) return; // this caller didn't have it open in the first place.. is_open.erase(it); QMutexLocker locker(&hw_lock); DVBChannel *master = GetMasterLock(); if (master != NULL && master != this) { if (dvbcam->IsRunning()) dvbcam->SetPMT(this, NULL); master->Close(this); fd_frontend = -1; ReturnMasterLock(master); return; } ReturnMasterLock(master); // if we're the master we don't need this lock.. if (!is_open.empty()) return; // not all callers have closed the DVB channel yet.. if (diseqc_tree) diseqc_tree->Close(); if (fd_frontend >= 0) { close(fd_frontend); fd_frontend = -1; dvbcam->Stop(); } }
// documented in dvbchannel.h double DVBChannel::GetUncorrectedBlockCount(bool *ok) const { const DVBChannel *master = GetMasterLock(); if (master != this) { double val = master->GetUncorrectedBlockCount(ok); ReturnMasterLock(master); return val; } ReturnMasterLock(master); // if we're the master we don't need this lock.. uint32_t ublocks = 0; int ret = ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &ublocks); if (ret < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Getting Frontend uncorrected block count failed." + ENO); } if (ok) *ok = (0 == ret); return (double) ublocks; }
// documented in dvbchannel.h double DVBChannel::GetBitErrorRate(bool *ok) const { const DVBChannel *master = GetMasterLock(); if (master != this) { double val = master->GetBitErrorRate(ok); ReturnMasterLock(master); return val; } ReturnMasterLock(master); // if we're the master we don't need this lock.. uint32_t ber = 0; int ret = ioctl(fd_frontend, FE_READ_BER, &ber); if (ret < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Getting Frontend signal error rate failed." + ENO); } if (ok) *ok = (0 == ret); return (double) ber; }
/** * \brief Tunes the card to a frequency but does not deal with PIDs. * * This is used by DVB Channel Scanner, the EIT Parser, and by TVRec. * * \param tuning Info on transport to tune to * \param inputid Optional, forces specific input (for DiSEqC) * \param force_reset If true, frequency tuning is done * even if it should not be needed. * \param same_input Optional, doesn't change input (for retuning). * \return true on success, false on failure */ bool DVBChannel::Tune(const DTVMultiplex &tuning, uint inputid, bool force_reset, bool same_input) { QMutexLocker lock(&tune_lock); QMutexLocker locker(&hw_lock); DVBChannel *master = GetMasterLock(); if (master != this) { LOG(VB_CHANNEL, LOG_INFO, LOC + "tuning on slave channel"); SetSIStandard(tuning.sistandard); bool ok = master->Tune(tuning, inputid, force_reset, false); ReturnMasterLock(master); return ok; } ReturnMasterLock(master); // if we're the master we don't need this lock.. int intermediate_freq = 0; bool can_fec_auto = false; bool reset = (force_reset || first_tune); if (tunerType.IsDiSEqCSupported() && !diseqc_tree) { LOG(VB_GENERAL, LOG_ERR, LOC + "DVB-S needs device tree for LNB handling"); return false; } desired_tuning = tuning; if (fd_frontend < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Card not open!"); return false; } // Remove any events in queue before tuning. drain_dvb_events(fd_frontend); // send DVB-S setup if (diseqc_tree) { // configure for new input if (!same_input) diseqc_settings.Load(inputid); // execute diseqc commands if (!diseqc_tree->Execute(diseqc_settings, tuning)) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Failed to setup DiSEqC devices"); return false; } // retrieve actual intermediate frequency DiSEqCDevLNB *lnb = diseqc_tree->FindLNB(diseqc_settings); if (!lnb) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): No LNB for this configuration"); return false; } if (lnb->GetDeviceID() != last_lnb_dev_id) { last_lnb_dev_id = lnb->GetDeviceID(); // make sure we tune to frequency, if the lnb has changed reset = first_tune = true; } intermediate_freq = lnb->GetIntermediateFrequency( diseqc_settings, tuning); // if card can auto-FEC, use it -- sometimes NITs are inaccurate if (capabilities & FE_CAN_FEC_AUTO) can_fec_auto = true; // Check DVB-S intermediate frequency here since it requires a fully // initialized diseqc tree CheckFrequency(intermediate_freq); } LOG(VB_CHANNEL, LOG_INFO, LOC + "Old Params: " + prev_tuning.toString() + "\n\t\t\t" + LOC + "New Params: " + tuning.toString()); // DVB-S is in kHz, other DVB is in Hz bool is_dvbs = ((DTVTunerType::kTunerTypeDVBS1 == tunerType) || (DTVTunerType::kTunerTypeDVBS2 == tunerType)); int freq_mult = (is_dvbs) ? 1 : 1000; QString suffix = (is_dvbs) ? "kHz" : "Hz"; if (reset || !prev_tuning.IsEqual(tunerType, tuning, 500 * freq_mult)) { LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Tune(): Tuning to %1%2") .arg(intermediate_freq ? intermediate_freq : tuning.frequency) .arg(suffix)); #if DVB_API_VERSION >=5 if (DTVTunerType::kTunerTypeDVBS2 == tunerType) { struct dtv_property p_clear; struct dtv_properties cmdseq_clear; p_clear.cmd = DTV_CLEAR; cmdseq_clear.num = 1; cmdseq_clear.props = &p_clear; if ((ioctl(fd_frontend, FE_SET_PROPERTY, &cmdseq_clear)) < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Clearing DTV properties cache failed." + ENO); return false; } struct dtv_properties *cmds = dtvmultiplex_to_dtvproperties( tunerType, tuning, intermediate_freq, can_fec_auto); if (!cmds) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to convert DTVMultiplex to DTV_PROPERTY sequence"); return false; } if (VERBOSE_LEVEL_CHECK(VB_CHANNEL, LOG_DEBUG)) { for (uint i = 0; i < cmds->num; i++) { LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("prop %1: cmd = %2, data %3") .arg(i).arg(cmds->props[i].cmd) .arg(cmds->props[i].u.data)); } } int res = ioctl(fd_frontend, FE_SET_PROPERTY, cmds); free(cmds->props); free(cmds); if (res < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Setting Frontend tuning parameters failed." + ENO); return false; } } else #endif { struct dvb_frontend_parameters params = dtvmultiplex_to_dvbparams( tunerType, tuning, intermediate_freq, can_fec_auto); if (ioctl(fd_frontend, FE_SET_FRONTEND, ¶ms) < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Tune(): Setting Frontend tuning parameters failed." + ENO); return false; } } // Extra delay to add for broken DVB drivers if (tuning_delay) usleep(tuning_delay * 1000); wait_for_backend(fd_frontend, 5 /* msec */); prev_tuning = tuning; first_tune = false; } SetSIStandard(tuning.sistandard); LOG(VB_CHANNEL, LOG_INFO, LOC + "Tune(): Frequency tuning successful."); return true; }
bool DVBChannel::Open(DVBChannel *who) { LOG(VB_CHANNEL, LOG_INFO, LOC + "Opening DVB channel"); QMutexLocker locker(&hw_lock); if (fd_frontend >= 0) { is_open[who] = true; return true; } DVBChannel *master = GetMasterLock(); if (master != this) { if (!master->Open(who)) { ReturnMasterLock(master); return false; } fd_frontend = master->fd_frontend; frontend_name = master->frontend_name; tunerType = master->tunerType; capabilities = master->capabilities; ext_modulations = master->ext_modulations; frequency_minimum = master->frequency_minimum; frequency_maximum = master->frequency_maximum; symbol_rate_minimum = master->symbol_rate_minimum; symbol_rate_maximum = master->symbol_rate_maximum; is_open[who] = true; if (!InitializeInputs()) { Close(); ReturnMasterLock(master); return false; } ReturnMasterLock(master); return true; } ReturnMasterLock(master); // if we're the master we don't need this lock.. QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device); QByteArray devn = devname.toAscii(); for (int tries = 1; ; ++tries) { fd_frontend = open(devn.constData(), O_RDWR | O_NONBLOCK); if (fd_frontend >= 0) break; LOG(VB_GENERAL, LOG_WARNING, LOC + "Opening DVB frontend device failed." + ENO); if (tries >= 20 || (errno != EBUSY && errno != EAGAIN)) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to open DVB frontend device due to " "fatal error or too many attempts.")); return false; } usleep(50000); } dvb_frontend_info info; memset(&info, 0, sizeof(info)); if (ioctl(fd_frontend, FE_GET_INFO, &info) < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get frontend information." + ENO); close(fd_frontend); fd_frontend = -1; return false; } frontend_name = info.name; tunerType = info.type; #if HAVE_FE_CAN_2G_MODULATION if (tunerType == DTVTunerType::kTunerTypeDVBS1 && (info.caps & FE_CAN_2G_MODULATION)) tunerType = DTVTunerType::kTunerTypeDVBS2; #endif // HAVE_FE_CAN_2G_MODULATION capabilities = info.caps; frequency_minimum = info.frequency_min; frequency_maximum = info.frequency_max; symbol_rate_minimum = info.symbol_rate_min; symbol_rate_maximum = info.symbol_rate_max; LOG(VB_RECORD, LOG_INFO, LOC + QString("Using DVB card %1, with frontend '%2'.") .arg(device).arg(frontend_name)); // Turn on the power to the LNB if (tunerType.IsDiSEqCSupported()) { diseqc_tree = diseqc_dev.FindTree(GetCardID()); if (diseqc_tree) diseqc_tree->Open(fd_frontend); } dvbcam->Start(); first_tune = true; if (!InitializeInputs()) { Close(); return false; } if (fd_frontend >= 0) is_open[who] = true; return (fd_frontend >= 0); }
void DVBChannel::CheckOptions(DTVMultiplex &tuning) const { if ((tuning.inversion == DTVInversion::kInversionAuto) && !(capabilities & FE_CAN_INVERSION_AUTO)) { LOG(VB_GENERAL, LOG_WARNING, LOC + "'Auto' inversion parameter unsupported by this driver, " "falling back to 'off'."); tuning.inversion = DTVInversion::kInversionOff; } // DVB-S needs a fully initialized diseqc tree and is checked later in Tune if (!diseqc_tree) { const DVBChannel *master = GetMasterLock(); if (master == NULL || !master->diseqc_tree) CheckFrequency(tuning.frequency); ReturnMasterLock(master); } if (tunerType.IsFECVariable() && symbol_rate_minimum && symbol_rate_maximum && (symbol_rate_minimum <= symbol_rate_maximum) && (tuning.symbolrate < symbol_rate_minimum || tuning.symbolrate > symbol_rate_maximum)) { LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Symbol Rate setting (%1) is out of range (min/max:%2/%3)") .arg(tuning.symbolrate) .arg(symbol_rate_minimum).arg(symbol_rate_maximum)); } if (tunerType.IsFECVariable() && !CheckCodeRate(tuning.fec)) { LOG(VB_GENERAL, LOG_WARNING, LOC + "Selected fec_inner parameter unsupported by this driver."); } if (tunerType.IsModulationVariable() && !CheckModulation(tuning.modulation)) { LOG(VB_GENERAL, LOG_WARNING, LOC + "Selected modulation parameter unsupported by this driver."); } if (DTVTunerType::kTunerTypeDVBT != tunerType && DTVTunerType::kTunerTypeDVBT2 != tunerType) { LOG(VB_CHANNEL, LOG_INFO, LOC + tuning.toString()); return; } // Check OFDM Tuning params if (!CheckCodeRate(tuning.hp_code_rate)) { LOG(VB_GENERAL, LOG_WARNING, LOC + "Selected code_rate_hp parameter unsupported by this driver."); } if (!CheckCodeRate(tuning.lp_code_rate)) { LOG(VB_GENERAL, LOG_WARNING, LOC + "Selected code_rate_lp parameter unsupported by this driver."); } if ((tuning.bandwidth == DTVBandwidth::kBandwidthAuto) && !(capabilities & FE_CAN_BANDWIDTH_AUTO)) { LOG(VB_GENERAL, LOG_WARNING, LOC + "'Auto' bandwidth parameter unsupported by this driver."); } if ((tuning.trans_mode == DTVTransmitMode::kTransmissionModeAuto) && !(capabilities & FE_CAN_TRANSMISSION_MODE_AUTO)) { LOG(VB_GENERAL, LOG_WARNING, LOC + "'Auto' transmission_mode parameter unsupported by this driver."); } if ((tuning.guard_interval == DTVGuardInterval::kGuardIntervalAuto) && !(capabilities & FE_CAN_GUARD_INTERVAL_AUTO)) { LOG(VB_GENERAL, LOG_WARNING, LOC + "'Auto' guard_interval parameter unsupported by this driver."); } if ((tuning.hierarchy == DTVHierarchy::kHierarchyAuto) && !(capabilities & FE_CAN_HIERARCHY_AUTO)) { LOG(VB_GENERAL, LOG_WARNING, LOC + "'Auto' hierarchy parameter unsupported by this driver. "); } if (!CheckModulation(tuning.modulation)) { LOG(VB_GENERAL, LOG_WARNING, LOC + "Selected modulation parameter unsupported by this driver."); } LOG(VB_CHANNEL, LOG_INFO, LOC + tuning.toString()); }
bool DVBChannel::Open(DVBChannel *who) { LOG(VB_CHANNEL, LOG_INFO, LOC + "Opening DVB channel"); if (!m_inputid) { if (!InitializeInput()) return false; } QMutexLocker locker(&m_hw_lock); if (m_fd_frontend >= 0) { m_is_open[who] = true; return true; } DVBChannel *master = GetMasterLock(); if (master != this) { if (!master->Open(who)) { ReturnMasterLock(master); return false; } m_fd_frontend = master->m_fd_frontend; m_frontend_name = master->m_frontend_name; m_tunerType = master->m_tunerType; m_capabilities = master->m_capabilities; m_ext_modulations = master->m_ext_modulations; m_frequency_minimum = master->m_frequency_minimum; m_frequency_maximum = master->m_frequency_maximum; m_symbol_rate_minimum = master->m_symbol_rate_minimum; m_symbol_rate_maximum = master->m_symbol_rate_maximum; m_is_open[who] = true; if (!InitializeInput()) { Close(); ReturnMasterLock(master); return false; } ReturnMasterLock(master); return true; } ReturnMasterLock(master); // if we're the master we don't need this lock.. QString devname = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, m_device); QByteArray devn = devname.toLatin1(); for (int tries = 1; ; ++tries) { m_fd_frontend = open(devn.constData(), O_RDWR | O_NONBLOCK); if (m_fd_frontend >= 0) break; LOG(VB_GENERAL, LOG_WARNING, LOC + "Opening DVB frontend device failed." + ENO); if (tries >= 20 || (errno != EBUSY && errno != EAGAIN)) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to open DVB frontend device due to " "fatal error or too many attempts.")); return false; } usleep(50000); } dvb_frontend_info info; memset(&info, 0, sizeof(info)); if (ioctl(m_fd_frontend, FE_GET_INFO, &info) < 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get frontend information." + ENO); close(m_fd_frontend); m_fd_frontend = -1; return false; } m_frontend_name = info.name; m_tunerType = info.type; #if HAVE_FE_CAN_2G_MODULATION if (info.caps & FE_CAN_2G_MODULATION) { if (m_tunerType == DTVTunerType::kTunerTypeDVBS1) m_tunerType = DTVTunerType::kTunerTypeDVBS2; else if (m_tunerType == DTVTunerType::kTunerTypeDVBT) m_tunerType = DTVTunerType::kTunerTypeDVBT2; } #endif // HAVE_FE_CAN_2G_MODULATION m_capabilities = info.caps; m_frequency_minimum = info.frequency_min; m_frequency_maximum = info.frequency_max; m_symbol_rate_minimum = info.symbol_rate_min; m_symbol_rate_maximum = info.symbol_rate_max; #if DVB_API_VERSION >=5 unsigned int i; struct dtv_property prop; struct dtv_properties cmd; memset(&prop, 0, sizeof(prop)); prop.cmd = DTV_API_VERSION; cmd.num = 1; cmd.props = ∝ if (ioctl(m_fd_frontend, FE_GET_PROPERTY, &cmd) == 0) { LOG(VB_RECORD, LOG_INFO, LOC + QString("dvb api version %1.%2").arg((prop.u.data>>8)&0xff).arg((prop.u.data)&0xff)); }