/** * 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; }