rendered paste body/**
* Actually tunes the card
*/
int tune_it(unsigned int freq, unsigned int srate, char pol,
int tone, fe_spectral_inversion_t specInv, unsigned char diseqc,
fe_modulation_t modulation, fe_code_rate_t HP_CodeRate,
fe_transmit_mode_t TransmissionMode, fe_guard_interval_t guardInterval,
fe_bandwidth_t bandwidth, fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier,
dvbcard_t *card, gint64 tune_wait_us)
{
int res;
int rv = -1;
int attempt = 1;
gint64 startTime = getMonoTime();
#ifdef READ_DUMP
if(config.read_dump){
return 0;
}
#endif
if (freq < 1000000) {
freq *= 1000UL;
}
struct dtv_properties cmdseq_tune = {
.num = 12, // magic 12, don't know what this is
};
gint64 timeRemaining = tune_wait_us;
while(rv && timeRemaining > 0 && !interrupted())
{
struct dtv_property p_clear[] = {
{ .cmd = DTV_CLEAR }
};
struct dtv_properties cmdseq_clear = {
.num = 1,
.props = p_clear
};
if ((ioctl(card->fd_frontend, FE_SET_PROPERTY, &cmdseq_clear)) == -1) {
perror("FE_SET_PROPERTY DTV_CLEAR failed \n");
return -1;
}
usleep (20*MSEC_uS);
if ((res = ioctl(card->fd_frontend, FE_GET_INFO, &(card->fe_info)) < 0))
{
ETVD_PERROR("FE_GET_INFO");
return -1;
}
updateTuneStatus();
g_info("\tCard %d tune attempt %d", card->g.cardIdx + 1, attempt++);
#if 0
/* Empty the event queue */
for( ; ; )
{
struct dvb_frontend_event event;
if ( ioctl( card->fd_frontend, FE_GET_EVENT, &event ) < 0
&& errno == EWOULDBLOCK )
break;
}
#endif
switch (card->fe_info.type)
{
case FE_OFDM:
; /* null statement - because you can't label a declaration */
struct dtv_property dvbt_tune[] = {
{ .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBT },
{ .cmd = DTV_FREQUENCY, .u.data = freq },
{ .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
{ .cmd = DTV_INVERSION, .u.data = INVERSION_OFF },
{ .cmd = DTV_BANDWIDTH_HZ, .u.data = (card->fe_info.caps & FE_CAN_BANDWIDTH_AUTO) ? BANDWIDTH_AUTO : bandwidth },
{ .cmd = DTV_CODE_RATE_HP, .u.data = FEC_AUTO },
{ .cmd = DTV_CODE_RATE_LP, .u.data = FEC_AUTO },
{ .cmd = DTV_GUARD_INTERVAL, .u.data = GUARD_INTERVAL_AUTO },
{ .cmd = DTV_TRANSMISSION_MODE, .u.data = TRANSMISSION_MODE_AUTO },
{ .cmd = DTV_HIERARCHY, .u.data = HIERARCHY_AUTO },
{ .cmd = DTV_TUNE },
};
cmdseq_tune.props = dvbt_tune;
g_info("\tTuning DVB-T card(%s) to %d Hz, Bandwidth: %d\n",
card->fe_info.name, freq,
bandwidth == BANDWIDTH_8_MHZ ? 8 : (bandwidth == BANDWIDTH_7_MHZ ? 7 : 6));
break;
case FE_QPSK:
card->diseqc = diseqc;
card->pol = toupper(pol);
int freq_param = 0;
if (freq > 2200000){
if (freq < SLOF){
freq_param = (freq - LOF1);
card->hi_lo = 0;
card->baseFreq = LOF1;
} else {
freq_param = (freq - LOF2);
card->hi_lo = 1;
card->baseFreq = LOF2;
}
} else {
freq_param = freq;
card->baseFreq = 0;
}
struct dtv_property dvbs_tune[] = {
{ .cmd = DTV_DELIVERY_SYSTEM, .u.data = card->currentTransponderType == TRANSPONDER_TYPE_DVBS2 ?
SYS_DVBS2 : SYS_DVBS },
{ .cmd = DTV_FREQUENCY, .u.data = freq_param },
{ .cmd = DTV_VOLTAGE, .u.data = card->pol == 'V' ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18 },
{ .cmd = DTV_SYMBOL_RATE, .u.data = srate },
{ .cmd = DTV_TONE, .u.data = card->hi_lo ? SEC_TONE_ON : SEC_TONE_OFF }, /* Not used? See S2API docs */
{ .cmd = DTV_MODULATION, .u.data = QPSK },
{ .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
{ .cmd = DTV_INVERSION, .u.data = specInv },
{ .cmd = DTV_ROLLOFF, .u.data = ROLLOFF_AUTO },
{ .cmd = DTV_BANDWIDTH_HZ, .u.data = 0 },
{ .cmd = DTV_PILOT, .u.data = PILOT_AUTO },
{ .cmd = DTV_TUNE },
};
cmdseq_tune.props = dvbs_tune;
/* Do this to ensure DiSEqC is set, may not be strictly necessary */
if (ioctl(card->fd_frontend, FE_SET_TONE, card->hi_lo ? SEC_TONE_ON : SEC_TONE_OFF) < 0)
ETVD_PERROR("Could not set 22kHz tone");
if (ioctl(card->fd_frontend, FE_SET_VOLTAGE, card->pol == 'V' ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18) < 0)
ETVD_PERROR("Could not set DiSEqC voltage");
g_info("\tTuning DVB-S card(%d) to %s %.01f %c MHz, SR %d, 22kHz tone %s\n",
card->g.cardIdx+1, card->currentTransponderType == TRANSPONDER_TYPE_DVBS2 ? "DVB-S2" : "DVB-S",
(double)freq / 1000, card->pol, srate/1000, card->hi_lo ? "on" : "off" );
break;
default:
g_warning("\tUnknown FE type. Aborting\n");
exit(-1);
}
struct pollfd pfd[1];
int locks = 0, ok = false;
fe_status_t festatus = 0; //FE_HAS_LOCK;
g_debug("Configuring frontend");
if (ioctl(card->fd_frontend, FE_SET_PROPERTY, &cmdseq_tune) == -1) {
ETVD_PERROR("FE_SET_PROPERTY TUNE failed");
//return -1;
}
usleep(300*MSEC_uS);
g_debug("waiting for lock info");
pfd[0].fd = card->fd_frontend;
pfd[0].events = POLLPRI;
gint64 startTimeInner = getMonoTime();
while (!ok && !interrupted())
{
festatus = 0;
if (poll(pfd, 1, 800) > 0)
{
if (pfd[0].revents & POLLPRI)
{
if (ioctl(card->fd_frontend, FE_READ_STATUS, &festatus) >= 0)
if (festatus & FE_HAS_LOCK)
locks++;
}
}
gchar* status = print_status(festatus);
g_debug("%s", status);
g_free(status);
if ((festatus & FE_TIMEDOUT) || (locks >= 3) || (getMonoTime() - startTimeInner > min(timeRemaining, 4*SEC_uS))){
ok = true;
continue;
}
usleep(500*MSEC_uS);
}
if (festatus & FE_HAS_LOCK)
{
g_string_printf(card->g.status, "TUNED and LOCKED");
struct dtv_property get_props[] = {
{ .cmd = DTV_FREQUENCY },
{ .cmd = DTV_SYMBOL_RATE },
{ .cmd = DTV_INNER_FEC },
};
struct dtv_properties get_props_a = {
.num = 11, .props = get_props
};
if (ioctl(card->fd_frontend, FE_GET_PROPERTY, get_props_a) >= 0)
{
switch (card->fe_info.type)
{
case FE_OFDM:
//nothing to do
break;
case FE_QPSK:
card->realFreq = (unsigned int)(get_props[0].u.data + card->baseFreq);
card->symbolRate = get_props[1].u.data;
card->fec = get_props[2].u.data;
break;
case FE_QAM:
card->realFreq = get_props[0].u.data;
card->symbolRate = get_props[1].u.data;
card->fec = get_props[2].u.data;
break;
#ifdef DVB_ATSC
case FE_ATSC:
card->realFreq = card->feparams.frequency;
//feparams->u.vsb.modulation);
break;
#endif
default:
break;
}
}
ioctl(card->fd_frontend, FE_READ_BER, &(card->errorRate));
ioctl(card->fd_frontend, FE_READ_SIGNAL_STRENGTH, &(card->signalStrength));
ioctl(card->fd_frontend, FE_READ_SNR, &(card->signalToNoise));
ioctl(card->fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &(card->uncorrectedBlocks));
rv = 0;
}
else
{
if(festatus & FE_HAS_SIGNAL){
g_string_printf(card->g.status, "Unable to lock signal");
rv = -1;
} else {
g_string_printf(card->g.status, "NO SIGNAL");
rv = -2;
}
}
if(rv) {
//reopen the card
g_debug("closing card for retune");
close(card->fd_frontend);
usleep(500*MSEC_uS);
g_debug("reopening card");
if ((card->fd_frontend = open(card->fdPath, O_RDWR | O_NONBLOCK)) < 0) {
return -1;
}
usleep(500*MSEC_uS);
g_debug("trying again");
}
timeRemaining = startTime + tune_wait_us - getMonoTime();
}
return rv;
}