/* set the delsys default/fixed parameters and replace DVBv5 default values */ static void dvb_setup_delsys_default(struct dvb_v5_fe_parms *p) { struct dvb_v5_fe_parms_priv *parms = (void *)p; uint32_t cc; switch (p->current_sys) { case SYS_ISDBT: /* Set country code. */ /* if the default country is not known, fallback to BR */ cc = COUNTRY_UNKNOWN; dvb_fe_retrieve_parm(p, DTV_COUNTRY_CODE, &cc); if (cc == COUNTRY_UNKNOWN) { cc = (parms->country == COUNTRY_UNKNOWN) ? BR : parms->country; dvb_fe_store_parm(p, DTV_COUNTRY_CODE, cc); } switch (cc) { case JP: p->default_charset = "arib-std-b24"; dvb_fe_store_parm(p, DTV_BANDWIDTH_HZ, 6000000); break; /* Americas (SBTVD) */ case AR: case BO: case BR: case CL: case CR: case EC: case GT: case HN: case NI: case PE: case PY: case UY: case VE: p->default_charset = "iso8859-15"; break; } break; case SYS_ISDBS: p->default_charset = "arib-std-b24"; if (!p->lnb) p->lnb = dvb_sat_get_lnb(dvb_sat_search_lnb("110BS")); break; default: break; } }
static int setup_frontend(struct arguments *args, struct dvb_v5_fe_parms *parms) { int rc; uint32_t freq; if (args->silent < 2) { rc = dvb_fe_retrieve_parm(parms, DTV_FREQUENCY, &freq); if (rc < 0) { PERROR("can't get the frequency"); return -1; } fprintf(stderr, "tuning to %i Hz\n", freq); } rc = dvb_fe_set_parms(parms); if (rc < 0) { PERROR("dvb_fe_set_parms failed"); return -1; } return 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; }
static int estimate_freq_shift(struct dvb_v5_fe_parms *parms) { uint32_t shift = 0, bw = 0, symbol_rate, ro; int rolloff = 0; int divisor = 100; /* Need to handle only cable/satellite and ATSC standards */ switch (parms->current_sys) { case SYS_DVBC_ANNEX_A: rolloff = 115; break; case SYS_DVBC_ANNEX_C: rolloff = 115; break; case SYS_DVBS: case SYS_ISDBS: /* FIXME: not sure if this rollof is right for ISDB-S */ divisor = 100000; rolloff = 135; break; case SYS_DVBS2: case SYS_DSS: case SYS_TURBO: divisor = 100000; dvb_fe_retrieve_parm(parms, DTV_ROLLOFF, &ro); switch (ro) { case ROLLOFF_20: rolloff = 120; break; case ROLLOFF_25: rolloff = 125; break; default: case ROLLOFF_AUTO: case ROLLOFF_35: rolloff = 135; break; } break; case SYS_ATSC: case SYS_DVBC_ANNEX_B: bw = 6000000; break; default: break; } if (rolloff) { /* * This is not 100% correct for DVB-S2, as there is a bw * guard interval there but it should be enough for the * purposes of estimating a max frequency shift here. */ dvb_fe_retrieve_parm(parms, DTV_SYMBOL_RATE, &symbol_rate); bw = (symbol_rate * rolloff) / divisor; } if (!bw) dvb_fe_retrieve_parm(parms, DTV_BANDWIDTH_HZ, &bw); /* * If the max frequency shift between two frequencies is below * than the used bandwidth / 8, it should be the same channel. */ shift = bw / 8; return shift; }
bool Frontend::Tune( Transponder &t ) { if( !IsPresent( )) { LogWarn( "device not present '%s'", name.c_str( )); return false; } Lock( ); if( transponder ) { if( transponder == &t ) { usecount++; Unlock( ); return true; } Log( "Frontend busy" ); Unlock( ); return false; } if( !Open( )) { Unlock( ); return false; } state = State_Tuning; transponder = &t; usecount++; Unlock( ); t.SetState( Transponder::State_Tuning ); Log( "Tuning %s", t.toString( ).c_str( )); uint8_t signal, noise; LogWarn( "dvb_set_compat_delivery_system %d", t.GetDelSys( )); int r = dvb_set_compat_delivery_system( fe, t.GetDelSys( )); if( r != 0 ) { LogError( "dvb_set_compat_delivery_system return %d", r ); goto fail; } SetTuneParams( t ); t.GetParams( fe ); LogWarn( "dvb_estimate_freq_shift"); dvb_estimate_freq_shift( fe ); r = dvb_fe_set_parms( fe ); if( r != 0 ) { LogError( "dvb_fe_set_parms failed with %d.", r ); dvb_fe_prt_parms( fe ); goto fail; } dvb_fe_prt_parms( fe ); /* As the DVB core emulates it, better to always use auto */ dvb_fe_store_parm(fe, DTV_INVERSION, INVERSION_AUTO); uint32_t freq; dvb_fe_retrieve_parm(fe, DTV_FREQUENCY, &freq); dvb_fe_prt_parms(fe); if( !GetLockStatus( signal, noise, tune_timeout )) { LogError( "Tuning failed" ); goto fail; } t.SetState( Transponder::State_Tuned ); t.SetSignal( signal, noise ); return true; fail: t.SetState( Transponder::State_TuningFailed ); t.SaveConfig( ); Release( ); return false; }
int dvb_fe_set_parms(struct dvb_v5_fe_parms *p) { struct dvb_v5_fe_parms_priv *parms = (void *)p; /* Use a temporary copy of the parameters so we can safely perform * adjustments for satellite */ struct dvb_v5_fe_parms_priv tmp_parms = *parms; struct dtv_properties prop; struct dvb_frontend_parameters v3_parms; uint32_t bw; if (parms->p.lna != LNA_AUTO && !parms->p.legacy_fe) { struct dvb_v5_fe_parms_priv tmp_lna_parms; memset(&prop, 0, sizeof(prop)); prop.props = tmp_lna_parms.dvb_prop; prop.props[0].cmd = DTV_LNA; prop.props[0].u.data = parms->p.lna; prop.num = 1; if (xioctl(parms->fd, FE_SET_PROPERTY, &prop) == -1) { dvb_perror(_("Setting LNA")); parms->p.lna = LNA_AUTO; } else if (parms->p.lna != LNA_AUTO && parms->p.verbose) dvb_logdbg(_("LNA is %s"), parms->p.lna ? _("ON") : _("OFF")); } if (dvb_fe_is_satellite(tmp_parms.p.current_sys)) { dvb_sat_set_parms(&tmp_parms.p); /* * even though the frequncy prop is kept un-modified here, * a later call to dvb_fe_get_parms() issues FE_GET_PROPERTY * ioctl and overwrites it with the offset-ed value from * the FE. So we need to save the offset here and * re-add it in dvb_fe_get_parms(). * note that dvbv5-{scan,zap} utilities call dvb_fe_get_parms() * indirectly from check_frontend() via dvb_fe_get_stats(). */ parms->freq_offset = tmp_parms.freq_offset; } dvb_setup_delsys_default(p); /* Filter out any user DTV_foo property such as DTV_POLARIZATION */ tmp_parms.n_props = dvb_copy_fe_props(tmp_parms.dvb_prop, tmp_parms.n_props, tmp_parms.dvb_prop); memset(&prop, 0, sizeof(prop)); prop.props = tmp_parms.dvb_prop; prop.num = tmp_parms.n_props; prop.props[prop.num].cmd = DTV_TUNE; prop.num++; if (!parms->p.legacy_fe) { if (xioctl(parms->fd, FE_SET_PROPERTY, &prop) == -1) { dvb_perror("FE_SET_PROPERTY"); if (parms->p.verbose) dvb_fe_prt_parms(&parms->p); return -1; } return 0; } /* DVBv3 call */ dvb_fe_retrieve_parm(&tmp_parms.p, DTV_FREQUENCY, &v3_parms.frequency); dvb_fe_retrieve_parm(&tmp_parms.p, DTV_INVERSION, &v3_parms.inversion); switch (tmp_parms.p.current_sys) { case SYS_DVBS: dvb_fe_retrieve_parm(&tmp_parms.p, DTV_SYMBOL_RATE, &v3_parms.u.qpsk.symbol_rate); dvb_fe_retrieve_parm(&tmp_parms.p, DTV_INNER_FEC, &v3_parms.u.qpsk.fec_inner); break; case SYS_DVBC_ANNEX_AC: dvb_fe_retrieve_parm(&tmp_parms.p, DTV_SYMBOL_RATE, &v3_parms.u.qam.symbol_rate); dvb_fe_retrieve_parm(&tmp_parms.p, DTV_INNER_FEC, &v3_parms.u.qam.fec_inner); dvb_fe_retrieve_parm(&tmp_parms.p, DTV_MODULATION, &v3_parms.u.qam.modulation); break; case SYS_ATSC: case SYS_ATSCMH: case SYS_DVBC_ANNEX_B: dvb_fe_retrieve_parm(&tmp_parms.p, DTV_MODULATION, &v3_parms.u.vsb.modulation); break; case SYS_DVBT: for (bw = 0; fe_bandwidth_name[bw] != 0; bw++) { if (fe_bandwidth_name[bw] == v3_parms.u.ofdm.bandwidth) break; } dvb_fe_retrieve_parm(&tmp_parms.p, DTV_BANDWIDTH_HZ, &bw); dvb_fe_retrieve_parm(&tmp_parms.p, DTV_CODE_RATE_HP, &v3_parms.u.ofdm.code_rate_HP); dvb_fe_retrieve_parm(&tmp_parms.p, DTV_CODE_RATE_LP, &v3_parms.u.ofdm.code_rate_LP); dvb_fe_retrieve_parm(&tmp_parms.p, DTV_MODULATION, &v3_parms.u.ofdm.constellation); dvb_fe_retrieve_parm(&tmp_parms.p, DTV_TRANSMISSION_MODE, &v3_parms.u.ofdm.transmission_mode); dvb_fe_retrieve_parm(&tmp_parms.p, DTV_GUARD_INTERVAL, &v3_parms.u.ofdm.guard_interval); dvb_fe_retrieve_parm(&tmp_parms.p, DTV_HIERARCHY, &v3_parms.u.ofdm.hierarchy_information); break; default: return -1; } if (xioctl(tmp_parms.fd, FE_SET_FRONTEND, &v3_parms) == -1) { dvb_perror("FE_SET_FRONTEND"); if (tmp_parms.p.verbose) dvb_fe_prt_parms(&tmp_parms.p); return -1; } return 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); }
static enum dvb_quality dvbv_fe_cnr_to_quality(struct dvb_v5_fe_parms_priv *parms, struct dtv_stats *cnr) { uint32_t modulation, fec; enum dvb_quality qual = DVB_QUAL_UNKNOWN; switch (cnr->scale) { case FE_SCALE_RELATIVE: if (cnr->uvalue == 65535) return DVB_QUAL_GOOD; else if (cnr->uvalue >= 65535 / 2) return DVB_QUAL_OK; else return DVB_QUAL_POOR; return qual; case FE_SCALE_DECIBEL: break; default: return DVB_QUAL_UNKNOWN; } switch (parms->p.current_sys) { case SYS_DVBC_ANNEX_A: case SYS_DVBC_ANNEX_C: dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &modulation); if (modulation == QAM_AUTO) modulation = QAM_64; /* Assume worse case */ qual = cnr_arr_to_qual(modulation, FEC_NONE, cnr->svalue, dvb_c_cnr_2_qual, ARRAY_SIZE(dvb_c_cnr_2_qual)); break; case SYS_DVBS: dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &fec); qual = cnr_arr_to_qual(QPSK, fec, cnr->svalue, dvb_s_cnr_2_qual, ARRAY_SIZE(dvb_s_cnr_2_qual)); break; case SYS_DVBS2: dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &modulation); dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &fec); qual = cnr_arr_to_qual(modulation, fec, cnr->svalue, dvb_s2_cnr_2_qual, ARRAY_SIZE(dvb_s_cnr_2_qual)); break; case SYS_ISDBT: dvb_fe_retrieve_parm(&parms->p, DTV_ISDBT_LAYERA_MODULATION, &modulation); dvb_fe_retrieve_parm(&parms->p, DTV_ISDBT_LAYERA_FEC, &fec); if (modulation == QAM_AUTO) modulation = QAM_64; /* Assume worse case */ qual = cnr_arr_to_qual(modulation, fec, cnr->svalue, isdb_t_cnr_2_qual, ARRAY_SIZE(isdb_t_cnr_2_qual)); break; case SYS_DVBT: dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &modulation); dvb_fe_retrieve_parm(&parms->p, DTV_CODE_RATE_LP, &fec); qual = cnr_arr_to_qual(modulation, fec, cnr->svalue, dvb_t_cnr_2_qual, ARRAY_SIZE(isdb_t_cnr_2_qual)); break; case SYS_DVBT2: case SYS_TURBO: case SYS_ISDBS: case SYS_DSS: case SYS_DTMB: case SYS_ATSC: case SYS_ATSCMH: case SYS_DVBC_ANNEX_B: default: /* Quality unknown */ break; } return qual; };