summaryrefslogtreecommitdiff
path: root/p2pvr/devices/frontends
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2014-03-13 19:42:07 +0000
committerrandomdan <randomdan@localhost>2014-03-13 19:42:07 +0000
commitab1eee942e75874739ce5f0b4ba289aac5cc3faf (patch)
tree6e43828794fe0c0c5c9921ec1911695b67357c50 /p2pvr/devices/frontends
parentExpose more of the interface (diff)
downloadp2pvr-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.cpp159
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);
+