void DVBSignalMonitor::HandleTDT(const TimeDateTable *tdt) { DTVSignalMonitor::HandleTDT(tdt); DVBChannel *dvbchannel = GetDVBChannel(); if (dvbchannel) dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset()); }
void DVBSignalMonitor::HandleSTT(const SystemTimeTable *stt) { DTVSignalMonitor::HandleSTT(stt); DVBChannel *dvbchannel = GetDVBChannel(); if (dvbchannel) dvbchannel->SetTimeOffset(GetStreamData()->TimeOffset()); }
void DVBSignalMonitor::HandlePMT(uint program_num, const ProgramMapTable *pmt) { DTVSignalMonitor::HandlePMT(program_num, pmt); if (pmt->ProgramNumber() == (uint)programNumber) { DVBChannel *dvbchannel = GetDVBChannel(); if (dvbchannel) dvbchannel->SetPMT(pmt); } }
void DVBSignalMonitor::GetRotorStatus(bool &was_moving, bool &is_moving) { DVBChannel *dvbchannel = GetDVBChannel(); if (!dvbchannel) return; const DiSEqCDevRotor *rotor = dvbchannel->GetRotor(); if (!rotor) return; QMutexLocker locker(&statusLock); was_moving = rotorPosition.GetValue() < 100; int pos = (int)truncf(rotor->GetProgress() * 100); rotorPosition.SetValue(pos); is_moving = rotorPosition.GetValue() < 100; }
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(); } }
/** * \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); }
/** \fn DVBSignalMonitor::UpdateValues() * \brief Fills in frontend stats and emits status Qt signals. * * This is automatically called by MonitorLoop(), after Start() * has been used to start the signal monitoring thread. */ void DVBSignalMonitor::UpdateValues(void) { if (!running || exit) return; if (streamHandlerStarted) { if (!streamHandler->IsRunning()) { error = QObject::tr("Error: stream handler died"); update_done = true; return; } EmitStatus(); if (IsAllGood()) SendMessageAllGood(); // TODO dtv signals... update_done = true; return; } AddFlags(kSigMon_WaitForSig); DVBChannel *dvbchannel = GetDVBChannel(); if (!dvbchannel) return; // Handle retuning after rotor has turned if (HasFlags(SignalMonitor::kDVBSigMon_WaitForPos)) { if (dvbchannel->GetRotor()) { if (!streamHandler->IsRetuneAllowed()) streamHandler->SetRetuneAllowed(true, this, dvbchannel); streamHandler->RetuneMonitor(); } else RemoveFlags(SignalMonitor::kDVBSigMon_WaitForPos); } bool wasLocked = false, isLocked = false; uint sig = 0, snr = 0, ber = 0, ublocks = 0; // Get info from card bool has_lock = dvbchannel->HasLock(); if (HasFlags(kSigMon_WaitForSig)) sig = (uint) (dvbchannel->GetSignalStrength() * 65535); if (HasFlags(kDVBSigMon_WaitForSNR)) snr = (uint) (dvbchannel->GetSNR() * 65535); if (HasFlags(kDVBSigMon_WaitForBER)) ber = (uint) dvbchannel->GetBitErrorRate(); if (HasFlags(kDVBSigMon_WaitForUB)) ublocks = (uint) dvbchannel->GetUncorrectedBlockCount(); has_lock |= streamHandler->IsRunning(); // Set SignalMonitorValues from info from card. { QMutexLocker locker(&statusLock); // BER and UB are actually uint32 values, but we // clamp them at 64K. This is because these values // are acutally cumulative, but we don't try to // normalize these to a time period. wasLocked = signalLock.IsGood(); signalLock.SetValue((has_lock) ? 1 : 0); isLocked = signalLock.IsGood(); if (HasFlags(kSigMon_WaitForSig)) signalStrength.SetValue(sig); if (HasFlags(kDVBSigMon_WaitForSNR)) signalToNoise.SetValue(snr); if (HasFlags(kDVBSigMon_WaitForBER)) bitErrorRate.SetValue(ber); if (HasFlags(kDVBSigMon_WaitForUB)) uncorrectedBlocks.SetValue(ublocks); } // Debug output if (wasLocked != isLocked) { VERBOSE(VB_CHANNEL, LOC + "UpdateValues -- Signal " <<(isLocked ? "Locked" : "Lost")); } EmitStatus(); if (IsAllGood()) SendMessageAllGood(); // Start table monitoring if we are waiting on any table // and we have a lock. if (isLocked && GetStreamData() && (!HasFlags(kDVBSigMon_WaitForPos) || rotorPosition.IsGood()) && HasAnyFlag(kDTVSigMon_WaitForPAT | kDTVSigMon_WaitForPMT | kDTVSigMon_WaitForMGT | kDTVSigMon_WaitForVCT | kDTVSigMon_WaitForNIT | kDTVSigMon_WaitForSDT)) { GetStreamData()->AddListeningPID(MPEG_PAT_PID); streamHandler->AddListener(GetStreamData(), true, false); streamHandlerStarted = true; } update_done = true; }
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)); }