#include #include #include #include #include "dvb_tuner.h" #include "dvb_channels.h" // {{{ dvb_tuner_create /** * Create a new DVB-Tuner * * @param int adapterID ID of adapater (/dev/dvb/adapter/) * @access public * @return dvb_tuner */ dvb_tuner *dvb_tuner_create (int adapterID, dvb_tuner *chain) { dvb_tuner *result = malloc (sizeof (dvb_tuner)); memset (&result->frontend_param, 0, sizeof (struct dvb_frontend_parameters)); /* Set initial values */ result->adapterID = adapterID; result->openWait = 5; /* Try to open file-handle for frontend */ if (((result->frontend_fd = dvb_tuner_try_open (result, "frontend0", O_RDWR)) == NULL) || (ioctl (result->frontend_fd, FE_GET_INFO, &result->frontend_info) < 0)) { close (result->frontend_fd); free (result); return NULL; } /* Add tuner to our chain */ result->next = chain; return result; } // }}} // {{{ dvb_tuner_add_filter dvb_tuner_filter *dvb_tuner_add_filter (dvb_tuner *tuner, __u16 pid, dmx_input_t input, dmx_output_t output, dmx_pes_type_t type, __u32 flags) { dvb_tuner_filter *result = malloc (sizeof (dvb_tuner_filter)); /* Set Flags of this filter */ result->filter.pid = pid; result->filter.input = input; result->filter.output = output; result->filter.pes_type = type; result->filter.flags = flags; result->parent = tuner; /* Add Filter to our current filter-chain */ result->next = tuner->filters; tuner->filters = result; return result; } // }}} // {{{ dvb_tuner_try_open /** * Try to open a DVB-Device * * @param dvb_tuner *tuner * @param char fn * @param int flags * * @access private * @return int */ int dvb_tuner_try_open (dvb_tuner *tuner, char *fn, int flags) { int i, ret; // Try to open device for a while for (i = 0; i < tuner->openWait * 20; i++) { if (!((ret = open (("/dev/dvb/adapter%d/%s", tuner->adapterID, fn), flags)) < 0)) return ret; usleep (50000); } return ret; } // }}} // {{{ dvb_tuner_set /** * Tune to a given channel * * @param dvb_tuner *tuner * @param dvb_channel *channel * * @access public * @return bool */ int dvb_tuner_set (dvb_tuner *tuner, dvb_channel *channel) { dvb_tuner_filter *nextf, *filter = tuner->filters; /* Check types */ if (tuner->frontend_info.type != channel->type) return NULL; /* Setup the frontend */ tuner->frontend_param.frequency = channel->freq; tuner->frontend_param.inversion = channel->inversion; // ATSC if (channel->type == FE_ATSC) { tuner->frontend_param.u.vsb.modulation = channel->mod; // DVB-C } else if (channel->type == FE_QAM) { tuner->frontend_param.u.qam.symbol_rate = channel->srate; tuner->frontend_param.u.qam.fec_inner = channel->fec; tuner->frontend_param.u.qam.modulation = channel->mod; // DVB-T } else if (channel->type == FE_OFDM) { tuner->frontend_param.u.ofdm.bandwidth = channel->bandwidth; tuner->frontend_param.u.ofdm.code_rate_HP = channel->rHP; tuner->frontend_param.u.ofdm.code_rate_LP = channel->rLP; tuner->frontend_param.u.ofdm.constellation = channel->constellation; tuner->frontend_param.u.ofdm.transmission_mode = channel->mode; tuner->frontend_param.u.ofdm.guard_interval = channel->guard; tuner->frontend_param.u.ofdm.hierarchy_information = channel->hierarchy; // DVB-S } else if (channel->type == FE_QPSK) { tuner->frontend_param.u.qpsk.symbol_rate = channel->srate; tuner->frontend_param.u.qpsk.fec_inner = channel->fec; /* Setup the LNB */ int hiband = 0; uint32_t ifreq = channel->freq - tuner->lnb_type.high_val; struct diseqc_cmd cmd = {{{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0}; if (tuner->lnb_type.switch_val && tuner->lnb_type.high_val && (channel->freq >= tuner->lnb_type.switch_val)) hiband = 1; else if (channel->freq < tuner->lnb_type.low_val) ifreq = tuner->lnb_type.low_val - channel->freq; cmd.cmd.msg [3] = 0xf0 | (((channel->sat_number * 4) & 0x0f) | hiband | (channel->polarity ? 0 : 2)); ioctl (tuner->frontend_fd, FE_SET_TONE, SEC_TONE_OFF); ioctl (tuner->frontend_fd, FE_SET_VOLTAGE, channel->polarity ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); usleep (15 * 1000); ioctl (tuner->frontend_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd.cmd); usleep (cmd.wait * 1000); usleep (15 * 1000); ioctl (tuner->frontend_fd, FE_DISEQC_SEND_BURST, (channel->sat_number / 4) % 2 ? SEC_MINI_B : SEC_MINI_A); usleep (15 * 1000); ioctl (tuner->frontend_fd, FE_SET_TONE, hiband ? SEC_TONE_ON : SEC_TONE_OFF); } /* Tune the tuner ;-) */ if (ioctl (tuner->frontend_fd, FE_SET_FRONTEND, &tuner->frontend_param) < 0) return NULL; /* Stop current filters */ while (filter != NULL) { nextf = filter->next; close (filter->filter_fd); free (filter); filter = nextf; } /* Setup new filters */ dvb_tuner_add_filter (tuner, channel->vpid, DMX_IN_FRONTEND, DMX_OUT_TS_TAP, DMX_PES_VIDEO, DMX_IMMEDIATE_START); dvb_tuner_add_filter (tuner, channel->apid, DMX_IN_FRONTEND, DMX_OUT_TS_TAP, DMX_PES_AUDIO, DMX_IMMEDIATE_START); filter = tuner->filters; while (filter != NULL) { dvb_tuner_setup_filter (filter); filter = filter->next; } return 1; } // }}} // {{{ dvb_tuner_setup_filter /** * Setup and activate a DVB-Demux-Filter * * @param dvb_tuner_filter filter * * @access public * @return bool */ int dvb_tuner_setup_filter (dvb_tuner_filter *filter) { // Validate this filter if ((filter == NULL) || (filter->filter.pid < 1)) return NULL; // Close filter first if already open if (filter->filter_fd) close (filter->filter_fd); // Try to open the demuxer if ((filter->filter_fd = dvb_tuner_try_open (filter->parent, "demux0", O_RDWR)) == NULL) return NULL; // Setup the demuxer if (ioctl (filter->filter_fd, DMX_SET_PES_FILTER, &filter->filter) < 0) { close (filter->filter_fd); return NULL; } // Return the handle (which is non-zero) return filter->filter_fd; } // }}} // {{{ dvb_tuner_stop /** * Close the tuner * * @param dvb_tuner tuner * * @access public * @return void */ void dvb_tuner_stop (dvb_tuner *tuner) { dvb_tuner_filter *nextf, *filter = tuner->filters; /* Stop current filters */ while (filter != NULL) { nextf = filter->next; close (filter->filter_fd); free (filter); filter = nextf; } } // }}}