diff options
author | randomdan <randomdan@localhost> | 2014-03-13 19:42:07 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2014-03-13 19:42:07 +0000 |
commit | ab1eee942e75874739ce5f0b4ba289aac5cc3faf (patch) | |
tree | 6e43828794fe0c0c5c9921ec1911695b67357c50 /p2pvr/devices/frontends | |
parent | Expose more of the interface (diff) | |
download | p2pvr-ab1eee942e75874739ce5f0b4ba289aac5cc3faf.tar.bz2 p2pvr-ab1eee942e75874739ce5f0b4ba289aac5cc3faf.tar.xz p2pvr-ab1eee942e75874739ce5f0b4ba289aac5cc3faf.zip |
Restructure into more sensibly arranged libs
Diffstat (limited to 'p2pvr/devices/frontends')
-rw-r--r-- | p2pvr/devices/frontends/ofdm.cpp | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/p2pvr/devices/frontends/ofdm.cpp b/p2pvr/devices/frontends/ofdm.cpp new file mode 100644 index 0000000..93e0d86 --- /dev/null +++ b/p2pvr/devices/frontends/ofdm.cpp @@ -0,0 +1,159 @@ +#include <pch.hpp> +#include "../frontend.h" +#include "../tuner.h" +#include <sys/ioctl.h> +#include <logger.h> +#include <linux/dvb/frontend.h> + +#define FREQ_OFFSET_MIN 0 +#define FREQ_OFFSET_MAX 4 + +class Frontend_OFDM : public Frontend { + public: + Frontend_OFDM(Tuner * t, int fd, const struct dvb_frontend_info & i) : Frontend(t, fd, i) { } + + void TuneTo(const DVBSI::DeliveryPtr & mp) const + { + auto td = DVBSI::TerrestrialDeliveryPtr::dynamicCast(mp); + if (!td) { + throw P2PVR::IncorrectDeliveryType(); + } + dvb_frontend_parameters feparams; + memset(&feparams, 0, sizeof(dvb_frontend_parameters)); + feparams.frequency = td->Frequency; + feparams.inversion = INVERSION_OFF; + feparams.u.ofdm.bandwidth = (fe_bandwidth)td->Bandwidth; + feparams.u.ofdm.code_rate_HP = (fe_code_rate_t)td->CodeRateHP; + feparams.u.ofdm.code_rate_LP = (fe_code_rate_t)td->CodeRateLP; + feparams.u.ofdm.constellation = (fe_modulation_t)td->Constellation; + feparams.u.ofdm.transmission_mode = (fe_transmit_mode)td->TransmissionMode; + feparams.u.ofdm.guard_interval = (fe_guard_interval_t)td->GuardInterval; + feparams.u.ofdm.hierarchy_information = (fe_hierarchy_t)td->Hierarchy; + SetParameters(feparams); + WaitForLock(); + } + + dvb_frontend_parameters GetParameters() const + { + dvb_frontend_parameters feparams; + memset(&feparams, 0, sizeof(dvb_frontend_parameters)); + if (ioctl(frontendFD, FE_GET_FRONTEND, &feparams) < 0) { + Logger()->messagebf(LOG_ERR, "Reading frontend parameters failed (%s:%d)", tuner->Device(), strerror(errno), errno); + throw P2PVR::DeviceError(tuner->Device(), strerror(errno), errno); + } + return feparams; + } + + void WaitForLock() const + { + fe_status_t status = (fe_status_t)0; + // Wait for something + for (int x = Tuner::TuningTimeout / 10; x > 0 && (status = GetStatus()) == 0; x -= 1) { + usleep(10000); + } + // Was it useful? + if (!(status & (FE_HAS_SIGNAL | FE_HAS_CARRIER))) { + Logger()->messagebf(LOG_ERR, "Tuning of device %s failed (No signal or carrier: 0x%02x)", tuner->Device(), status); + throw P2PVR::DeviceError(tuner->Device(), "No carrier", 0); + } + // Wait for lock + for (int x = Tuner::LockTimeout / 10; x > 0 && ((status = GetStatus()) & FE_HAS_LOCK) == 0; x -= 1) { + usleep(10000); + } + if (!(status & FE_HAS_LOCK)) { + Logger()->messagebf(LOG_ERR, "Tuning of device %s failed (%s)", tuner->Device(), "No lock"); + throw P2PVR::DeviceError(tuner->Device(), "No lock", 0); + } + } + + void SetParameters(const dvb_frontend_parameters & feparams) const + { + if (ioctl(frontendFD, FE_SET_FRONTEND, &feparams) < 0) { + Logger()->messagebf(LOG_ERR, "Tuning of device %s failed (%s:%d)", tuner->Device(), strerror(errno), errno); + throw P2PVR::DeviceError(tuner->Device(), strerror(errno), errno); + } + } + + std::string Type() const + { + return "OFDM (DVB-T)"; + } + + enum Country { DVBT_AU, DVBT_DE, DVBT_FR, DVBT_GB }; + + static uint32_t FrequencyForCountry(Country country, int channel) + { + switch (country) { + case DVBT_AU: //AUSTRALIA, 7MHz step list + switch (channel) { + case 5 ... 12: return 142500000; + case 21 ... 69: return 333500000; + } + case DVBT_DE: //GERMANY + case DVBT_FR: //FRANCE, +/- offset 166kHz & +offset 332kHz & +offset 498kHz + case DVBT_GB: //UNITED KINGDOM, +/- offset + switch (channel) { + case 5 ... 12: return 142500000; // VHF unused in FRANCE, skip those in offset loop + case 21 ... 69: return 306000000; + } + } + return 0; + } + static uint32_t FrequencyStepForCountry(Country country, int channel) + { + switch (country) { + case DVBT_AU: + return 7000000; // dvb-t australia, 7MHz step + case DVBT_DE: + case DVBT_FR: + case DVBT_GB: + switch (channel) { // dvb-t europe, 7MHz VHF ch5..12, all other 8MHz + case 5 ... 12: return 7000000; + case 21 ... 69: return 8000000; + } + } + return 0; + } + static uint32_t ChannelFrequencyForCountry(Country country, int channel, int) + { + return FrequencyForCountry(country, channel) + (channel * FrequencyStepForCountry(country, channel)); + } + + void FrequencyScan(const OnFrequencyFound & onFrequencyFound) const + { + struct dvb_frontend_parameters feparams; + memset(&feparams, 0, sizeof(dvb_frontend_parameters)); + feparams.inversion = (fe_info.caps & FE_CAN_INVERSION_AUTO ? INVERSION_AUTO : INVERSION_OFF); + feparams.u.ofdm.constellation = (fe_info.caps & FE_CAN_QAM_AUTO ? QAM_AUTO : QAM_64); + feparams.u.ofdm.hierarchy_information = HIERARCHY_NONE; + + for (int channel = 0; channel < 134; channel += 1) { + for (uint32_t offset = FREQ_OFFSET_MIN; offset <= 0/*FREQ_OFFSET_MAX*/; offset += 1) { + feparams.frequency = ChannelFrequencyForCountry(DVBT_GB, channel, offset); + if (feparams.frequency == 0) { + continue; + } + if (fe_info.frequency_min > feparams.frequency || fe_info.frequency_max < feparams.frequency) { + Logger()->messagebf(LOG_WARNING, "Channel %d, freq (%d Hz) outside card range", channel, feparams.frequency); + continue; + } + try { + Logger()->messagebf(LOG_DEBUG, "Channel %d, Frequency %d Hz", channel, feparams.frequency); + SetParameters(feparams); + WaitForLock(); + Logger()->messagebf(LOG_INFO, "Found multiplex at %d Hz", feparams.frequency); + Logger()->messagebf(LOG_DEBUG, "frequency %d", feparams.frequency); + if (onFrequencyFound(feparams.frequency)) { + return; + } + } + catch (const P2PVR::DeviceError &) { + // Moving on... + } + } + } + } +}; + +DECLARE_GENERIC_LOADER(FE_OFDM, FrontendLoader, Frontend_OFDM); + |