All pastes #2080348 Raw Edit

Untitled

public text v1 · immutable
#2080348 ·published 2011-09-08 13:37 UTC
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;
}