예제 #1
0
void dvb_desc_event_short_print(struct dvb_v5_fe_parms *parms, const struct dvb_desc *desc)
{
    const struct dvb_desc_event_short *event = (const struct dvb_desc_event_short *) desc;
    dvb_log("|   Name          '%s'", event->name);
    dvb_log("|   Language      '%s'", event->language);
    dvb_log("|   Description   '%s'", event->text);
}
예제 #2
0
void dvb_fe_prt_parms(const struct dvb_v5_fe_parms *p)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	int i;

	for (i = 0; i < parms->n_props; i++) {
		const char * const *attr_name = dvb_attr_names(parms->dvb_prop[i].cmd);
		if (attr_name) {
			int j;

			for (j = 0; j < parms->dvb_prop[i].u.data; j++) {
				if (!*attr_name)
					break;
				attr_name++;
			}
		}

		if (!attr_name || !*attr_name)
			dvb_log("%s = %u",
				dvb_cmd_name(parms->dvb_prop[i].cmd),
				parms->dvb_prop[i].u.data);
		else
			dvb_log("%s = %s",
				dvb_cmd_name(parms->dvb_prop[i].cmd),
				*attr_name);
	}
};
예제 #3
0
int dvb_fe_get_event(struct dvb_v5_fe_parms *p)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	struct dvb_frontend_event event;
	fe_status_t status;
	int i;

	if (!parms->p.legacy_fe) {
		dvb_fe_get_parms(&parms->p);
		return dvb_fe_get_stats(&parms->p);
	}

	if (xioctl(parms->fd, FE_GET_EVENT, &event) == -1) {
		dvb_perror("FE_GET_EVENT");
		return errno;
	}
	status = event.status;
	if (parms->p.verbose > 1) {
		dvb_log(_("Status: "));
		for (i = 0; i < ARRAY_SIZE(fe_status_name); i++) {
			if (status & fe_status_name[i].idx)
				dvb_log ("    %s", fe_status_name[i].name);
		}
	}
	dvb_fe_store_stats(parms, DTV_STATUS, FE_SCALE_RELATIVE, 0, status);

	dvb_fe_retrieve_parm(&parms->p, DTV_FREQUENCY, &event.parameters.frequency);
	dvb_fe_retrieve_parm(&parms->p, DTV_INVERSION, &event.parameters.inversion);
	switch (parms->p.current_sys) {
	case SYS_DVBS:
		dvb_fe_retrieve_parm(&parms->p, DTV_SYMBOL_RATE, &event.parameters.u.qpsk.symbol_rate);
		dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &event.parameters.u.qpsk.fec_inner);
		break;
	case SYS_DVBC_ANNEX_AC:
		dvb_fe_retrieve_parm(&parms->p, DTV_SYMBOL_RATE, &event.parameters.u.qam.symbol_rate);
		dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &event.parameters.u.qam.fec_inner);
		dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &event.parameters.u.qam.modulation);
		break;
	case SYS_ATSC:
	case SYS_ATSCMH:
	case SYS_DVBC_ANNEX_B:
		dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &event.parameters.u.vsb.modulation);
		break;
	case SYS_DVBT:
		dvb_fe_retrieve_parm(&parms->p, DTV_BANDWIDTH_HZ, &event.parameters.u.ofdm.bandwidth);
		dvb_fe_retrieve_parm(&parms->p, DTV_CODE_RATE_HP, &event.parameters.u.ofdm.code_rate_HP);
		dvb_fe_retrieve_parm(&parms->p, DTV_CODE_RATE_LP, &event.parameters.u.ofdm.code_rate_LP);
		dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &event.parameters.u.ofdm.constellation);
		dvb_fe_retrieve_parm(&parms->p, DTV_TRANSMISSION_MODE, &event.parameters.u.ofdm.transmission_mode);
		dvb_fe_retrieve_parm(&parms->p, DTV_GUARD_INTERVAL, &event.parameters.u.ofdm.guard_interval);
		dvb_fe_retrieve_parm(&parms->p, DTV_HIERARCHY, &event.parameters.u.ofdm.hierarchy_information);
		break;
	default:
		return EINVAL;
	}

	return dvb_fe_get_stats(&parms->p);
}
예제 #4
0
void dvb_desc_hierarchy_print(struct dvb_v5_fe_parms *parms, const struct dvb_desc *desc)
{
    const struct dvb_desc_hierarchy *hierarchy = (const struct dvb_desc_hierarchy *) desc;
    dvb_log("|	Hierarchy");
    dvb_log("|           type           %d", hierarchy->hierarchy_type);
    dvb_log("|           layer          %d", hierarchy->layer);
    dvb_log("|           embedded_layer %d", hierarchy->embedded_layer);
    dvb_log("|           channel        %d", hierarchy->channel);
}
예제 #5
0
void dvb_desc_service_location_print(struct dvb_v5_fe_parms *parms, const struct dvb_desc *desc)
{
	const struct dvb_desc_service_location *service_location = (const struct dvb_desc_service_location *) desc;
	struct dvb_desc_service_location_element *element = service_location->element;
	int i;

	dvb_log("|    pcr pid      %d", service_location->pcr_pid);
	dvb_log("|    streams:");
	for (i = 0; i < service_location->elements; i++)
		dvb_log("|      pid %d, type %d: %s", element[i].elementary_pid, element[i].stream_type, element[i].language);
	dvb_log("| 	%d elements", service_location->elements);
}
예제 #6
0
int dvb_fe_diseqc_reply(struct dvb_v5_fe_parms *p, unsigned *len, char *buf,
		       int timeout)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	struct dvb_diseqc_slave_reply reply;
	int rc;

	if (*len > 4)
		*len = 4;

	reply.timeout = timeout;
	reply.msg_len = *len;

	if (parms->p.verbose)
		dvb_log("DiSEqC FE_DISEQC_RECV_SLAVE_REPLY");

	rc = xioctl(parms->fd, FE_DISEQC_RECV_SLAVE_REPLY, reply);
	if (rc == -1) {
		dvb_perror("FE_DISEQC_RECV_SLAVE_REPLY");
		return rc;
	}

	*len = reply.msg_len;
	memcpy(buf, reply.msg, reply.msg_len);

	return 0;
}
예제 #7
0
int dvb_fe_diseqc_cmd(struct dvb_v5_fe_parms *p, const unsigned len,
		      const unsigned char *buf)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	struct dvb_diseqc_master_cmd msg;
	int rc;

	if (len > 6)
		return -EINVAL;

	msg.msg_len = len;
	memcpy(msg.msg, buf, len);

	if (parms->p.verbose) {
		int i;
		char log[len * 3 + 20], *p = log;

		p += sprintf(p, _("DiSEqC command: "));
		for (i = 0; i < len; i++)
			p += sprintf (p, "%02x ", buf[i]);
		dvb_log("%s", log);
	}

	rc = xioctl(parms->fd, FE_DISEQC_SEND_MASTER_CMD, &msg);
	if (rc == -1)
		dvb_perror("FE_DISEQC_SEND_MASTER_CMD");
	return rc;
}
예제 #8
0
void dvb_desc_sat_print(struct dvb_v5_fe_parms *parms, const struct dvb_desc *desc)
{
	const struct dvb_desc_sat *sat = (const struct dvb_desc_sat *) desc;
	char pol;
	switch(sat->polarization) {
		case 0:
			pol = 'H';
			break;
		case 1:
			pol = 'V';
			break;
		case 2:
			pol = 'L';
			break;
		case 3:
			pol = 'R';
			break;
	}
	dvb_log("|           modulation_system %s", sat->modulation_system ? "DVB-S2" : "DVB-S");
	dvb_log("|           frequency         %d %c", sat->frequency, pol);
	dvb_log("|           symbol_rate       %d", sat->symbol_rate);
	dvb_log("|           fec               %d", sat->fec);
	dvb_log("|           modulation_type   %d", sat->modulation_type);
	dvb_log("|           roll_off          %d", sat->roll_off);
	dvb_log("|           orbit             %.1f %c", (float) sat->orbit / 10.0, sat->west_east ? 'E' : 'W');
}
예제 #9
0
int dvb_fe_set_default_country(struct dvb_v5_fe_parms *p, const char *cc)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;

	if (!cc) {
		parms->country = dvb_guess_user_country();
		if (parms->p.verbose) {
			if (parms->country != COUNTRY_UNKNOWN)
				dvb_log(_("Assuming you're in %s.\n"),
					dvb_country_to_2letters(parms->country));
			else
				dvb_log(_("Failed to guess country from the current locale setting.\n"));
		}
		return 0;
	}

	parms->country = dvb_country_a2_to_id(cc);
	return (parms->country == COUNTRY_UNKNOWN) ? -EINVAL : 0;
}
예제 #10
0
int dvb_fe_sec_tone(struct dvb_v5_fe_parms *p, fe_sec_tone_mode_t tone)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	int rc;
	if (parms->p.verbose)
		dvb_log( _("DiSEqC TONE: %s"), fe_tone_name[tone] );
	rc = xioctl(parms->fd, FE_SET_TONE, tone);
	if (rc == -1)
		dvb_perror("FE_SET_TONE");
	return rc;
}
예제 #11
0
int dvb_fe_sec_voltage(struct dvb_v5_fe_parms *p, int on, int v18)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	fe_sec_voltage_t v;
	int rc;

	if (!on) {
		v = SEC_VOLTAGE_OFF;
		if (parms->p.verbose)
			dvb_log(_("DiSEqC VOLTAGE: OFF"));
	} else {
		v = v18 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13;
		if (parms->p.verbose)
			dvb_log(_("DiSEqC VOLTAGE: %s"), v18 ? "18" : "13");
	}
	rc = xioctl(parms->fd, FE_SET_VOLTAGE, v);
	if (rc == -1)
		dvb_perror("FE_SET_VOLTAGE");
	return rc;
}
예제 #12
0
void isdb_desc_partial_reception_print(struct dvb_v5_fe_parms *parms, const struct dvb_desc *desc)
{
	struct isdb_desc_partial_reception *d = (void *)desc;
	int i;
	size_t len;

	len = d->length / sizeof(d->partial_reception);

	for (i = 0; i < len; i++) {
		dvb_log("|           service ID[%d]     %d", i, d->partial_reception[i].service_id);
	}
}
예제 #13
0
void dvb_desc_cable_delivery_print(struct dvb_v5_fe_parms *parms, const struct dvb_desc *desc)
{
	const struct dvb_desc_cable_delivery *cable = (const struct dvb_desc_cable_delivery *) desc;
	dvb_log("|        cable delivery");
	dvb_log("|           length            %d", cable->length);
	dvb_log("|           frequency         %d", cable->frequency);
	dvb_log("|           fec outer         %d", cable->fec_outer);
	dvb_log("|           modulation        %d", cable->modulation);
	dvb_log("|           symbol_rate       %d", cable->symbol_rate);
	dvb_log("|           fec inner         %d", cable->fec_inner);
}
예제 #14
0
int dvb_fe_lnb_high_voltage(struct dvb_v5_fe_parms *p, int on)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	int rc;

	if (on) on = 1;
	if (parms->p.verbose)
		dvb_log( _("DiSEqC HIGH LNB VOLTAGE: %s"), on ? _("ON") : _("OFF") );
	rc = xioctl(parms->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, on);
	if (rc == -1)
		dvb_perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
	return rc;
}
예제 #15
0
파일: sdt.c 프로젝트: llmike/v4l2-tools
void dvb_table_sdt_print(struct dvb_v5_fe_parms *parms, struct dvb_table_sdt *sdt)
{
	dvb_log("SDT");
	dvb_table_header_print(parms, &sdt->header);
	dvb_log("|- network_id         %d", sdt->network_id);
	dvb_log("|\\  service_id");
	const struct dvb_table_sdt_service *service = sdt->service;
	uint16_t services = 0;
	while(service) {
		dvb_log("|- %7d", service->service_id);
		dvb_log("|   EIT schedule          %d", service->EIT_schedule);
		dvb_log("|   EIT present following %d", service->EIT_present_following);
		dvb_log("|   free CA mode          %d", service->free_CA_mode);
		dvb_log("|   running status        %d", service->running_status);
		dvb_print_descriptors(parms, service->descriptor);
		service = service->next;
		services++;
	}
	dvb_log("|_  %d services", services);
}
예제 #16
0
int dvb_fe_diseqc_burst(struct dvb_v5_fe_parms *p, int mini_b)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	fe_sec_mini_cmd_t mini;
	int rc;

	mini = mini_b ? SEC_MINI_B : SEC_MINI_A;

	if (parms->p.verbose)
		dvb_log( _("DiSEqC BURST: %s"), mini_b ? "SEC_MINI_B" : "SEC_MINI_A" );
	rc = xioctl(parms->fd, FE_DISEQC_SEND_BURST, mini);
	if (rc == -1)
		dvb_perror("FE_DISEQC_SEND_BURST");
	return rc;
}
예제 #17
0
struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
					  unsigned verbose,
					  unsigned use_legacy_call,
					  dvb_logfunc logfunc,
					  int flags)
{
	int fd, i, r;
	char *fname;
	struct dtv_properties dtv_prop;
	struct dvb_v5_fe_parms_priv *parms = NULL;

	libdvbv5_initialize();

	if (logfunc == NULL)
		logfunc = dvb_default_log;

	r = asprintf(&fname, "/dev/dvb/adapter%i/frontend%i", adapter, frontend);
	if (r < 0) {
		logfunc(LOG_ERR, _("asprintf error"));
		return NULL;
	}
	if (!fname) {
		logfunc(LOG_ERR, _("fname calloc: %s"), strerror(errno));
		return NULL;
	}

	fd = open(fname, flags, 0);
	if (fd == -1) {
		logfunc(LOG_ERR, _("%s while opening %s"), strerror(errno), fname);
		free(fname);
		return NULL;
	}
	parms = calloc(sizeof(*parms), 1);
	if (!parms) {
		logfunc(LOG_ERR, _("parms calloc: %s"), strerror(errno));
		close(fd);
		free(fname);
		return NULL;
	}
	parms->fname = fname;
	parms->fd = fd;
	parms->fe_flags = flags;
	parms->p.verbose = verbose;
	parms->p.default_charset = "iso-8859-1";
	parms->p.output_charset = "utf-8";
	parms->p.logfunc = logfunc;
	parms->p.lna = LNA_AUTO;
	parms->p.sat_number = -1;
	parms->p.abort = 0;
	parms->country = COUNTRY_UNKNOWN;

	if (xioctl(fd, FE_GET_INFO, &parms->p.info) == -1) {
		dvb_perror("FE_GET_INFO");
		dvb_v5_free(parms);
		close(fd);
		free(fname);
		return NULL;
	}

	if (verbose) {
		fe_caps_t caps = parms->p.info.caps;

		dvb_log(_("Device %s (%s) capabilities:"),
			parms->p.info.name, fname);
		for (i = 0; i < ARRAY_SIZE(fe_caps_name); i++) {
			if (caps & fe_caps_name[i].idx)
				dvb_log ("     %s", fe_caps_name[i].name);
		}
	}

	parms->dvb_prop[0].cmd = DTV_API_VERSION;
	parms->dvb_prop[1].cmd = DTV_DELIVERY_SYSTEM;

	dtv_prop.num = 2;
	dtv_prop.props = parms->dvb_prop;

	/* Detect a DVBv3 device */
	if (xioctl(fd, FE_GET_PROPERTY, &dtv_prop) == -1) {
		parms->dvb_prop[0].u.data = 0x300;
		parms->dvb_prop[1].u.data = SYS_UNDEFINED;
	}

	parms->p.version = parms->dvb_prop[0].u.data;
	parms->p.current_sys = parms->dvb_prop[1].u.data;
	if (verbose)
		dvb_log (_("DVB API Version %d.%d%s, Current v5 delivery system: %s"),
			parms->p.version / 256,
			parms->p.version % 256,
			use_legacy_call ? _(" (forcing DVBv3 calls)") : "",
			delivery_system_name[parms->p.current_sys]);

	if (parms->p.version < 0x500)
		use_legacy_call = 1;

	if (parms->p.version >= 0x50a)
		parms->p.has_v5_stats = 1;
	else
		parms->p.has_v5_stats = 0;

	if (use_legacy_call || parms->p.version < 0x505) {
		parms->p.legacy_fe = 1;
		switch(parms->p.info.type) {
		case FE_QPSK:
			parms->p.current_sys = SYS_DVBS;
			parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
			if (parms->p.version < 0x0500)
				break;
			if (parms->p.info.caps & FE_CAN_2G_MODULATION)
				parms->p.systems[parms->p.num_systems++] = SYS_DVBS2;
			if (parms->p.info.caps & FE_CAN_TURBO_FEC)
				parms->p.systems[parms->p.num_systems++] = SYS_TURBO;
			break;
		case FE_QAM:
			parms->p.current_sys = SYS_DVBC_ANNEX_A;
			parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
			break;
		case FE_OFDM:
			parms->p.current_sys = SYS_DVBT;
			parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
			if (parms->p.version < 0x0500)
				break;
			if (parms->p.info.caps & FE_CAN_2G_MODULATION)
				parms->p.systems[parms->p.num_systems++] = SYS_DVBT2;
			break;
		case FE_ATSC:
			if (parms->p.info.caps & (FE_CAN_8VSB | FE_CAN_16VSB))
				parms->p.systems[parms->p.num_systems++] = SYS_ATSC;
			if (parms->p.info.caps & (FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO))
				parms->p.systems[parms->p.num_systems++] = SYS_DVBC_ANNEX_B;
			parms->p.current_sys = parms->p.systems[0];
			break;
		}
		if (!parms->p.num_systems) {
			dvb_logerr(_("delivery system not detected"));
			dvb_v5_free(parms);
			close(fd);
			return NULL;
		}
	} else {
		parms->dvb_prop[0].cmd = DTV_ENUM_DELSYS;
		parms->n_props = 1;
		dtv_prop.num = 1;
		dtv_prop.props = parms->dvb_prop;
		if (xioctl(fd, FE_GET_PROPERTY, &dtv_prop) == -1) {
			dvb_perror("FE_GET_PROPERTY");
			dvb_v5_free(parms);
			close(fd);
			return NULL;
		}
		parms->p.num_systems = parms->dvb_prop[0].u.buffer.len;
		for (i = 0; i < parms->p.num_systems; i++)
			parms->p.systems[i] = parms->dvb_prop[0].u.buffer.data[i];

		if (parms->p.num_systems == 0) {
			dvb_logerr(_("driver returned 0 supported delivery systems!"));
			dvb_v5_free(parms);
			close(fd);
			return NULL;
		}
	}

	if (verbose) {
		dvb_log(_("Supported delivery system%s: "),
		       (parms->p.num_systems > 1) ? "s" : "");
		for (i = 0; i < parms->p.num_systems; i++) {
			if (parms->p.systems[i] == parms->p.current_sys)
				dvb_log ("    [%s]",
					delivery_system_name[parms->p.systems[i]]);
			else
				dvb_log ("     %s",
					delivery_system_name[parms->p.systems[i]]);
		}
		if (use_legacy_call || parms->p.version < 0x505)
			dvb_log(_("Warning: new delivery systems like ISDB-T, ISDB-S, DMB-TH, DSS, ATSC-MH will be miss-detected by a DVBv5.4 or earlier API call"));
	}

	/*
	 * Fix a bug at some DVB drivers
	 */
	if (parms->p.current_sys == SYS_UNDEFINED)
		parms->p.current_sys = parms->p.systems[0];

	/* Prepare to use the delivery system */
	parms->n_props = dvb_add_parms_for_sys(&parms->p, parms->p.current_sys);

	if ((flags & O_ACCMODE) == O_RDWR)
		dvb_set_sys(&parms->p, parms->p.current_sys);

	/*
	 * Prepare the status struct - DVBv5.10 parameters should
	 * come first, as they'll be read together.
	 */
	parms->stats.prop[0].cmd = DTV_STAT_SIGNAL_STRENGTH;
	parms->stats.prop[1].cmd = DTV_STAT_CNR;
	parms->stats.prop[2].cmd = DTV_STAT_PRE_ERROR_BIT_COUNT;
	parms->stats.prop[3].cmd = DTV_STAT_PRE_TOTAL_BIT_COUNT;
	parms->stats.prop[4].cmd = DTV_STAT_POST_ERROR_BIT_COUNT;
	parms->stats.prop[5].cmd = DTV_STAT_POST_TOTAL_BIT_COUNT;
	parms->stats.prop[6].cmd = DTV_STAT_ERROR_BLOCK_COUNT;
	parms->stats.prop[7].cmd = DTV_STAT_TOTAL_BLOCK_COUNT;

	/* Now, status and the calculated stats */
	parms->stats.prop[8].cmd = DTV_STATUS;
	parms->stats.prop[9].cmd = DTV_BER;
	parms->stats.prop[10].cmd = DTV_PER;
	parms->stats.prop[11].cmd = DTV_QUALITY;
	parms->stats.prop[12].cmd = DTV_PRE_BER;

	return &parms->p;
}
예제 #18
0
static int run_scan(struct arguments *args,
		    struct dvb_v5_fe_parms *parms)
{
	struct dvb_file *dvb_file = NULL, *dvb_file_new = NULL;
	struct dvb_entry *entry;
	int i, rc, count = 0, dmx_fd, shift;
	uint32_t freq, sys;

	/* This is used only when reading old formats */
	switch (parms->current_sys) {
	case SYS_DVBT:
	case SYS_DVBS:
	case SYS_DVBC_ANNEX_A:
	case SYS_ATSC:
		sys = parms->current_sys;
		break;
	case SYS_DVBC_ANNEX_C:
		sys = SYS_DVBC_ANNEX_A;
		break;
	case SYS_DVBC_ANNEX_B:
		sys = SYS_ATSC;
		break;
	case SYS_ISDBT:
		sys = SYS_DVBT;
		break;
	default:
		sys = SYS_UNDEFINED;
		break;
	}
	dvb_file = dvb_read_file_format(args->confname, sys,
				    args->input_format);
	if (!dvb_file)
		return -2;

	dmx_fd = open(args->demux_dev, O_RDWR);
	if (dmx_fd < 0) {
		perror("openening pat demux failed");
		return -3;
	}

	for (entry = dvb_file->first_entry; entry != NULL; entry = entry->next) {
		struct dvb_v5_descriptors *dvb_desc = NULL;

		/* First of all, set the delivery system */
		for (i = 0; i < entry->n_props; i++)
			if (entry->props[i].cmd == DTV_DELIVERY_SYSTEM)
				dvb_set_compat_delivery_system(parms,
							       entry->props[i].u.data);

		/* Copy data into parms */
		for (i = 0; i < entry->n_props; i++) {
			uint32_t data = entry->props[i].u.data;

			/* Don't change the delivery system */
			if (entry->props[i].cmd == DTV_DELIVERY_SYSTEM)
				continue;

			dvb_fe_store_parm(parms, entry->props[i].cmd, data);
			if (parms->current_sys == SYS_ISDBT) {
				dvb_fe_store_parm(parms, DTV_ISDBT_PARTIAL_RECEPTION, 0);
				dvb_fe_store_parm(parms, DTV_ISDBT_SOUND_BROADCASTING, 0);
				dvb_fe_store_parm(parms, DTV_ISDBT_LAYER_ENABLED, 0x07);
				if (entry->props[i].cmd == DTV_CODE_RATE_HP) {
					dvb_fe_store_parm(parms, DTV_ISDBT_LAYERA_FEC,
							data);
					dvb_fe_store_parm(parms, DTV_ISDBT_LAYERB_FEC,
							data);
					dvb_fe_store_parm(parms, DTV_ISDBT_LAYERC_FEC,
							data);
				} else if (entry->props[i].cmd == DTV_MODULATION) {
					dvb_fe_store_parm(parms,
							DTV_ISDBT_LAYERA_MODULATION,
							data);
					dvb_fe_store_parm(parms,
							DTV_ISDBT_LAYERB_MODULATION,
							data);
					dvb_fe_store_parm(parms,
							DTV_ISDBT_LAYERC_MODULATION,
							data);
				}
			}
			if (parms->current_sys == SYS_ATSC &&
			    entry->props[i].cmd == DTV_MODULATION) {
				if (data != VSB_8 && data != VSB_16)
					dvb_fe_store_parm(parms,
							DTV_DELIVERY_SYSTEM,
							SYS_DVBC_ANNEX_B);
			}
		}

		/*
		 * If the channel file has duplicated frequencies, or some
		 * entries without any frequency at all, discard.
		 */
		freq = 0;
		for (i = 0; i < entry->n_props; i++) {
			if (entry->props[i].cmd == DTV_FREQUENCY) {
				freq = entry->props[i].u.data;
				break;
			}
		}
		if (!freq)
			continue;
		shift = estimate_freq_shift(parms);
		if (dvb_desc && !new_freq_is_needed(dvb_file->first_entry, entry,
					freq, dvb_desc->nit_table.pol, shift))
			continue;

		rc = dvb_fe_set_parms(parms);
		if (rc < 0) {
			PERROR("dvb_fe_set_parms failed");
			return -1;
		}

		/* As the DVB core emulates it, better to always use auto */
		dvb_fe_store_parm(parms, DTV_INVERSION, INVERSION_AUTO);

		dvb_fe_retrieve_parm(parms, DTV_FREQUENCY, &freq);
		count++;
		dvb_log("Scanning frequency #%d %d", count, freq);
		if (verbose)
			dvb_fe_prt_parms(parms);

		rc = check_frontend(args, parms);
		if (rc < 0)
			continue;

		dvb_desc = dvb_get_ts_tables(parms, dmx_fd,
					     parms->current_sys,
					     args->other_nit,
					     args->timeout_multiply,
					     verbose);
		if (!dvb_desc)
			continue;

		for (i = 0; i < dvb_desc->sdt_table.service_table_len; i++) {
			struct service_table *service_table = &dvb_desc->sdt_table.service_table[i];

			entry->vchannel = dvb_vchannel(dvb_desc, i);
			printf("Service #%d (%d)", i,
				service_table->service_id);
			if (service_table->service_name)
				printf(" %s", service_table->service_name);
			if (entry->vchannel)
				printf(" channel %s", entry->vchannel);
			printf("\n");
		}

		store_dvb_channel(&dvb_file_new, parms, dvb_desc,
				  args->get_detected, args->get_nit);

		if (!args->dont_add_new_freqs)
			add_other_freq_entries(dvb_file, parms, dvb_desc);

		dvb_free_ts_tables(dvb_desc);
	}

	if (dvb_file_new)
		write_file_format(args->output, dvb_file_new,
				  parms->current_sys, args->output_format);

	dvb_file_free(dvb_file);
	if (dvb_file_new)
		dvb_file_free(dvb_file_new);

	close(dmx_fd);
	return 0;
}
예제 #19
0
static int run_scan(struct arguments *args,
		    struct dvb_v5_fe_parms *parms)
{
	struct dvb_file *dvb_file = NULL, *dvb_file_new = NULL;
	struct dvb_entry *entry;
	int count = 0, dmx_fd, shift;
	uint32_t freq, sys;
	enum dvb_sat_polarization pol;

	/* This is used only when reading old formats */
	switch (parms->current_sys) {
	case SYS_DVBT:
	case SYS_DVBS:
	case SYS_DVBC_ANNEX_A:
	case SYS_ATSC:
		sys = parms->current_sys;
		break;
	case SYS_DVBC_ANNEX_C:
		sys = SYS_DVBC_ANNEX_A;
		break;
	case SYS_DVBC_ANNEX_B:
		sys = SYS_ATSC;
		break;
	case SYS_ISDBT:
	case SYS_DTMB:
		sys = SYS_DVBT;
		break;
	default:
		sys = SYS_UNDEFINED;
		break;
	}
	dvb_file = dvb_read_file_format(args->confname, sys,
				    args->input_format);
	if (!dvb_file)
		return -2;

	dmx_fd = open(args->demux_dev, O_RDWR);
	if (dmx_fd < 0) {
		perror(_("openening pat demux failed"));
		return -3;
	}

	for (entry = dvb_file->first_entry; entry != NULL; entry = entry->next) {
		struct dvb_v5_descriptors *dvb_scan_handler = NULL;
		uint32_t stream_id;

		/*
		 * If the channel file has duplicated frequencies, or some
		 * entries without any frequency at all, discard.
		 */
		if (dvb_retrieve_entry_prop(entry, DTV_FREQUENCY, &freq))
			continue;
		shift = dvb_estimate_freq_shift(parms);

		if (dvb_retrieve_entry_prop(entry, DTV_POLARIZATION, &pol))
			pol = POLARIZATION_OFF;

		if (dvb_retrieve_entry_prop(entry, DTV_STREAM_ID, &stream_id))
			stream_id = NO_STREAM_ID_FILTER;

		if (!dvb_new_entry_is_needed(dvb_file->first_entry, entry,
						  freq, shift, pol, stream_id))
			continue;

		count++;
		dvb_log(_("Scanning frequency #%d %d"), count, freq);

		/*
		 * update params->lnb only if it differs from entry->lnb
		 * (and "--lnbf" option was not provided),
		 * to avoid linear search of LNB types for every entries.
		 */
		if (!args->lnb_name && entry->lnb &&
		    (!parms->lnb || strcasecmp(entry->lnb, parms->lnb->alias)))
			parms->lnb = dvb_sat_get_lnb(dvb_sat_search_lnb(entry->lnb));

		/*
		 * Run the scanning logic
		 */

		dvb_scan_handler = dvb_scan_transponder(parms, entry, dmx_fd,
							&check_frontend, args,
							args->other_nit,
							args->timeout_multiply);

		if (parms->abort) {
			dvb_scan_free_handler_table(dvb_scan_handler);
			break;
		}
		if (!dvb_scan_handler)
			continue;

		/*
		 * Store the service entry
		 */
		dvb_store_channel(&dvb_file_new, parms, dvb_scan_handler,
				  args->get_detected, args->get_nit);

		/*
		 * Add new transponders based on NIT table information
		 */
		if (!args->dont_add_new_freqs)
			dvb_add_scaned_transponders(parms, dvb_scan_handler,
						    dvb_file->first_entry, entry);

		/*
		 * Free the scan handler associated with the transponder
		 */

		dvb_scan_free_handler_table(dvb_scan_handler);
	}

	if (dvb_file_new)
		dvb_write_file_format(args->output, dvb_file_new,
				      parms->current_sys, args->output_format);

	dvb_file_free(dvb_file);
	if (dvb_file_new)
		dvb_file_free(dvb_file_new);

	close(dmx_fd);
	return 0;
}
예제 #20
0
static int run_scan(struct arguments *args,
		    struct dvb_v5_fe_parms *parms)
{
	struct dvb_file *dvb_file = NULL, *dvb_file_new = NULL;
	struct dvb_entry *entry;
	int count = 0, dmx_fd, shift;
	uint32_t freq, sys;
	enum dvb_sat_polarization pol;

	/* This is used only when reading old formats */
	switch (parms->current_sys) {
	case SYS_DVBT:
	case SYS_DVBS:
	case SYS_DVBC_ANNEX_A:
	case SYS_ATSC:
		sys = parms->current_sys;
		break;
	case SYS_DVBC_ANNEX_C:
		sys = SYS_DVBC_ANNEX_A;
		break;
	case SYS_DVBC_ANNEX_B:
		sys = SYS_ATSC;
		break;
	case SYS_ISDBT:
		sys = SYS_DVBT;
		break;
	default:
		sys = SYS_UNDEFINED;
		break;
	}
	dvb_file = dvb_read_file_format(args->confname, sys,
				    args->input_format);
	if (!dvb_file)
		return -2;

	dmx_fd = open(args->demux_dev, O_RDWR);
	if (dmx_fd < 0) {
		perror("openening pat demux failed");
		return -3;
	}

	for (entry = dvb_file->first_entry; entry != NULL; entry = entry->next) {
		struct dvb_v5_descriptors *dvb_scan_handler = NULL;

		/*
		 * If the channel file has duplicated frequencies, or some
		 * entries without any frequency at all, discard.
		 */
		if (retrieve_entry_prop(entry, DTV_FREQUENCY, &freq))
			continue;

		shift = estimate_freq_shift(parms);

		if (retrieve_entry_prop(entry, DTV_POLARIZATION, &pol))
			pol = POLARIZATION_OFF;

		if (!new_freq_is_needed(dvb_file->first_entry, entry,
					freq, pol, shift))
			continue;

		count++;
		dvb_log("Scanning frequency #%d %d", count, freq);

		/*
		 * Run the scanning logic
		 */

		dvb_scan_handler = dvb_scan_transponder(parms, entry, dmx_fd,
							&check_frontend, args,
							args->other_nit,
							args->timeout_multiply);

		if (parms->abort) {
			dvb_scan_free_handler_table(dvb_scan_handler);
			break;
		}
		if (!dvb_scan_handler)
			continue;

		/*
		 * Store the service entry
		 */
		store_dvb_channel(&dvb_file_new, parms, dvb_scan_handler,
				  args->get_detected, args->get_nit);

		/*
		 * Add new transponders based on NIT table information
		 */
		if (!args->dont_add_new_freqs)
			dvb_add_scaned_transponders(parms, dvb_scan_handler,
						    dvb_file->first_entry, entry);

		/*
		 * Free the scan handler associated with the transponder
		 */

		dvb_scan_free_handler_table(dvb_scan_handler);
	}

	if (dvb_file_new)
		write_file_format(args->output, dvb_file_new,
				  parms->current_sys, args->output_format);

	dvb_file_free(dvb_file);
	if (dvb_file_new)
		dvb_file_free(dvb_file_new);

	close(dmx_fd);
	return 0;
}
예제 #21
0
void dvb_desc_default_print(struct dvb_v5_fe_parms *parms, const struct dvb_desc *desc)
{
	dvb_log("|                   %s (%d)", dvb_descriptors[desc->type].name, desc->type);
	hexdump(parms, "|                       ", desc->data, desc->length);
}
예제 #22
0
void atsc_table_header_print(struct dvb_v5_fe_parms *parms, const struct atsc_table_header *t)
{
	dvb_log("| table_id         %02x", t->table_id);
	dvb_log("| section_length   %d", t->section_length);
	dvb_log("| syntax           %d", t->syntax);
	dvb_log("| priv             %d", t->priv);
	dvb_log("| one              %d", t->one);
	dvb_log("| id               %d", t->id);
	dvb_log("| one2             %d", t->one2);
	dvb_log("| version          %d", t->version);
	dvb_log("| current_next     %d", t->current_next);
	dvb_log("| section_id       %d", t->section_id);
	dvb_log("| last_section     %d", t->last_section);
	dvb_log("| protocol_version %d", t->protocol_version);
}
예제 #23
0
void dvb_desc_event_extended_print(struct dvb_v5_fe_parms *parms, const struct dvb_desc *desc)
{
	const struct dvb_desc_event_extended *event = (const struct dvb_desc_event_extended *) desc;
	dvb_log("|   Description   '%s'", event->text);
}
예제 #24
0
int dvb_set_compat_delivery_system(struct dvb_v5_fe_parms *p,
				   uint32_t desired_system)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	int i;
	uint32_t delsys = SYS_UNDEFINED;
	enum dvbv3_emulation_type type;

	/* Check if the desired delivery system is supported */
	for (i = 0; i < parms->p.num_systems; i++) {
		if (parms->p.systems[i] == desired_system) {
			dvb_set_sys(&parms->p, desired_system);
			return 0;
		}
	}

	/*
	 * Find the closest DVBv3 system that matches the delivery
	 * system.
	 */
	type = dvbv3_type(desired_system);

	/*
	 * Get the last non-DVBv3 delivery system that has the same type
	 * of the desired system
	 */
	for (i = 0; i < parms->p.num_systems; i++) {
		if ((dvbv3_type(parms->p.systems[i]) == type) &&
		    !is_dvbv3_delsys(parms->p.systems[i]))
			delsys = parms->p.systems[i];
	}

	if (delsys == SYS_UNDEFINED)
		return EINVAL;

	dvb_log(_("Using a DVBv3 compat file for %s"), delivery_system_name[delsys]);

	dvb_set_sys(&parms->p, delsys);

	/* Put ISDB-T into auto mode */
	if (delsys == SYS_ISDBT) {
		dvb_fe_store_parm(&parms->p, DTV_BANDWIDTH_HZ, 6000000);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_PARTIAL_RECEPTION, 0);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_SOUND_BROADCASTING, 0);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_SB_SUBCHANNEL_ID, 0);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_SB_SEGMENT_IDX, 0);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_SB_SEGMENT_COUNT, 0);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYER_ENABLED, 7);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_FEC, FEC_AUTO);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_FEC, FEC_AUTO);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_FEC, FEC_AUTO);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_MODULATION, QAM_AUTO);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_MODULATION, QAM_AUTO);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_MODULATION, QAM_AUTO);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0);
		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0);
	}
	return 0;
}
예제 #25
0
파일: vct.c 프로젝트: palosaari/v4l-utils
void atsc_table_vct_print(struct dvb_v5_fe_parms *parms, struct atsc_table_vct *vct)
{
	if (vct->header.table_id == ATSC_TABLE_CVCT)
		dvb_log("CVCT");
	else
		dvb_log("TVCT");

	atsc_table_header_print(parms, &vct->header);

	dvb_log("|- Protocol version %d", vct->ATSC_protocol_version);
	dvb_log("|- #channels        %d", vct->num_channels_in_section);
	dvb_log("|\\  channel_id");
	const struct atsc_table_vct_channel *channel = vct->channel;
	uint16_t channels = 0;
	while(channel) {
		dvb_log("|- Channel                %d.%d: %s",
			channel->major_channel_number,
			channel->minor_channel_number,
			channel->short_name);
		dvb_log("|   modulation mode       %d", channel->modulation_mode);
		dvb_log("|   carrier frequency     %d", channel->carrier_frequency);
		dvb_log("|   TS ID                 %d", channel->channel_tsid);
		dvb_log("|   program number        %d", channel->program_number);

		dvb_log("|   ETM location          %d", channel->ETM_location);
		dvb_log("|   access controlled     %d", channel->access_controlled);
		dvb_log("|   hidden                %d", channel->hidden);

		if (vct->header.table_id == ATSC_TABLE_CVCT) {
			dvb_log("|   path select           %d", channel->path_select);
			dvb_log("|   out of band           %d", channel->out_of_band);
		}
		dvb_log("|   hide guide            %d", channel->hide_guide);
		dvb_log("|   service type          %d", channel->service_type);
		dvb_log("|   source id            %d", channel->source_id);

		dvb_print_descriptors(parms, channel->descriptor);
		channel = channel->next;
		channels++;
	}
	dvb_log("|_  %d channels", channels);
}
void dvb_desc_terrestrial_delivery_print(struct dvb_v5_fe_parms *parms, const struct dvb_desc *desc)
{
	const struct dvb_desc_terrestrial_delivery *tdel = (const struct dvb_desc_terrestrial_delivery *) desc;
	dvb_log("|       terrestrial delivery");
	dvb_log("|           length                %d", tdel->length);
	dvb_log("|           centre frequency      %d", tdel->centre_frequency * 10);
	dvb_log("|           mpe_fec_indicator     %d", tdel->mpe_fec_indicator);
	dvb_log("|           time_slice_indicator  %d", tdel->time_slice_indicator);
	dvb_log("|           priority              %d", tdel->priority);
	dvb_log("|           bandwidth             %d", tdel->bandwidth);
	dvb_log("|           code_rate_hp_stream   %d", tdel->code_rate_hp_stream);
	dvb_log("|           hierarchy_information %d", tdel->hierarchy_information);
	dvb_log("|           constellation         %d", tdel->constellation);
	dvb_log("|           other_frequency_flag  %d", tdel->other_frequency_flag);
	dvb_log("|           transmission_mode     %d", tdel->transmission_mode);
	dvb_log("|           guard_interval        %d", tdel->guard_interval);
	dvb_log("|           code_rate_lp_stream   %d", tdel->code_rate_lp_stream);
}
예제 #27
0
int dvb_fe_get_parms(struct dvb_v5_fe_parms *p)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	int i, n = 0;
	const unsigned int *sys_props;
	struct dtv_properties prop;
	struct dvb_frontend_parameters v3_parms;
	uint32_t bw;

	sys_props = dvb_v5_delivery_system[parms->p.current_sys];
	if (!sys_props)
		return EINVAL;

	while (sys_props[n]) {
		parms->dvb_prop[n].cmd = sys_props[n];
		n++;
	}
	parms->dvb_prop[n].cmd = DTV_DELIVERY_SYSTEM;
	parms->dvb_prop[n].u.data = parms->p.current_sys;
	n++;

	/* Keep it ready for set */
	parms->dvb_prop[n].cmd = DTV_TUNE;
	parms->n_props = n;

	struct dtv_property fe_prop[DTV_MAX_COMMAND];
	n = dvb_copy_fe_props(parms->dvb_prop, n, fe_prop);

	prop.props = fe_prop;
	prop.num = n;
	if (!parms->p.legacy_fe) {
		if (xioctl(parms->fd, FE_GET_PROPERTY, &prop) == -1) {
			dvb_perror("FE_GET_PROPERTY");
			return errno;
		}

		/* copy back params from temporary fe_prop */
		for (i = 0; i < n; i++) {
			if (dvb_fe_is_satellite(p->current_sys)
			    && fe_prop[i].cmd == DTV_FREQUENCY)
				fe_prop[i].u.data += parms->freq_offset;
			dvb_fe_store_parm(&parms->p, fe_prop[i].cmd, fe_prop[i].u.data);
		}

		if (parms->p.verbose) {
			dvb_log(_("Got parameters for %s:"),
			       delivery_system_name[parms->p.current_sys]);
			dvb_fe_prt_parms(&parms->p);
		}
		return 0;
	}
	/* DVBv3 call */
	if (xioctl(parms->fd, FE_GET_FRONTEND, &v3_parms) == -1) {
		dvb_perror("FE_GET_FRONTEND");
		return EINVAL;
	}

	dvb_fe_store_parm(&parms->p, DTV_FREQUENCY, v3_parms.frequency);
	dvb_fe_store_parm(&parms->p, DTV_INVERSION, v3_parms.inversion);
	switch (parms->p.current_sys) {
	case SYS_DVBS:
		dvb_fe_store_parm(&parms->p, DTV_SYMBOL_RATE, v3_parms.u.qpsk.symbol_rate);
		dvb_fe_store_parm(&parms->p, DTV_INNER_FEC, v3_parms.u.qpsk.fec_inner);
		break;
	case SYS_DVBC_ANNEX_A:
		dvb_fe_store_parm(&parms->p, DTV_SYMBOL_RATE, v3_parms.u.qam.symbol_rate);
		dvb_fe_store_parm(&parms->p, DTV_INNER_FEC, v3_parms.u.qam.fec_inner);
		dvb_fe_store_parm(&parms->p, DTV_MODULATION, v3_parms.u.qam.modulation);
		break;
	case SYS_ATSC:
	case SYS_ATSCMH:
	case SYS_DVBC_ANNEX_B:
		dvb_fe_store_parm(&parms->p, DTV_MODULATION, v3_parms.u.vsb.modulation);
		break;
	case SYS_DVBT:
		if (v3_parms.u.ofdm.bandwidth < ARRAY_SIZE(fe_bandwidth_name) -1)
			bw = fe_bandwidth_name[v3_parms.u.ofdm.bandwidth];
		else bw = 0;
		dvb_fe_store_parm(&parms->p, DTV_BANDWIDTH_HZ, bw);
		dvb_fe_store_parm(&parms->p, DTV_CODE_RATE_HP, v3_parms.u.ofdm.code_rate_HP);
		dvb_fe_store_parm(&parms->p, DTV_CODE_RATE_LP, v3_parms.u.ofdm.code_rate_LP);
		dvb_fe_store_parm(&parms->p, DTV_MODULATION, v3_parms.u.ofdm.constellation);
		dvb_fe_store_parm(&parms->p, DTV_TRANSMISSION_MODE, v3_parms.u.ofdm.transmission_mode);
		dvb_fe_store_parm(&parms->p, DTV_GUARD_INTERVAL, v3_parms.u.ofdm.guard_interval);
		dvb_fe_store_parm(&parms->p, DTV_HIERARCHY, v3_parms.u.ofdm.hierarchy_information);
		break;
	default:
		return EINVAL;
	}

	return 0;
}
예제 #28
0
int dvb_fe_get_stats(struct dvb_v5_fe_parms *p)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	fe_status_t status = 0;
	uint32_t ber= 0, ucb = 0;
	uint16_t strength = 0, snr = 0;
	int i;
	enum fecap_scale_params scale;

	if (xioctl(parms->fd, FE_READ_STATUS, &status) == -1) {
		dvb_perror("FE_READ_STATUS");
		return EINVAL;
	}
	dvb_fe_store_stats(parms, DTV_STATUS, FE_SCALE_RELATIVE, 0, status);

	/* if lock has obtained, get DVB parameters */
	if (status != parms->stats.prev_status) {
		if ((status & FE_HAS_LOCK) &&
		    parms->stats.prev_status != status)
			dvb_fe_get_parms(&parms->p);
		parms->stats.prev_status = status;
	}

	if (parms->p.has_v5_stats) {
		struct dtv_properties props;

		props.num = DTV_NUM_KERNEL_STATS;
		props.props = parms->stats.prop;

		/* Do a DVBv5.10 stats call */
		if (ioctl(parms->fd, FE_GET_PROPERTY, &props) == -1) {
			if (errno == EAGAIN)
				return 0;
			goto dvbv3_fallback;
		}

		/*
		 * All props with len=0 mean that this device doesn't have any
		 * dvbv5 stats. Try the legacy stats instead.
		 */
		for (i = 0; i < props.num; i++)
			if (parms->stats.prop[i].u.st.len)
				break;
		if (i == props.num)
			goto dvbv3_fallback;

		dvb_fe_update_counters(parms);

		return 0;
	}

dvbv3_fallback:
	/* DVB v3 stats */
	parms->p.has_v5_stats = 0;

	if (ioctl(parms->fd, FE_READ_BER, &ber) == -1)
		scale = FE_SCALE_NOT_AVAILABLE;
	else
		scale = FE_SCALE_RELATIVE;

	/*
	 * BER scale on DVBv3 is not defined - different drivers use
	 * different scales, even weird ones, like multiples of 1/65280
	 */
	dvb_fe_store_stats(parms, DTV_BER, scale, 0, ber);

	if (ioctl(parms->fd, FE_READ_SIGNAL_STRENGTH, &strength) == -1)
		scale = FE_SCALE_NOT_AVAILABLE;
	else
		scale = FE_SCALE_RELATIVE;

	dvb_fe_store_stats(parms, DTV_STAT_SIGNAL_STRENGTH, scale, 0, strength);

	if (ioctl(parms->fd, FE_READ_SNR, &snr) == -1)
		scale = FE_SCALE_NOT_AVAILABLE;
	else
		scale = FE_SCALE_RELATIVE;
	dvb_fe_store_stats(parms, DTV_STAT_CNR, scale, 0, snr);

	if (ioctl(parms->fd, FE_READ_UNCORRECTED_BLOCKS, &ucb) == -1)
		scale = FE_SCALE_NOT_AVAILABLE;
	else
		scale = FE_SCALE_COUNTER;
	dvb_fe_store_stats(parms, DTV_STAT_ERROR_BLOCK_COUNT, scale, 0, snr);

	if (parms->p.verbose > 1) {
		dvb_log(_("Status: "));
		for (i = 0; i < ARRAY_SIZE(fe_status_name); i++) {
			if (status & fe_status_name[i].idx)
				dvb_log ("    %s", fe_status_name[i].name);
		}
		dvb_log(_("BER: %d, Strength: %d, SNR: %d, UCB: %d"),
		       ber, strength, snr, ucb);
	}
	return 0;
}