Add support for manually configuring DVB multiplexes by entering all tuning parameters

Ticket #37
This commit is contained in:
Andreas Öman 2009-07-18 07:55:43 +00:00
parent e84dbe3acc
commit f774e7b031
6 changed files with 620 additions and 6 deletions

View file

@ -208,6 +208,8 @@ void dvb_adapter_notify(th_dvb_adapter_t *tda);
htsmsg_t *dvb_adapter_build_msg(th_dvb_adapter_t *tda);
htsmsg_t *dvb_fe_opts(th_dvb_adapter_t *tda, const char *which);
/**
* DVB Multiplex
*/
@ -237,6 +239,20 @@ htsmsg_t *dvb_mux_build_msg(th_dvb_mux_instance_t *tdmi);
void dvb_mux_notify(th_dvb_mux_instance_t *tdmi);
const char *dvb_mux_add_by_params(th_dvb_adapter_t *tda,
int freq,
int symrate,
int bw,
int constellation,
int tmode,
int guard,
int hier,
int fechi,
int feclo,
int fec,
int polarisation,
const char *satconf);
/**
* DVB Transport (aka DVB service)
*/

View file

@ -497,6 +497,13 @@ dvb_adapter_input_dvr(void *aux)
}
}
static struct strtab deliverysystemtab[] = {
{"DVB-S", FE_QPSK},
{"DVB-T", FE_OFDM},
{"DVB-C", FE_QAM},
};
/**
*
*/
@ -507,7 +514,6 @@ dvb_adapter_build_msg(th_dvb_adapter_t *tda)
htsmsg_t *m = htsmsg_create_map();
th_dvb_mux_instance_t *tdmi;
th_transport_t *t;
int nummux = 0;
int numsvc = 0;
@ -533,6 +539,9 @@ dvb_adapter_build_msg(th_dvb_adapter_t *tda)
htsmsg_add_str(m, "currentMux", buf);
}
htsmsg_add_str(m, "deliverySystem",
val2str(tda->tda_type, deliverysystemtab) ?: "");
htsmsg_add_u32(m, "satConf", tda->tda_sat);
return m;
}
@ -546,3 +555,106 @@ dvb_adapter_notify(th_dvb_adapter_t *tda)
{
notify_by_msg("dvbAdapter", dvb_adapter_build_msg(tda));
}
/**
*
*/
static void
fe_opts_add(htsmsg_t *a, const char *title, int value)
{
htsmsg_t *v = htsmsg_create_map();
htsmsg_add_str(v, "title", title);
htsmsg_add_u32(v, "id", value);
htsmsg_add_msg(a, NULL, v);
}
/**
*
*/
htsmsg_t *
dvb_fe_opts(th_dvb_adapter_t *tda, const char *which)
{
htsmsg_t *a = htsmsg_create_list();
fe_caps_t c = tda->tda_fe_info->caps;
if(!strcmp(which, "constellations")) {
if(c & FE_CAN_QAM_AUTO) fe_opts_add(a, "Auto", QAM_AUTO);
if(c & FE_CAN_QPSK) fe_opts_add(a, "QPSK", QPSK);
if(c & FE_CAN_QAM_16) fe_opts_add(a, "QAM-16", QAM_16);
if(c & FE_CAN_QAM_32) fe_opts_add(a, "QAM-32", QAM_32);
if(c & FE_CAN_QAM_64) fe_opts_add(a, "QAM-64", QAM_64);
if(c & FE_CAN_QAM_128) fe_opts_add(a, "QAM-128", QAM_128);
if(c & FE_CAN_QAM_256) fe_opts_add(a, "QAM-256", QAM_256);
return a;
}
if(!strcmp(which, "transmissionmodes")) {
if(c & FE_CAN_TRANSMISSION_MODE_AUTO)
fe_opts_add(a, "Auto", TRANSMISSION_MODE_AUTO);
fe_opts_add(a, "2k", TRANSMISSION_MODE_2K);
fe_opts_add(a, "8k", TRANSMISSION_MODE_8K);
return a;
}
if(!strcmp(which, "bandwidths")) {
if(c & FE_CAN_BANDWIDTH_AUTO)
fe_opts_add(a, "Auto", BANDWIDTH_AUTO);
fe_opts_add(a, "8 MHz", BANDWIDTH_8_MHZ);
fe_opts_add(a, "7 MHz", BANDWIDTH_7_MHZ);
fe_opts_add(a, "6 MHz", BANDWIDTH_6_MHZ);
return a;
}
if(!strcmp(which, "guardintervals")) {
if(c & FE_CAN_GUARD_INTERVAL_AUTO)
fe_opts_add(a, "Auto", GUARD_INTERVAL_AUTO);
fe_opts_add(a, "1/32", GUARD_INTERVAL_1_32);
fe_opts_add(a, "1/16", GUARD_INTERVAL_1_16);
fe_opts_add(a, "1/8", GUARD_INTERVAL_1_8);
fe_opts_add(a, "1/4", GUARD_INTERVAL_1_4);
return a;
}
if(!strcmp(which, "hierarchies")) {
if(c & FE_CAN_HIERARCHY_AUTO)
fe_opts_add(a, "Auto", HIERARCHY_AUTO);
fe_opts_add(a, "None", HIERARCHY_NONE);
fe_opts_add(a, "1", HIERARCHY_1);
fe_opts_add(a, "2", HIERARCHY_2);
fe_opts_add(a, "4", HIERARCHY_4);
return a;
}
if(!strcmp(which, "fec")) {
if(c & FE_CAN_FEC_AUTO)
fe_opts_add(a, "Auto", FEC_AUTO);
fe_opts_add(a, "None", FEC_NONE);
fe_opts_add(a, "1/2", FEC_1_2);
fe_opts_add(a, "2/3", FEC_2_3);
fe_opts_add(a, "3/4", FEC_3_4);
fe_opts_add(a, "4/5", FEC_4_5);
fe_opts_add(a, "5/6", FEC_5_6);
fe_opts_add(a, "6/7", FEC_6_7);
fe_opts_add(a, "7/8", FEC_7_8);
fe_opts_add(a, "8/9", FEC_8_9);
return a;
}
if(!strcmp(which, "polarisations")) {
fe_opts_add(a, "Horizontal", POLARISATION_HORIZONTAL);
fe_opts_add(a, "Vertical", POLARISATION_VERTICAL);
return a;
}
htsmsg_destroy(a);
return NULL;
}

View file

@ -413,7 +413,6 @@ tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m, const char *identifier)
const char *s;
int r;
int polarisation = 0;
unsigned int switchport = 0;
unsigned int tsid, u32, enabled;
dvb_satconf_t *sc;
@ -475,8 +474,6 @@ tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m, const char *identifier)
if(s == NULL || (r = str2val(s, poltab)) < 0)
return "Invalid polarisation";
polarisation = r;
htsmsg_get_u32(m, "switchport", &switchport);
break;
case FE_QAM:
@ -695,3 +692,111 @@ dvb_mux_notify(th_dvb_mux_instance_t *tdmi)
{
notify_by_msg("dvbMux", dvb_mux_build_msg(tdmi));
}
/**
*
*/
const char *
dvb_mux_add_by_params(th_dvb_adapter_t *tda,
int freq,
int symrate,
int bw,
int constellation,
int tmode,
int guard,
int hier,
int fechi,
int feclo,
int fec,
int polarisation,
const char *satconf)
{
dvb_satconf_t *sc;
struct dvb_frontend_parameters f;
th_dvb_mux_instance_t *tdmi;
memset(&f, 0, sizeof(f));
f.inversion = INVERSION_AUTO;
switch(tda->tda_type) {
case FE_OFDM:
f.frequency = freq * 1000;
if(!val2str(bw, bwtab))
return "Invalid bandwidth";
if(!val2str(constellation, qamtab))
return "Invalid QAM constellation";
if(!val2str(tmode, modetab))
return "Invalid transmission mode";
if(!val2str(guard, guardtab))
return "Invalid guard interval";
if(!val2str(hier, hiertab))
return "Invalid hierarchy";
if(!val2str(fechi, fectab))
return "Invalid FEC Hi";
if(!val2str(feclo, fectab))
return "Invalid FEC Lo";
f.u.ofdm.bandwidth = bw;
f.u.ofdm.constellation = constellation;
f.u.ofdm.transmission_mode = tmode;
f.u.ofdm.guard_interval = guard;
f.u.ofdm.hierarchy_information = hier;
f.u.ofdm.code_rate_HP = fechi;
f.u.ofdm.code_rate_LP = feclo;
polarisation = 0;
break;
case FE_QAM:
f.frequency = freq * 1000;
if(!val2str(constellation, qamtab))
return "Invalid QAM constellation";
if(!val2str(fec, fectab))
return "Invalid FEC";
f.u.qam.symbol_rate = symrate;
f.u.qam.modulation = constellation;
f.u.qam.fec_inner = fec;
polarisation = 0;
break;
case FE_QPSK:
f.frequency = freq;
if(!val2str(fec, fectab))
return "Invalid FEC";
if(!val2str(polarisation, poltab))
return "Invalid polarisation";
f.u.qpsk.symbol_rate = symrate;
f.u.qpsk.fec_inner = fec;
break;
}
if(satconf != NULL) {
sc = dvb_satconf_entry_find(tda, satconf, 0);
if(sc == NULL)
return "Satellite configuration not found";
} else {
sc = NULL;
}
tdmi = dvb_mux_create(tda, &f, polarisation, sc,
0xffff, NULL, NULL, 1, NULL);
if(tdmi == NULL)
return "Mux already exist";
return NULL;
}

View file

@ -665,4 +665,8 @@ extern void scopedunlock(pthread_mutex_t **mtxp);
#define scopedgloballock() scopedlock(&global_lock)
#define tvh_strdupa(n) ({ int tvh_l = strlen(n); \
char *tvh_b = alloca(tvh_l + 1); \
memcpy(tvh_b, n, tvh_l + 1); })
#endif /* TV_HEAD_H */

View file

@ -1369,6 +1369,99 @@ extjs_dvbservicedetails(http_connection_t *hc,
}
/**
*
*/
static int
extjs_dvb_feopts(http_connection_t *hc, const char *remain, void *opaque)
{
htsbuf_queue_t *hq = &hc->hc_reply;
char *a, *r;
th_dvb_adapter_t *tda;
htsmsg_t *e, *out;
if(remain == NULL)
return 400;
r = tvh_strdupa(remain);
if((a = strchr(r, '/')) == NULL)
return 400;
*a++ = 0;
pthread_mutex_lock(&global_lock);
if((tda = dvb_adapter_find_by_identifier(a)) == NULL) {
pthread_mutex_unlock(&global_lock);
return 404;
}
e = dvb_fe_opts(tda, r);
if(e == NULL) {
pthread_mutex_unlock(&global_lock);
return 400;
}
out = htsmsg_create_map();
htsmsg_add_msg(out, "entries", e);
pthread_mutex_unlock(&global_lock);
htsmsg_json_serialize(out, hq, 0);
http_output_content(hc, "text/x-json; charset=UTF-8");
htsmsg_destroy(out);
return 0;
}
/**
*
*/
static int
extjs_dvb_addmux(http_connection_t *hc, const char *remain, void *opaque)
{
htsmsg_t *out;
htsbuf_queue_t *hq = &hc->hc_reply;
struct http_arg_list *args = &hc->hc_req_args;
th_dvb_adapter_t *tda;
const char *err;
pthread_mutex_lock(&global_lock);
if(remain == NULL ||
(tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
pthread_mutex_unlock(&global_lock);
return 404;
}
err =
dvb_mux_add_by_params(tda,
atoi(http_arg_get(args, "frequency")?:"-1"),
atoi(http_arg_get(args, "symbolrateID")?: "-1"),
atoi(http_arg_get(args, "bandwidthID")?: "-1"),
atoi(http_arg_get(args, "constellationID")?: "-1"),
atoi(http_arg_get(args, "tmodeID")?: "-1"),
atoi(http_arg_get(args, "guardintervalID")?: "-1"),
atoi(http_arg_get(args, "hierarchyID")?: "-1"),
atoi(http_arg_get(args, "fechiID")?: "-1"),
atoi(http_arg_get(args, "fecloID")?: "-1"),
atoi(http_arg_get(args, "fecID")?: "-1"),
atoi(http_arg_get(args, "polarisationID")?: "-1"),
http_arg_get(args, "satconfID") ?: NULL);
if(err != NULL)
tvhlog(LOG_ERR, "web interface",
"Unable to create mux on %s: %s",
tda->tda_displayname, err);
pthread_mutex_unlock(&global_lock);
out = htsmsg_create_map();
htsmsg_json_serialize(out, hq, 0);
http_output_content(hc, "text/x-json; charset=UTF-8");
htsmsg_destroy(out);
return 0;
}
/**
* WEB user interface
*/
@ -1404,4 +1497,10 @@ extjs_start(void)
http_path_add("/dvb/servicedetails",
NULL, extjs_dvbservicedetails, ACCESS_ADMIN);
http_path_add("/dvb/feopts",
NULL, extjs_dvb_feopts, ACCESS_ADMIN);
http_path_add("/dvb/addmux",
NULL, extjs_dvb_addmux, ACCESS_ADMIN);
}

View file

@ -12,7 +12,8 @@ tvheadend.dvbAdapterStore = new Ext.data.JsonStore({
'services',
'muxes',
'initialMuxes',
'satConf'],
'satConf',
'deliverySystem'],
url:'dvb/adapter'
});
@ -256,7 +257,13 @@ tvheadend.dvb_muxes = function(adapterData, satConfStore) {
viewConfig: {forceFit:true},
selModel: selModel,
tbar: [
delBtn, '-', saveBtn, rejectBtn, '->', {
delBtn, '-', saveBtn, rejectBtn, '-', {
text: 'Add mux(es) manually',
iconCls:'add',
handler: function() {
tvheadend.addMuxManually(adapterData, satConfStore)
}
}, '->', {
text: 'Help',
handler: function() {
new tvheadend.help(title, helpContent);
@ -563,6 +570,277 @@ tvheadend.addMuxByLocation = function(adapterData, satConfStore) {
}
/**
* Add mux by manual configuration
*/
tvheadend.addMuxManually = function(adapterData, satConfStore) {
var adId = adapterData.identifier;
var items = [
new Ext.form.NumberField({
fieldLabel: 'Frequency (kHz)',
name: 'frequency',
allowNegative: false
})
];
switch(adapterData.deliverySystem) {
case 'DVB-T':
items.push(new Ext.form.ComboBox({
fieldLabel: 'Bandwidth',
name: 'bandwidth',
hiddenName: 'bandwidthID',
editable: false,
allowBlank: false,
displayField: 'title',
valueField:'id',
mode:'remote',
triggerAction: 'all',
store: new Ext.data.JsonStore({
root:'entries',
fields: ['title', 'id'],
url: 'dvb/feopts/bandwidths/' + adId
})
}));
items.push(new Ext.form.ComboBox({
fieldLabel: 'Constellation',
name: 'constellation',
hiddenName: 'constellationID',
editable: false,
allowBlank: false,
displayField: 'title',
valueField:'id',
mode:'remote',
triggerAction: 'all',
store: new Ext.data.JsonStore({
root:'entries',
fields: ['title', 'id'],
url: 'dvb/feopts/constellations/' + adId
})
}));
items.push(new Ext.form.ComboBox({
fieldLabel: 'Transmission mode',
name: 'tmode',
hiddenName: 'tmodeID',
editable: false,
allowBlank: false,
displayField: 'title',
valueField:'id',
mode:'remote',
triggerAction: 'all',
store: new Ext.data.JsonStore({
root:'entries',
fields: ['title', 'id'],
url: 'dvb/feopts/transmissionmodes/' + adId
})
}));
items.push(new Ext.form.ComboBox({
fieldLabel: 'Guard interval',
name: 'guardinterval',
hiddenName: 'guardintervalID',
editable: false,
allowBlank: false,
displayField: 'title',
valueField:'id',
mode:'remote',
triggerAction: 'all',
store: new Ext.data.JsonStore({
root:'entries',
fields: ['title', 'id'],
url: 'dvb/feopts/guardintervals/' + adId
})
}));
items.push(new Ext.form.ComboBox({
fieldLabel: 'Hierarchy',
name: 'hierarchy',
hiddenName: 'hierarchyID',
editable: false,
allowBlank: false,
displayField: 'title',
valueField:'id',
mode:'remote',
triggerAction: 'all',
store: new Ext.data.JsonStore({
root:'entries',
fields: ['title', 'id'],
url: 'dvb/feopts/hierarchies/' + adId
})
}));
items.push(new Ext.form.ComboBox({
fieldLabel: 'FEC Hi',
name: 'fechi',
hiddenName: 'fechiID',
editable: false,
allowBlank: false,
displayField: 'title',
valueField:'id',
mode:'remote',
triggerAction: 'all',
store: new Ext.data.JsonStore({
root:'entries',
fields: ['title', 'id'],
url: 'dvb/feopts/fec/' + adId
})
}));
items.push(new Ext.form.ComboBox({
fieldLabel: 'FEC Lo',
name: 'feclo',
hiddenName: 'fecloID',
editable: false,
allowBlank: false,
displayField: 'title',
valueField:'id',
mode:'remote',
triggerAction: 'all',
store: new Ext.data.JsonStore({
root:'entries',
fields: ['title', 'id'],
url: 'dvb/feopts/fec/' + adId
})
}));
break;
case 'DVB-C':
items.push(new Ext.form.NumberField({
fieldLabel: 'Symbolrate (baud)',
name: 'symbolrate',
allowNegative: false
}));
items.push(new Ext.form.ComboBox({
fieldLabel: 'Constellation',
name: 'constellation',
hiddenName: 'constellationID',
editable: false,
allowBlank: false,
displayField: 'title',
valueField:'id',
mode:'remote',
triggerAction: 'all',
store: new Ext.data.JsonStore({
root:'entries',
fields: ['title', 'id'],
url: 'dvb/feopts/constellations/' + adId
})
}));
items.push(new Ext.form.ComboBox({
fieldLabel: 'FEC',
name: 'fec',
hiddenName: 'fecID',
editable: false,
allowBlank: false,
displayField: 'title',
valueField:'id',
mode:'remote',
triggerAction: 'all',
store: new Ext.data.JsonStore({
root:'entries',
fields: ['title', 'id'],
url: 'dvb/feopts/fec/' + adId
})
}));
break;
case 'DVB-S':
items.push(new Ext.form.NumberField({
fieldLabel: 'Symbolrate (baud)',
name: 'symbolrate',
allowNegative: false
}));
items.push(new Ext.form.ComboBox({
fieldLabel: 'FEC',
name: 'fec',
hiddenName: 'fecID',
editable: false,
allowBlank: false,
displayField: 'title',
valueField:'id',
mode:'remote',
triggerAction: 'all',
store: new Ext.data.JsonStore({
root:'entries',
fields: ['title', 'id'],
url: 'dvb/feopts/fec/' + adId
})
}));
items.push(new Ext.form.ComboBox({
fieldLabel: 'Polarisation',
name: 'polarisation',
hiddenName: 'polarisationID',
editable: false,
allowBlank: false,
displayField: 'title',
valueField:'id',
mode:'remote',
triggerAction: 'all',
store: new Ext.data.JsonStore({
root:'entries',
fields: ['title', 'id'],
url: 'dvb/feopts/polarisations/' + adId
})
}));
}
if(satConfStore) {
items.push(new Ext.form.ComboBox({
store: satConfStore,
fieldLabel: 'Satellite config',
name: 'satconf',
hiddenName: 'satconfID',
editable: false,
allowBlank: false,
triggerAction: 'all',
mode: 'remote',
displayField:'name',
valueField:'identifier',
}));
}
function addMux() {
panel.getForm().submit({
url:'dvb/addmux/' + adapterId,
waitMsg:'Creating mux...'
});
}
var panel = new Ext.FormPanel({
frame:true,
border:true,
bodyStyle:'padding:5px',
labelAlign: 'right',
labelWidth: 110,
defaultType: 'textfield',
items: items,
buttons: [{
text: 'Add',
handler: addMux
}]
});
win = new Ext.Window({
title: 'Add muxes on ' + adapterData.name,
layout: 'fit',
width: 500,
height: 500,
plain: true,
items: panel
});
win.show();
}
/**
* DVB adapter details