diff options
| author | etobi <git@e-tobi.net> | 2013-09-03 09:48:41 +0200 | 
|---|---|---|
| committer | etobi <git@e-tobi.net> | 2013-09-03 09:48:41 +0200 | 
| commit | ab959d7b4194715870128e616b8e29d4a101e488 (patch) | |
| tree | 61a746231d30817be73416a7d67763fd677a1042 /lib/libdvbsec | |
| parent | 6b350466c4902c5b137e0efaf1d189128a7f18f5 (diff) | |
| download | linux-dvb-apps-ab959d7b4194715870128e616b8e29d4a101e488.tar.gz | |
Imported Upstream version 1.1.1+rev1207upstream/1.1.1+rev1207
Diffstat (limited to 'lib/libdvbsec')
| -rw-r--r-- | lib/libdvbsec/Makefile | 17 | ||||
| -rw-r--r-- | lib/libdvbsec/dvbsec_api.c | 951 | ||||
| -rw-r--r-- | lib/libdvbsec/dvbsec_api.h | 436 | ||||
| -rw-r--r-- | lib/libdvbsec/dvbsec_cfg.c | 366 | ||||
| -rw-r--r-- | lib/libdvbsec/dvbsec_cfg.h | 203 | 
5 files changed, 1973 insertions, 0 deletions
| diff --git a/lib/libdvbsec/Makefile b/lib/libdvbsec/Makefile new file mode 100644 index 0000000..3d405f4 --- /dev/null +++ b/lib/libdvbsec/Makefile @@ -0,0 +1,17 @@ +# Makefile for linuxtv.org dvb-apps/lib/libdvbsec + +includes = dvbsec_api.h        \ +           dvbsec_cfg.h + +objects  = dvbsec_api.o        \ +           dvbsec_cfg.o + +lib_name = libdvbsec + +CPPFLAGS += -I../../lib + +.PHONY: all + +all: library + +include ../../Make.rules diff --git a/lib/libdvbsec/dvbsec_api.c b/lib/libdvbsec/dvbsec_api.c new file mode 100644 index 0000000..5f2ae22 --- /dev/null +++ b/lib/libdvbsec/dvbsec_api.c @@ -0,0 +1,951 @@ +/* +	libdvbsec - an SEC library + +	Copyright (C) 2005 Manu Abraham <abraham.manu@gmail.com> +	Copyright (C) 2006 Andrew de Quincey <adq_dvb@lidskialf.net> + +	This library is free software; you can redistribute it and/or +	modify it under the terms of the GNU Lesser General Public +	License as published by the Free Software Foundation; either +	version 2.1 of the License, or (at your option) any later version. +	This library is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +	Lesser General Public License for more details. +	You should have received a copy of the GNU Lesser General Public +	License along with this library; if not, write to the Free Software +	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA +*/ + +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <linux/types.h> +#include <libdvbapi/dvbfe.h> +#include "dvbsec_api.h" + +// uncomment this to make dvbsec_command print out debug instead of talking to a frontend +// #define TEST_SEC_COMMAND 1 + +int dvbsec_set(struct dvbfe_handle *fe, +		   struct dvbsec_config *sec_config, +		   enum dvbsec_diseqc_polarization polarization, +		   enum dvbsec_diseqc_switch sat_pos, +		   enum dvbsec_diseqc_switch switch_option, +		   struct dvbfe_parameters *params, +		   int timeout) +{ +	int tmp; +	struct dvbfe_parameters localparams; +	struct dvbfe_parameters *topass = params; + +	// perform SEC +	if (sec_config != NULL) { +		switch(sec_config->config_type) { +		case DVBSEC_CONFIG_NONE: +			break; + +		case DVBSEC_CONFIG_POWER: +			dvbfe_set_voltage(fe, DVBFE_SEC_VOLTAGE_13); +			break; + +		case DVBSEC_CONFIG_STANDARD: +		{ +			// calculate the correct oscillator value +			enum dvbsec_diseqc_oscillator osc = DISEQC_OSCILLATOR_LOW; +			if (sec_config->switch_frequency && (sec_config->switch_frequency < params->frequency)) +				osc = DISEQC_OSCILLATOR_HIGH; + +			if ((tmp = dvbsec_std_sequence(fe, +			     				  osc, +							  polarization, +							  sat_pos, +							  switch_option)) < 0) +				return tmp; +			break; +		} + +		case DVBSEC_CONFIG_ADVANCED: +		{ +			// are we high or not? +			int high = 0; +			if (sec_config->switch_frequency && (sec_config->switch_frequency < params->frequency)) +				high = 1; + +			//  determine correct string +			char *cmd = NULL; +			switch(polarization) { +			case DISEQC_POLARIZATION_H: +				if (!high) +					cmd = sec_config->adv_cmd_lo_h; +				else +					cmd = sec_config->adv_cmd_hi_h; +				break; +			case DISEQC_POLARIZATION_V: +				if (!high) +					cmd = sec_config->adv_cmd_lo_v; +				else +					cmd = sec_config->adv_cmd_hi_v; +				break; +			case DISEQC_POLARIZATION_L: +				if (!high) +					cmd = sec_config->adv_cmd_lo_l; +				else +					cmd = sec_config->adv_cmd_hi_l; +				break; +			case DISEQC_POLARIZATION_R: +				if (!high) +					cmd = sec_config->adv_cmd_lo_r; +				else +					cmd = sec_config->adv_cmd_hi_r; +				break; +			default: +				return -EINVAL; +			} + +			// do it +			if (cmd) +				if ((tmp = dvbsec_command(fe, cmd)) < 0) +					return tmp; +			break; +		} +		} + +		// work out the correct LOF value +		uint32_t lof = 0; +		if ((sec_config->switch_frequency == 0) || (params->frequency < sec_config->switch_frequency)) { +			// LOW band +			switch(polarization) { +			case DISEQC_POLARIZATION_H: +				lof = sec_config->lof_lo_h; +				break; +			case DISEQC_POLARIZATION_V: +				lof = sec_config->lof_lo_v; +				break; +			case DISEQC_POLARIZATION_L: +				lof = sec_config->lof_lo_l; +				break; +			case DISEQC_POLARIZATION_R: +				lof = sec_config->lof_lo_r; +				break; +			case DISEQC_POLARIZATION_UNCHANGED: +				break; +			} +		} else { +			// HIGH band +			switch(polarization) { +			case DISEQC_POLARIZATION_H: +				lof = sec_config->lof_hi_h; +				break; +			case DISEQC_POLARIZATION_V: +				lof = sec_config->lof_hi_v; +				break; +			case DISEQC_POLARIZATION_L: +				lof = sec_config->lof_hi_l; +				break; +			case DISEQC_POLARIZATION_R: +				lof = sec_config->lof_hi_r; +				break; +			case DISEQC_POLARIZATION_UNCHANGED: +				break; +			} +		} + +		// do frequency adjustment +		if (lof) { +			memcpy(&localparams, params, sizeof(struct dvbfe_parameters)); +			int tmpfreq = localparams.frequency - lof; + +			if (tmpfreq < 0) +				tmpfreq *= -1; +			localparams.frequency = (uint32_t) tmpfreq; +			topass = &localparams; +		} +	} + +	// set the frontend! +	return dvbfe_set(fe, topass, timeout); +} + +int dvbsec_std_sequence(struct dvbfe_handle *fe, +			   enum dvbsec_diseqc_oscillator oscillator, +			   enum dvbsec_diseqc_polarization polarization, +			   enum dvbsec_diseqc_switch sat_pos, +			   enum dvbsec_diseqc_switch switch_option) +{ +	dvbfe_set_22k_tone(fe, DVBFE_SEC_TONE_OFF); + +	switch(polarization) { +	case DISEQC_POLARIZATION_V: +	case DISEQC_POLARIZATION_R: +		dvbfe_set_voltage(fe, DVBFE_SEC_VOLTAGE_13); +		break; +	case DISEQC_POLARIZATION_H: +	case DISEQC_POLARIZATION_L: +		dvbfe_set_voltage(fe, DVBFE_SEC_VOLTAGE_18); +		break; +	default: +		return -EINVAL; +	} + +	dvbsec_diseqc_set_committed_switches(fe, +					    DISEQC_ADDRESS_ANY_DEVICE, +					    oscillator, +					    polarization, +					    sat_pos, +					    switch_option); + +	usleep(15000); + +	switch(sat_pos) { +	case DISEQC_SWITCH_A: +		dvbfe_set_tone_data_burst(fe, DVBFE_SEC_MINI_A); +		break; +	case DISEQC_SWITCH_B: +		dvbfe_set_tone_data_burst(fe, DVBFE_SEC_MINI_B); +		break; +	default: +		break; +	} + +	if (sat_pos != DISEQC_SWITCH_UNCHANGED) +		usleep(15000); + +	switch(oscillator) { +	case DISEQC_OSCILLATOR_LOW: +		dvbfe_set_22k_tone(fe, DVBFE_SEC_TONE_OFF); +		break; +	case DISEQC_OSCILLATOR_HIGH: +		dvbfe_set_22k_tone(fe, DVBFE_SEC_TONE_ON); +		break; +	default: +		break; +	} + +	return 0; +} + +int dvbsec_diseqc_set_reset(struct dvbfe_handle *fe, +			   enum dvbsec_diseqc_address address, +			   enum dvbsec_diseqc_reset state) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x00 }; + +	if (state == DISEQC_RESET_CLEAR) +		data[2] = 0x01; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_set_power(struct dvbfe_handle *fe, +			   enum dvbsec_diseqc_address address, +			   enum dvbsec_diseqc_power state) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x02 }; + +	if (state == DISEQC_POWER_ON) +		data[2] = 0x03; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_set_listen(struct dvbfe_handle *fe, +			    enum dvbsec_diseqc_address address, +			    enum dvbsec_diseqc_listen state) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x30 }; + +	if (state == DISEQC_LISTEN_AWAKE) +		data[2] = 0x31; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_set_committed_switches(struct dvbfe_handle *fe, +					enum dvbsec_diseqc_address address, +					enum dvbsec_diseqc_oscillator oscillator, +					enum dvbsec_diseqc_polarization polarization, +					enum dvbsec_diseqc_switch sat_pos, +					enum dvbsec_diseqc_switch switch_option) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x38, 0x00 }; + +	switch(oscillator) { +	case DISEQC_OSCILLATOR_LOW: +		data[3] |= 0x10; +		break; +	case DISEQC_OSCILLATOR_HIGH: +		data[3] |= 0x11; +		break; +	case DISEQC_OSCILLATOR_UNCHANGED: +		break; +	} +	switch(polarization) { +	case DISEQC_POLARIZATION_V: +	case DISEQC_POLARIZATION_R: +		data[3] |= 0x20; +		break; +	case DISEQC_POLARIZATION_H: +	case DISEQC_POLARIZATION_L: +		data[3] |= 0x22; +		break; +	default: +		break; +	} +	switch(sat_pos) { +	case DISEQC_SWITCH_A: +		data[3] |= 0x40; +		break; +	case DISEQC_SWITCH_B: +		data[3] |= 0x44; +		break; +	case DISEQC_SWITCH_UNCHANGED: +		break; +	} +	switch(switch_option) { +	case DISEQC_SWITCH_A: +		data[3] |= 0x80; +		break; +	case DISEQC_SWITCH_B: +		data[3] |= 0x88; +		break; +	case DISEQC_SWITCH_UNCHANGED: +		break; +	} + +	if (data[3] == 0) +		return 0; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_set_uncommitted_switches(struct dvbfe_handle *fe, +					  enum dvbsec_diseqc_address address, +					  enum dvbsec_diseqc_switch s1, +					  enum dvbsec_diseqc_switch s2, +					  enum dvbsec_diseqc_switch s3, +					  enum dvbsec_diseqc_switch s4) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x39, 0x00 }; + +	switch(s1) { +	case DISEQC_SWITCH_A: +		data[3] |= 0x10; +		break; +	case DISEQC_SWITCH_B: +		data[3] |= 0x11; +		break; +	case DISEQC_SWITCH_UNCHANGED: +		break; +	} +	switch(s2) { +	case DISEQC_SWITCH_A: +		data[3] |= 0x20; +		break; +	case DISEQC_SWITCH_B: +		data[3] |= 0x22; +		break; +	case DISEQC_SWITCH_UNCHANGED: +		break; +	} +	switch(s3) { +	case DISEQC_SWITCH_A: +		data[3] |= 0x40; +		break; +	case DISEQC_SWITCH_B: +		data[3] |= 0x44; +		break; +	case DISEQC_SWITCH_UNCHANGED: +		break; +	} +	switch(s4) { +	case DISEQC_SWITCH_A: +		data[3] |= 0x80; +		break; +	case DISEQC_SWITCH_B: +		data[3] |= 0x88; +		break; +	case DISEQC_SWITCH_UNCHANGED: +		break; +	} + +	if (data[3] == 0) +		return 0; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_set_analog_value(struct dvbfe_handle *fe, +				  enum dvbsec_diseqc_address address, +				  enum dvbsec_diseqc_analog_id id, +				  uint8_t value) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x48, value }; + +	if (id == DISEQC_ANALOG_ID_A1) +		data[2] = 0x49; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_set_frequency(struct dvbfe_handle *fe, +			       enum dvbsec_diseqc_address address, +			       uint32_t frequency) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x58, 0x00, 0x00, 0x00 }; +	int len = 5; + +	uint32_t bcdval = 0; +	int i; +	for(i=0; i<=24;i+=4) { +		bcdval |= ((frequency % 10) << i); +		frequency /= 10; +	} + +	data[3] = bcdval >> 16; +	data[4] = bcdval >> 8; +	if (bcdval & 0xff) { +		data[5] = bcdval; +		len++; +	} + +	return dvbfe_do_diseqc_command(fe, data, len); +} + +int dvbsec_diseqc_set_channel(struct dvbfe_handle *fe, +			     enum dvbsec_diseqc_address address, +			     uint16_t channel) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x59, 0x00, 0x00}; + +	data[3] = channel >> 8; +	data[4] = channel; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_halt_satpos(struct dvbfe_handle *fe, +			     enum dvbsec_diseqc_address address) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x60}; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_disable_satpos_limits(struct dvbfe_handle *fe, +				       enum dvbsec_diseqc_address address) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x63}; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_set_satpos_limit(struct dvbfe_handle *fe, +				  enum dvbsec_diseqc_address address, +				  enum dvbsec_diseqc_direction direction) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x66}; + +	if (direction == DISEQC_DIRECTION_WEST) +		data[2] = 0x67; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_drive_satpos_motor(struct dvbfe_handle *fe, +				    enum dvbsec_diseqc_address address, +				    enum dvbsec_diseqc_direction direction, +				    enum dvbsec_diseqc_drive_mode mode, +				    uint8_t value) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x68, 0x00}; + +	if (direction == DISEQC_DIRECTION_WEST) +		data[2] = 0x69; + +	switch(mode) { +	case DISEQC_DRIVE_MODE_STEPS: +		data[3] = (value & 0x7f) | 0x80; +		break; +	case DISEQC_DRIVE_MODE_TIMEOUT: +		data[3] = value & 0x7f; +		break; +	} + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_store_satpos_preset(struct dvbfe_handle *fe, +				     enum dvbsec_diseqc_address address, +				     uint8_t id) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x6A, id}; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_goto_satpos_preset(struct dvbfe_handle *fe, +				    enum dvbsec_diseqc_address address, +				    uint8_t id) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x6B, id}; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +int dvbsec_diseqc_recalculate_satpos_positions(struct dvbfe_handle *fe, +					      enum dvbsec_diseqc_address address, +					      int val1, +					      int val2) +{ +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x6F, 0x00, 0x00}; +	int len = 3; + +	if (val1 != -1) { +		data[3] = val1; +		len++; +	} +	if (val2 != -1) { +		data[4] = val2; +		len = 5; +	} + +	return dvbfe_do_diseqc_command(fe, data, len); +} + +int dvbsec_diseqc_goto_rotator_bearing(struct dvbfe_handle *fe, +				      enum dvbsec_diseqc_address address, +				      float angle) +{ +	int integer = (int) angle; +	uint8_t data[] = { DISEQC_FRAMING_MASTER_NOREPLY, address, 0x6e, 0x00, 0x00}; + +	// transform the fraction into the correct representation +	int fraction = (int) (((angle - integer) * 16.0) + 0.9) & 0x0f; +	switch(fraction) { +	case 1: +	case 4: +	case 7: +	case 9: +	case 12: +	case 15: +		fraction--; +		break; +	} + +	// generate the command +	if (integer < -256) { +		return -EINVAL; +	} else if (integer < 0) { +		integer = -integer; +		data[3] = 0xf0; +	} else if (integer < 256) { +		data[3] = 0x00; +	} else if (integer < 512) { +		integer -= 256; +		data[3] = 0x10; +	} else { +		return -EINVAL; +	} +	data[3] |= ((integer / 16) & 0x0f); +	integer = integer % 16; +	data[4] |= ((integer & 0x0f) << 4) | fraction; + +	return dvbfe_do_diseqc_command(fe, data, sizeof(data)); +} + +static int skipwhite(char **line, char *end) +{ +	while(**line) { +		if (end && (*line >= end)) +			return -1; +		if (!isspace(**line)) +			return 0; +		(*line)++; +	} + +	return -1; +} + +static int getstringupto(char **line, char *end, char *matches, char **ptrdest, int *ptrlen) +{ +	char *start = *line; + +	while(**line) { +		if (end && (*line >= end)) +			break; +		if (strchr(matches, **line)) { +			*ptrdest = start; +			*ptrlen = *line - start; +			return 0; +		} +		(*line)++; +	} + +	*ptrdest = start; +	*ptrlen = *line - start; +	return 0; +} + +static int parsefunction(char **line, +			 char **nameptr, int *namelen, +			 char **argsptr, int *argslen) +{ +	if (skipwhite(line, NULL)) +		return -1; + +	if (getstringupto(line, NULL, "(", nameptr, namelen)) +		return -1; +	if ((*line) == 0) +		return -1; +	(*line)++; // skip the '(' +	if (getstringupto(line, NULL, ")", argsptr, argslen)) +		return -1; +	if ((*line) == 0) +		return -1; +	(*line)++; // skip the ')' + +	return 0; +} + +static int parseintarg(char **args, char *argsend, int *result) +{ +	char tmp[32]; +	char *arg; +	int arglen; + +	// skip whitespace +	if (skipwhite(args, argsend)) +		return -1; + +	// get the arg +	if (getstringupto(args, argsend, ",", &arg, &arglen)) +		return -1; +	if ((**args) == ',') +		(*args)++; // skip the ',' if present +	if (arglen > 31) +		arglen = 31; +	strncpy(tmp, arg, arglen); +	tmp[arglen] = 0; + +	if (sscanf(tmp, "%i", result) != 1) +		return -1; + +	return 0; +} + +static int parsechararg(char **args, char *argsend, int *result) +{ +	char *arg; +	int arglen; + +	// skip whitespace +	if (skipwhite(args, argsend)) +		return -1; + +	// get the arg +	if (getstringupto(args, argsend, ",", &arg, &arglen)) +		return -1; +	if ((**args) == ',') +		(*args)++; // skip the ',' if present +	if (arglen > 0) +		*result = arg[0]; + +	return 0; +} + +static int parsefloatarg(char **args, char *argsend, float *result) +{ +	char tmp[32]; +	char *arg; +	int arglen; + +	// skip whitespace +	if (skipwhite(args, argsend)) +		return -1; + +	// get the arg +	if (getstringupto(args, argsend, ",", &arg, &arglen)) +		return -1; +	if ((**args) == ',') +		(*args)++; // skip the ',' if present +	if (arglen > 31) +		arglen = 31; +	strncpy(tmp, arg, arglen); +	arg[arglen] = 0; + +	if (sscanf(tmp, "%f", result) != 1) +		return -1; + +	return 0; +} + +static enum dvbsec_diseqc_switch parse_switch(int c) +{ +	switch(toupper(c)) { +	case 'A': +		return DISEQC_SWITCH_A; +	case 'B': +		return DISEQC_SWITCH_B; +	default: +		return DISEQC_SWITCH_UNCHANGED; +	} +} + +int dvbsec_command(struct dvbfe_handle *fe, char *command) +{ +	char *name; +	char *args; +	int namelen; +	int argslen; +	int address; +	int iarg; +	int iarg2; +	int iarg3; +	int iarg4; +	float farg; + +	while(!parsefunction(&command, &name, &namelen, &args, &argslen)) { +		char *argsend = args+argslen; + +		if (!strncasecmp(name, "tone", namelen)) { +			if (parsechararg(&args, argsend, &iarg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("tone: %c\n", iarg); +#else +			if (toupper(iarg) == 'B') { +				dvbfe_set_22k_tone(fe, DVBFE_SEC_TONE_ON); +			} else { +				dvbfe_set_22k_tone(fe, DVBFE_SEC_TONE_OFF); +			} +#endif +		} else if (!strncasecmp(name, "voltage", namelen)) { +			if (parseintarg(&args, argsend, &iarg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("voltage: %i\n", iarg); +#else +			switch(iarg) { +			case 0: +				dvbfe_set_voltage(fe, DVBFE_SEC_VOLTAGE_OFF); +				break; +			case 13: +				dvbfe_set_voltage(fe, DVBFE_SEC_VOLTAGE_13); +				break; +			case 18: +				dvbfe_set_voltage(fe, DVBFE_SEC_VOLTAGE_18); +				break; +			default: +				return -1; +			} +#endif +		} else if (!strncasecmp(name, "toneburst", namelen)) { +			if (parsechararg(&args, argsend, &iarg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("toneburst: %c\n", iarg); +#else +			if (toupper(iarg) == 'B') { +				dvbfe_set_tone_data_burst(fe, DVBFE_SEC_MINI_B); +			} else { +				dvbfe_set_tone_data_burst(fe, DVBFE_SEC_MINI_A); +			} +#endif +		} else if (!strncasecmp(name, "highvoltage", namelen)) { +			if (parseintarg(&args, argsend, &iarg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("highvoltage: %i\n", iarg); +#else +			dvbfe_set_high_lnb_voltage(fe, iarg ? 1 : 0); +#endif +		} else if (!strncasecmp(name, "dishnetworks", namelen)) { +			if (parseintarg(&args, argsend, &iarg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("dishnetworks: %i\n", iarg); +#else +			dvbfe_do_dishnetworks_legacy_command(fe, iarg); +#endif +		} else if (!strncasecmp(name, "wait", namelen)) { +			if (parseintarg(&args, argsend, &iarg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("wait: %i\n", iarg); +#else +			if (iarg) +				usleep(iarg * 1000); +#endif +		} else if (!strncasecmp(name, "Dreset", namelen)) { +			if (parseintarg(&args, argsend, &address)) +				return -1; +			if (parseintarg(&args, argsend, &iarg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("Dreset: %i %i\n", address, iarg); +#else +			if (iarg) { +				dvbsec_diseqc_set_reset(fe, address, DISEQC_RESET); +			} else { +				dvbsec_diseqc_set_reset(fe, address, DISEQC_RESET_CLEAR); +			} +#endif +		} else if (!strncasecmp(name, "Dpower", namelen)) { +			if (parseintarg(&args, argsend, &address)) +				return -1; +			if (parseintarg(&args, argsend, &iarg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("Dpower: %i %i\n", address, iarg); +#else +			if (iarg) { +				dvbsec_diseqc_set_power(fe, address, DISEQC_POWER_ON); +			} else { +				dvbsec_diseqc_set_power(fe, address, DISEQC_POWER_OFF); +			} +#endif +		} else if (!strncasecmp(name, "Dcommitted", namelen)) { +			if (parseintarg(&args, argsend, &address)) +				return -1; +			if (parsechararg(&args, argsend, &iarg)) +				return -1; +			if (parsechararg(&args, argsend, &iarg2)) +				return -1; +			if (parsechararg(&args, argsend, &iarg3)) +				return -1; +			if (parsechararg(&args, argsend, &iarg4)) +				return -1; + +			enum dvbsec_diseqc_oscillator oscillator; +			switch(toupper(iarg)) { +			case 'H': +				oscillator = DISEQC_OSCILLATOR_HIGH; +				break; +			case 'L': +				oscillator = DISEQC_OSCILLATOR_LOW; +				break; +			default: +				oscillator = DISEQC_OSCILLATOR_UNCHANGED; +				break; +			} + +			int polarization = -1; +			switch(toupper(iarg2)) { +			case 'H': +				polarization = DISEQC_POLARIZATION_H; +				break; +			case 'V': +				polarization = DISEQC_POLARIZATION_V; +				break; +			case 'L': +				polarization = DISEQC_POLARIZATION_L; +				break; +			case 'R': +				polarization = DISEQC_POLARIZATION_R; +				break; +			default: +				polarization = -1; +				break; +			} + +#ifdef TEST_SEC_COMMAND +			printf("Dcommitted: %i %i %i %i %i\n", address, +			       oscillator, +			       polarization, +			       parse_switch(iarg3), +			       parse_switch(iarg4)); +#else +			dvbsec_diseqc_set_committed_switches(fe, address, +							    oscillator, +							    polarization, +							    parse_switch(iarg3), +							    parse_switch(iarg4)); +#endif +		} else if (!strncasecmp(name, "Duncommitted", namelen)) { +			if (parsechararg(&args, argsend, &address)) +				return -1; +			if (parsechararg(&args, argsend, &iarg)) +				return -1; +			if (parsechararg(&args, argsend, &iarg2)) +				return -1; +			if (parsechararg(&args, argsend, &iarg3)) +				return -1; +			if (parsechararg(&args, argsend, &iarg4)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("Duncommitted: %i %i %i %i %i\n", address, +			       parse_switch(iarg), +			       parse_switch(iarg2), +			       parse_switch(iarg3), +			       parse_switch(iarg4)); +#else +			dvbsec_diseqc_set_uncommitted_switches(fe, address, +					parse_switch(iarg), +					parse_switch(iarg2), +					parse_switch(iarg3), +					parse_switch(iarg4)); +#endif +		} else if (!strncasecmp(name, "Dfrequency", namelen)) { +			if (parseintarg(&args, argsend, &address)) +				return -1; +			if (parseintarg(&args, argsend, &iarg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("Dfrequency: %i %i\n", address, iarg); +#else +			dvbsec_diseqc_set_frequency(fe, address, iarg); +#endif +		} else if (!strncasecmp(name, "Dchannel", namelen)) { +			if (parseintarg(&args, argsend, &address)) +				return -1; +			if (parseintarg(&args, argsend, &iarg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("Dchannel: %i %i\n", address, iarg); +#else +			dvbsec_diseqc_set_channel(fe, address, iarg); +#endif +		} else if (!strncasecmp(name, "Dgotopreset", namelen)) { +			if (parseintarg(&args, argsend, &address)) +				return -1; +			if (parseintarg(&args, argsend, &iarg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("Dgotopreset: %i %i\n", address, iarg); +#else +			dvbsec_diseqc_goto_satpos_preset(fe, address, iarg); +#endif +		} else if (!strncasecmp(name, "Dgotobearing", namelen)) { +			if (parseintarg(&args, argsend, &address)) +				return -1; +			if (parsefloatarg(&args, argsend, &farg)) +				return -1; + +#ifdef TEST_SEC_COMMAND +			printf("Dgotobearing: %i %f\n", address, farg); +#else +			dvbsec_diseqc_goto_rotator_bearing(fe, address, farg); +#endif +		} else { +			return -1; +		} +	} + +	return 0; +} diff --git a/lib/libdvbsec/dvbsec_api.h b/lib/libdvbsec/dvbsec_api.h new file mode 100644 index 0000000..7e454d7 --- /dev/null +++ b/lib/libdvbsec/dvbsec_api.h @@ -0,0 +1,436 @@ +/* +	libdvbsec - an SEC library + +	Copyright (C) 2005 Manu Abraham <abraham.manu@gmail.com> +	Copyright (C) 2006 Andrew de Quincey <adq_dvb@lidskialf.net> + +	This library is free software; you can redistribute it and/or +	modify it under the terms of the GNU Lesser General Public +	License as published by the Free Software Foundation; either +	version 2.1 of the License, or (at your option) any later version. +	This library is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +	Lesser General Public License for more details. +	You should have received a copy of the GNU Lesser General Public +	License along with this library; if not, write to the Free Software +	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA +*/ + +#ifndef DVBSEC_API_H +#define DVBSEC_API_H 1 + +#include <stdint.h> + +struct dvbfe_handle; +struct dvbfe_parameters; + +enum dvbsec_diseqc_framing { +	DISEQC_FRAMING_MASTER_NOREPLY		= 0xE0, +	DISEQC_FRAMING_MASTER_NOREPLY_REPEAT	= 0xE1, +	DISEQC_FRAMING_MASTER_REPLY		= 0xE2, +	DISEQC_FRAMING_MASTER_REPLY_REPEAT	= 0xE3, +	DISEQC_FRAMING_SLAVE_OK			= 0xE4, +	DISEQC_FRAMING_SLAVE_UNSUPPORTED	= 0xE5, +	DISEQC_FRAMING_SLAVE_PARITY_ERROR	= 0xE6, +	DISEQC_FRAMING_SLAVE_UNRECOGNISED 	= 0xE7, +}; + +enum dvbsec_diseqc_address { +	DISEQC_ADDRESS_ANY_DEVICE		= 0x00, + +	DISEQC_ADDRESS_ANY_LNB_SWITCHER_SMATV	= 0x10, +	DISEQC_ADDRESS_LNB			= 0x11, +	DISEQC_ADDRESS_LNB_WITH_LOOP		= 0x12, +	DISEQC_ADDRESS_SWITCHER			= 0x14, +	DISEQC_ADDRESS_SWITCHER_WITH_LOOP	= 0x15, +	DISEQC_ADDRESS_SMATV			= 0x18, + +	DISEQC_ADDRESS_ANY_POLARISER		= 0x20, +	DISEQC_ADDRESS_LINEAR_POLARISER		= 0x21, + +	DISEQC_ADDRESS_ANY_POSITIONER		= 0x30, +	DISEQC_ADDRESS_POLAR_AZIMUTH_POSITIONER	= 0x31, +	DISEQC_ADDRESS_ELEVATION_POSITIONER	= 0x32, + +	DISEQC_ADDRESS_ANY_INSTALLER_AID	= 0x40, +	DISEQC_ADDRESS_SIGNAL_STRENGTH		= 0x41, + +	DISEQC_ADDRESS_ANY_INTERFACE		= 0x70, +	DISEQC_ADDRESS_HEADEND_INTERFACE	= 0x71, + +	DISEQC_ADDRESS_REALLOC_BASE		= 0x60, +	DISEQC_ADDRESS_OEM_BASE			= 0xf0, +}; + +enum dvbsec_diseqc_reset { +	DISEQC_RESET, +	DISEQC_RESET_CLEAR, +}; + +enum dvbsec_diseqc_power { +	DISEQC_POWER_OFF, +	DISEQC_POWER_ON, +}; + +enum dvbsec_diseqc_listen { +	DISEQC_LISTEN_SLEEP, +	DISEQC_LISTEN_AWAKE, +}; + +enum dvbsec_diseqc_polarization { +	DISEQC_POLARIZATION_UNCHANGED = 0, +	DISEQC_POLARIZATION_H = 'h', +	DISEQC_POLARIZATION_V = 'v', +	DISEQC_POLARIZATION_L = 'l', +	DISEQC_POLARIZATION_R = 'r', +}; + +enum dvbsec_diseqc_oscillator { +	DISEQC_OSCILLATOR_UNCHANGED = 0, +	DISEQC_OSCILLATOR_LOW, +	DISEQC_OSCILLATOR_HIGH, +}; + +enum dvbsec_diseqc_switch { +	DISEQC_SWITCH_UNCHANGED = 0, +	DISEQC_SWITCH_A, +	DISEQC_SWITCH_B, +}; + +enum dvbsec_diseqc_analog_id { +	DISEQC_ANALOG_ID_A0, +	DISEQC_ANALOG_ID_A1, +}; + +enum dvbsec_diseqc_drive_mode { +	DISEQC_DRIVE_MODE_STEPS, +	DISEQC_DRIVE_MODE_TIMEOUT, +}; + +enum dvbsec_diseqc_direction { +	DISEQC_DIRECTION_EAST, +	DISEQC_DIRECTION_WEST, +}; + +enum dvbsec_config_type { +	DVBSEC_CONFIG_NONE = 0, +	DVBSEC_CONFIG_POWER, +	DVBSEC_CONFIG_STANDARD, +	DVBSEC_CONFIG_ADVANCED, +}; + + +#define MAX_SEC_CMD_LEN 100 + +struct dvbsec_config +{ +	char id[32]; /* ID of this SEC config structure */ +	uint32_t switch_frequency; /* switching frequency - supply 0 for none. */ +	uint32_t lof_lo_v; /* frequency to subtract for V + LOW band channels - or for switch_frequency == 0 */ +	uint32_t lof_lo_h; /* frequency to subtract for H + LOW band channels - or for switch_frequency == 0 */ +	uint32_t lof_lo_l; /* frequency to subtract for L + LOW band channels - or for switch_frequency == 0 */ +	uint32_t lof_lo_r; /* frequency to subtract for R + LOW band channels - or for switch_frequency == 0 */ +	uint32_t lof_hi_v; /* frequency to subtract for V + HIGH band channels */ +	uint32_t lof_hi_h; /* frequency to subtract for H + HIGH band channels */ +	uint32_t lof_hi_l; /* frequency to subtract for L + HIGH band channels */ +	uint32_t lof_hi_r; /* frequency to subtract for R + HIGH band channels */ + +	/** +	 * The SEC control to be used depends on the type: +	 * +	 * NONE - no SEC commands will be issued. (Frequency adjustment will still be performed). +	 * +	 * POWER - only the SEC power will be turned on. +	 * +	 * STANDARD - the standard DISEQC back compatable sequence is used. +	 * +	 * ADVANCED - SEC strings are supplied by the user describing the exact sequence +	 * of operations to use. +	 */ +	enum dvbsec_config_type config_type; + +	/* stuff for type == dvbsec_config_ADVANCED */ +	char adv_cmd_lo_h[MAX_SEC_CMD_LEN];			/* ADVANCED SEC command to use for LOW/H. */ +	char adv_cmd_lo_v[MAX_SEC_CMD_LEN];			/* ADVANCED SEC command to use for LOW/V. */ +	char adv_cmd_lo_l[MAX_SEC_CMD_LEN];			/* ADVANCED SEC command to use for LOW/L. */ +	char adv_cmd_lo_r[MAX_SEC_CMD_LEN];			/* ADVANCED SEC command to use for LOW/R. */ +	char adv_cmd_hi_h[MAX_SEC_CMD_LEN];			/* ADVANCED SEC command to use for HI/H. */ +	char adv_cmd_hi_v[MAX_SEC_CMD_LEN];			/* ADVANCED SEC command to use for HI/V. */ +	char adv_cmd_hi_l[MAX_SEC_CMD_LEN];			/* ADVANCED SEC command to use for HI/L. */ +	char adv_cmd_hi_r[MAX_SEC_CMD_LEN];			/* ADVANCED SEC command to use for HI/R. */ +}; + +/** + * Helper function for tuning adapters with SEC support. This function will do + * everything required, including frequency adjustment based on the parameters + * in sec_config. + * + * Note: Since the SEC configuration structure can be set to disable any SEC + * operations, this function can be reused for ALL DVB style devices (just + * set all LOF=0,type=dvbsec_config_NONE for devices which do not require + * SEC control). + * + * The sec configuration structures can be looked up using the dvbcfg_sec library. + * + * @param fe Frontend concerned. + * @param sec_config SEC configuration structure. May be NULL to disable SEC/frequency adjustment. + * @param polarization Polarization of signal. + * @param sat_pos Satellite position - only used if type == DISEQC_SEC_CONFIG_STANDARD. + * @param switch_option Switch option - only used if type == DISEQC_SEC_CONFIG_STANDARD. + * @param params Tuning parameters. + * @param timeout <0 => wait forever for lock. 0=>return immediately, >0=> + * number of milliseconds to wait for a lock. + * @return 0 on locked (or if timeout==0 and everything else worked), or + * nonzero on failure (including no lock). + */ +extern int dvbsec_set(struct dvbfe_handle *fe, +			  struct dvbsec_config *sec_config, +			  enum dvbsec_diseqc_polarization polarization, +			  enum dvbsec_diseqc_switch sat_pos, +			  enum dvbsec_diseqc_switch switch_option, +			  struct dvbfe_parameters *params, +			  int timeout); + +/** + * This will issue the standardised back-compatable DISEQC/SEC command + * sequence as defined in the DISEQC spec: + * + * i.e. tone off, set voltage, wait15, DISEQC, wait15, toneburst, wait15, set tone. + * + * @param fe Frontend concerned. + * @param oscillator Value to set the lo/hi switch to. + * @param polarization Value to set the polarisation switch to. + * @param sat_pos Value to set the satellite position switch to. + * @param switch_option Value to set the "swtch option" switch to. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_std_sequence(struct dvbfe_handle *fe, +				  enum dvbsec_diseqc_oscillator oscillator, +				  enum dvbsec_diseqc_polarization polarization, +				  enum dvbsec_diseqc_switch sat_pos, +				  enum dvbsec_diseqc_switch switch_option); + +/** + * Execute an SEC command string on the provided frontend. Please see the documentation + * in dvbsec_cfg.h on the command format, + * + * @param fe Frontend concerned. + * @param command The command to execute. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_command(struct dvbfe_handle *fe, char *command); + +/** + * Control the reset status of an attached DISEQC device. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param state The state to set. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_set_reset(struct dvbfe_handle *fe, +				  enum dvbsec_diseqc_address address, +				  enum dvbsec_diseqc_reset state); + +/** + * Control the power status of an attached DISEQC peripheral. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param state The state to set. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_set_power(struct dvbfe_handle *fe, +				  enum dvbsec_diseqc_address address, +				  enum dvbsec_diseqc_power state); + +/** + * Control the listening status of an attached DISEQC peripheral. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param state The state to set. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_set_listen(struct dvbfe_handle *fe, +				   enum dvbsec_diseqc_address address, +				   enum dvbsec_diseqc_listen state); + +/** + * Set the state of the committed switches of a DISEQC device. + * These are switches which are defined to have a standard name. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param oscillator Value to set the lo/hi switch to. + * @param polarization Value to set the polarization switch to. + * @param sat_pos Value to set the satellite position switch to. + * @param switch_option Value to set the switch option switch to. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_set_committed_switches(struct dvbfe_handle *fe, +					       enum dvbsec_diseqc_address address, +					       enum dvbsec_diseqc_oscillator oscillator, +					       enum dvbsec_diseqc_polarization polarization, +					       enum dvbsec_diseqc_switch sat_pos, +					       enum dvbsec_diseqc_switch switch_option); + +/** + * Set the state of the uncommitted switches of a DISEQC device. + * These provide another four switching possibilities. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param s1 Value to set the S1 switch to. + * @param s2 Value to set the S2 switch to. + * @param s3 Value to set the S3 switch to. + * @param s3 Value to set the S4 switch to. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_set_uncommitted_switches(struct dvbfe_handle *fe, +						 enum dvbsec_diseqc_address address, +						 enum dvbsec_diseqc_switch s1, +						 enum dvbsec_diseqc_switch s2, +						 enum dvbsec_diseqc_switch s3, +						 enum dvbsec_diseqc_switch s4); + +/** + * Set an analogue value. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param id The id of the analogue value to set. + * @param value The value to set. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_set_analog_value(struct dvbfe_handle *fe, +					 enum dvbsec_diseqc_address address, +					 enum dvbsec_diseqc_analog_id id, +					 uint8_t value); + +/** + * Set the desired frequency. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param frequency The frequency to set in GHz. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_set_frequency(struct dvbfe_handle *fe, +				      enum dvbsec_diseqc_address address, +				      uint32_t frequency); + +/** + * Set the desired channel. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param channel ID of the channel to set. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_set_channel(struct dvbfe_handle *fe, +				    enum dvbsec_diseqc_address address, +				    uint16_t channel); + +/** + * Halt the satellite positioner. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_halt_satpos(struct dvbfe_handle *fe, +				    enum dvbsec_diseqc_address address); + +/** + * Disable satellite positioner limits. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_disable_satpos_limits(struct dvbfe_handle *fe, +					      enum dvbsec_diseqc_address address); + +/** + * Set satellite positioner limits. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_set_satpos_limit(struct dvbfe_handle *fe, +					 enum dvbsec_diseqc_address address, +					 enum dvbsec_diseqc_direction direction); + +/** + * Drive satellite positioner motor. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param direction Direction to drive in. + * @param mode Drive mode to use + * 	       (TIMEOUT=>value is a timeout in seconds, or STEPS=>value is a count of steps to use) + * @param value Value associated with the drive mode (range 0->127) + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_drive_satpos_motor(struct dvbfe_handle *fe, +					   enum dvbsec_diseqc_address address, +					   enum dvbsec_diseqc_direction direction, +					   enum dvbsec_diseqc_drive_mode mode, +					   uint8_t value); + +/** + * Store satellite positioner preset id at current position. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param id ID of the preset. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_store_satpos_preset(struct dvbfe_handle *fe, +					    enum dvbsec_diseqc_address address, +					    uint8_t id); + +/** + * Send a satellite positioner to a pre-set position. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param id ID of the preset. + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_goto_satpos_preset(struct dvbfe_handle *fe, +					   enum dvbsec_diseqc_address address, +					   uint8_t id); + +/** + * Recalculate satellite positions based on the current position, using + * magic positioner specific values. + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param val1 value1 (range 0->255, pass -1 to ignore). + * @param val2 value2 (range 0->255, pass -1 to ignore). + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_recalculate_satpos_positions(struct dvbfe_handle *fe, +						     enum dvbsec_diseqc_address address, +						     int val1, +						     int val2); + +/** + * Send a terrestrial aerial rotator to a particular bearing + * (0 degrees = north, fractional angles allowed). + * + * @param fe Frontend concerned. + * @param address Address of the device. + * @param angle Angle to rotate to (-256.0 -> 512.0) + * @return 0 on success, or nonzero on error. + */ +extern int dvbsec_diseqc_goto_rotator_bearing(struct dvbfe_handle *fe, +					     enum dvbsec_diseqc_address address, +					     float angle); + +#endif diff --git a/lib/libdvbsec/dvbsec_cfg.c b/lib/libdvbsec/dvbsec_cfg.c new file mode 100644 index 0000000..4b05a32 --- /dev/null +++ b/lib/libdvbsec/dvbsec_cfg.c @@ -0,0 +1,366 @@ +/** + * dvbsec_cfg (i.e. linuxtv sec format) configuration file support. + * + * Copyright (c) 2005 by Andrew de Quincey <adq_dvb@lidskialf.net> + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <linux/types.h> +#include "dvbsec_cfg.h" + +int dvbcfg_issection(char* line, char* sectionname) +{ +	int len; + +	len = strlen(line); +	if (len < 2) +		return 0; + +	if ((line[0] != '[') || (line[len-1] != ']')) +		return 0; + +	line++; +	while(isspace(*line)) +		line++; + +	if (strncmp(line, sectionname, strlen(sectionname))) +		return 0; + +	return 1; +} + +char* dvbcfg_iskey(char* line, char* keyname) +{ +	int len = strlen(keyname); + +	/* does the key match? */ +	if (strncmp(line, keyname, len)) +		return NULL; + +	/* skip keyname & any whitespace */ +	line += len; +	while(isspace(*line)) +		line++; + +	/* should be the '=' sign */ +	if (*line != '=') +		return 0; + +	/* more whitespace skipping */ +	line++; +	while(isspace(*line)) +		line++; + +	/* finally, return the value */ +	return line; +} + +int dvbsec_cfg_load(FILE *f, +		    void *arg, +		    dvbsec_cfg_callback cb) +{ +	struct dvbsec_config tmpsec; +	char *linebuf = NULL; +	size_t line_size = 0; +	int len; +	int insection = 0; +	char *value; + +	/* process each line */ +	while((len = getline(&linebuf, &line_size, f)) > 0) { +		char *line = linebuf; + +		/* chop any comments */ +		char *hashpos = strchr(line, '#'); +		if (hashpos) +			*hashpos = 0; +		char *lineend = line + strlen(line); + +		/* trim the line */ +		while(*line && isspace(*line)) +			line++; +		while((lineend != line) && isspace(*(lineend-1))) +			lineend--; +		*lineend = 0; + +		/* skip blank lines */ +		if (*line == 0) +			continue; + +		if (dvbcfg_issection(line, "sec")) { +			if (insection) { +				if (cb(arg, &tmpsec)) +					return 0; +			} +			insection = 1; +			memset(&tmpsec, 0, sizeof(tmpsec)); + +		} else if ((value = dvbcfg_iskey(line, "name")) != NULL) { +			strncpy(tmpsec.id, value, sizeof(tmpsec.id)); +		} else if ((value = dvbcfg_iskey(line, "switch-frequency")) != NULL) { +			tmpsec.switch_frequency = atoi(value); +		} else if ((value = dvbcfg_iskey(line, "lof-lo-v")) != NULL) { +			tmpsec.lof_lo_v = atoi(value); +		} else if ((value = dvbcfg_iskey(line, "lof-lo-h")) != NULL) { +			tmpsec.lof_lo_h = atoi(value); +		} else if ((value = dvbcfg_iskey(line, "lof-lo-l")) != NULL) { +			tmpsec.lof_lo_l = atoi(value); +		} else if ((value = dvbcfg_iskey(line, "lof-lo-r")) != NULL) { +			tmpsec.lof_lo_r = atoi(value); +		} else if ((value = dvbcfg_iskey(line, "lof-hi-v")) != NULL) { +			tmpsec.lof_hi_v = atoi(value); +		} else if ((value = dvbcfg_iskey(line, "lof-hi-h")) != NULL) { +			tmpsec.lof_hi_h = atoi(value); +		} else if ((value = dvbcfg_iskey(line, "lof-hi-l")) != NULL) { +			tmpsec.lof_hi_l = atoi(value); +		} else if ((value = dvbcfg_iskey(line, "lof-hi-r")) != NULL) { +			tmpsec.lof_hi_r = atoi(value); +		} else if ((value = dvbcfg_iskey(line, "config-type")) != NULL) { +			if (!strcasecmp(value, "none")) { +				tmpsec.config_type = DVBSEC_CONFIG_NONE; +			} else if (!strcasecmp(value, "power")) { +				tmpsec.config_type = DVBSEC_CONFIG_POWER; +			} else if (!strcasecmp(value, "standard")) { +				tmpsec.config_type = DVBSEC_CONFIG_STANDARD; +			} else if (!strcasecmp(value, "advanced")) { +				tmpsec.config_type = DVBSEC_CONFIG_ADVANCED; +			} else { +				insection = 0; +			} +		} else if ((value = dvbcfg_iskey(line, "cmd-lo-v")) != NULL) { +			strncpy(tmpsec.adv_cmd_lo_v, value, sizeof(tmpsec.adv_cmd_lo_v)); +		} else if ((value = dvbcfg_iskey(line, "cmd-lo-h")) != NULL) { +			strncpy(tmpsec.adv_cmd_lo_h, value, sizeof(tmpsec.adv_cmd_lo_h)); +		} else if ((value = dvbcfg_iskey(line, "cmd-lo-r")) != NULL) { +			strncpy(tmpsec.adv_cmd_lo_r, value, sizeof(tmpsec.adv_cmd_lo_r)); +		} else if ((value = dvbcfg_iskey(line, "cmd-lo-l")) != NULL) { +			strncpy(tmpsec.adv_cmd_lo_l, value, sizeof(tmpsec.adv_cmd_lo_l)); +		} else if ((value = dvbcfg_iskey(line, "cmd-hi-v")) != NULL) { +			strncpy(tmpsec.adv_cmd_hi_v, value, sizeof(tmpsec.adv_cmd_hi_v)); +		} else if ((value = dvbcfg_iskey(line, "cmd-hi-h")) != NULL) { +			strncpy(tmpsec.adv_cmd_hi_h, value, sizeof(tmpsec.adv_cmd_hi_h)); +		} else if ((value = dvbcfg_iskey(line, "cmd-hi-r")) != NULL) { +			strncpy(tmpsec.adv_cmd_hi_r, value, sizeof(tmpsec.adv_cmd_hi_r)); +		} else if ((value = dvbcfg_iskey(line, "cmd-hi-l")) != NULL) { +			strncpy(tmpsec.adv_cmd_hi_l, value, sizeof(tmpsec.adv_cmd_hi_l)); +		} else { +			insection = 0; +		} +	} + +	// output the final section if there is one +	if (insection) { +		if (cb(arg, &tmpsec)) +			return 0; +	} + +	if (linebuf) +		free(linebuf); +	return 0; +} + +static int dvbsec_cfg_find_callback(void *arg, struct dvbsec_config *sec); +static int dvbsec_cfg_find_default(const char *sec_id, struct dvbsec_config *sec); + +struct findparams { +	const char *sec_id; +	struct dvbsec_config *sec_dest; +}; + +int dvbsec_cfg_find(const char *config_file, +		    const char *sec_id, +		    struct dvbsec_config *sec) +{ +	struct findparams findp; + +	// clear the structure +	memset(sec, 0, sizeof(struct dvbsec_config)); + +	// open the file +	if (config_file != NULL) { +		FILE *f = fopen(config_file, "r"); +		if (f == NULL) +			return -EIO; + +		// parse each entry +		findp.sec_id = sec_id; +		findp.sec_dest = sec; +		dvbsec_cfg_load(f, &findp, dvbsec_cfg_find_callback); + +		// done +		fclose(f); + +		// find it? +		if (sec->id[0]) +			return 0; +	} + +	return dvbsec_cfg_find_default(sec_id, sec); +} + +static int dvbsec_cfg_find_callback(void *arg, struct dvbsec_config *sec) +{ +	struct findparams *findp = arg; + +	if (strcmp(findp->sec_id, sec->id)) +		return 0; + +	memcpy(findp->sec_dest, sec, sizeof(struct dvbsec_config)); +	return 1; +} + +int dvbsec_cfg_save(FILE *f, +		    struct dvbsec_config *secs, +		    int count) +{ +	int i; + +	for(i=0; i<count; i++) { +		char *config_type = ""; +		switch(secs[i].config_type) { +		case DVBSEC_CONFIG_NONE: +			config_type = "none"; +			break; +		case DVBSEC_CONFIG_POWER: +			config_type = "power"; +			break; +		case DVBSEC_CONFIG_STANDARD: +			config_type = "standard"; +			break; +		case DVBSEC_CONFIG_ADVANCED: +			config_type = "advanced"; +			break; +		} + +		fprintf(f, "[lnb]\n"); +		fprintf(f, "switch-frequency=%i\n", secs[i].switch_frequency); +		if (secs[i].lof_lo_v) +			fprintf(f, "lof-lo-v=%i\n", secs[i].lof_lo_v); +		if (secs[i].lof_lo_h) +			fprintf(f, "lof-lo-h=%i\n", secs[i].lof_lo_h); +		if (secs[i].lof_lo_l) +			fprintf(f, "lof-lo-l=%i\n", secs[i].lof_lo_l); +		if (secs[i].lof_lo_r) +			fprintf(f, "lof-lo-r=%i\n", secs[i].lof_lo_r); +		if (secs[i].lof_hi_v) +			fprintf(f, "lof-hi-v=%i\n", secs[i].lof_hi_v); +		if (secs[i].lof_hi_h) +			fprintf(f, "lof-hi-h=%i\n", secs[i].lof_hi_h); +		if (secs[i].lof_hi_l) +			fprintf(f, "lof-hi-l=%i\n", secs[i].lof_hi_l); +		if (secs[i].lof_hi_r) +			fprintf(f, "lof-hi-r=%i\n", secs[i].lof_hi_r); +		fprintf(f, "config-type=%s\n", config_type); + +		if (secs[i].config_type == DVBSEC_CONFIG_ADVANCED) { +			if (secs[i].adv_cmd_lo_h[0]) +				fprintf(f, "cmd-lo-h=%s\n", secs[i].adv_cmd_lo_h); +			if (secs[i].adv_cmd_lo_v[0]) +				fprintf(f, "cmd-lo-v=%s\n", secs[i].adv_cmd_lo_v); +			if (secs[i].adv_cmd_lo_r[0]) +				fprintf(f, "cmd-lo-r=%s\n", secs[i].adv_cmd_lo_r); +			if (secs[i].adv_cmd_lo_l[0]) +				fprintf(f, "cmd-lo-l=%s\n", secs[i].adv_cmd_lo_l); +			if (secs[i].adv_cmd_hi_h[0]) +				fprintf(f, "cmd-hi-h=%s\n", secs[i].adv_cmd_hi_h); +			if (secs[i].adv_cmd_hi_v[0]) +				fprintf(f, "cmd-hi-v=%s\n", secs[i].adv_cmd_hi_v); +			if (secs[i].adv_cmd_hi_r[0]) +				fprintf(f, "cmd-hi-r=%s\n", secs[i].adv_cmd_hi_r); +			if (secs[i].adv_cmd_hi_l[0]) +				fprintf(f, "cmd-hi-l=%s\n", secs[i].adv_cmd_hi_l); +		} + +		fprintf(f, "\n"); +	} + +	return 0; +} + +static struct dvbsec_config defaults[] = { + +	{ +		.id = "NULL", +		.config_type = DVBSEC_CONFIG_STANDARD, +	}, +	{ +		.id = "UNIVERSAL", +		.switch_frequency = 11700000, +		.lof_lo_v = 9750000, +		.lof_lo_h = 9750000, +		.lof_hi_v = 10600000, +		.lof_hi_h = 10600000, +		.config_type = DVBSEC_CONFIG_STANDARD, +	}, +	{ +		.id = "DBS", +		.switch_frequency = 0, +		.lof_lo_v = 11250000, +		.lof_lo_h = 11250000, +		.config_type = DVBSEC_CONFIG_STANDARD, +	}, +	{ +		.id = "STANDARD", +		.switch_frequency = 0, +		.lof_lo_v = 10000000, +		.lof_lo_h = 10000000, +		.config_type = DVBSEC_CONFIG_STANDARD, +	}, +	{ +		.id = "ENHANCED", +		.switch_frequency = 0, +		.lof_lo_v = 9750000, +		.lof_lo_h = 9750000, +		.config_type = DVBSEC_CONFIG_STANDARD, +	}, +	{ +		.id = "C-BAND", +		.switch_frequency = 0, +		.lof_lo_v = 5150000, +		.lof_lo_h = 5150000, +		.config_type = DVBSEC_CONFIG_POWER, +	}, +	{ +		.id = "C-MULTI", +		.switch_frequency = 0, +		.lof_lo_v = 5150000, +		.lof_lo_h = 5750000, +		.config_type = DVBSEC_CONFIG_POWER, +	}, +}; +#define defaults_count (sizeof(defaults) / sizeof(struct dvbsec_config)) + +static int dvbsec_cfg_find_default(const char *sec_id, +				   struct dvbsec_config *sec) +{ +	unsigned int i; + +	for(i=0; i< defaults_count; i++) { +		if (!strncmp(sec_id, defaults[i].id, sizeof(defaults[i].id))) { +			memcpy(sec, &defaults[i], sizeof(struct dvbsec_config)); +			return 0; +		} +	} + +	return -1; +} diff --git a/lib/libdvbsec/dvbsec_cfg.h b/lib/libdvbsec/dvbsec_cfg.h new file mode 100644 index 0000000..d4546de --- /dev/null +++ b/lib/libdvbsec/dvbsec_cfg.h @@ -0,0 +1,203 @@ +/** + * dvbsec_cfg (i.e. linuxtv SEC format) configuration file support. + * + * Copyright (c) 2006 by Andrew de Quincey <adq_dvb@lidskialf.net> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + */ + +/** + * This library allows SEC (Satellite Equipment Control) configurations + * to be retrieved. Each configuration is identified by a unique satellite_id. + * + * In order to make things as easy as possible for users, there are a set of + * defaults hardcoded into the library covering the majority of LNB types. When + * these are used, the standard back-compatable sequence defined in the DISEQC + * standard will be used - this will suffice for _most_ situations. + * + * UNIVERSAL - Europe, 10800 to 11800 MHz and 11600 to 12700 Mhz, Dual LO, loband 9750, hiband 10600 MHz. + * DBS - Expressvu, North America, 12200 to 12700 MHz, Single LO, 11250 MHz. + * STANDARD - 10945 to 11450 Mhz, Single LO, 10000Mhz. + * ENHANCED - Astra, 10700 to 11700 MHz, Single LO, 9750MHz. + * C-BAND - Big Dish, 3700 to 4200 MHz, Single LO, 5150Mhz. + * C-MULTI - Big Dish - Multipoint LNBf, 3700 to 4200 MHz, Dual LO, H:5150MHz, V:5750MHz. + * + * However, for the power user with a more complex setup, these simple defaults + * are not enough. Therefore, it is also possible to define additional SEC + * configurations in an external configuration file. This file consists of multiple + * entries in the following format: + * + * [sec] + * name=<sec_id> + * switch-frequency=<switching frequency (SLOF)> + * lof-lo-v=<low band + V + frequency> + * lof-lo-h=<low band + H + frequency> + * lof-lo-l=<low band + L + frequency> + * lof-lo-r=<low band + R + frequency> + * lof-hi-v=<high band + V + frequency> + * lof-hi-h=<high band + H + frequency> + * lof-hi-l=<high band + L + frequency> + * lof-hi-r=<high band + R + frequency> + * config-type=<none|power|standard|advanced> + * cmd-lo-v=<sec sequence> + * cmd-lo-h=<sec sequence> + * cmd-lo-r=<sec sequence> + * cmd-lo-l=<sec sequence> + * cmd-hi-v=<sec sequence> + * cmd-hi-h=<sec sequence> + * cmd-hi-r=<sec sequence> + * cmd-hi-l=<sec sequence> + * + * The sec_id is whatever unique value you wish. If it is the same as one of the hardcoded defaults, the configuration + * 	details from the file will be used instead of the hardcoded ones. + * The switch-frequency (or SLOF) indicates the point seperating low band frequencies from high band frequencies. + * 	Set this value to 0 if there is only one frequency band. + * The lof-lo-v is the frequency adjustment for V + low band (i.e. less than SLOF), or is used if switch-frequency==0. + * The lof-lo-h is the frequency adjustment for H + low band (i.e. less than SLOF), or is used if switch-frequency==0. + * The lof-lo-l is the frequency adjustment for L + low band (i.e. less than SLOF), or is used if switch-frequency==0. + * The lof-lo-r is the frequency adjustment for R + low band (i.e. less than SLOF), or is used if switch-frequency==0. + * The lof-hi-v is the frequency adjustment for V + high band (unused if switch-frequency==0). + * The lof-hi-h is the frequency adjustment for H + high band (unused if switch-frequency==0). + * The lof-hi-l is the frequency adjustment for L + high band (unused if switch-frequency==0). + * The lof-hi-r is the frequency adjustment for R + high band (unused if switch-frequency==0). + * + * config-type indicates the desired type of SEC command to use, it may be: + * 	none - No SEC commands will be issued (frequency adjustment will still be performed). + * 	power - Only the SEC power is turned on. + * 	standard - The standard DISEQC back compatable sequence will be issued. + * 	advanced - The DISEQC sequence described in the appropriate sec cmd string will be used. + * + * The cmd-<lo|hi>-<v|h|l|r> describes the SEC cmd string to use in advanced mode for each of the possible combinations of + * frequency band and polarisation. If a certain combination is not required, it may be omitted. It consists of a + * space seperated combination of commands - those available are as follows: + * + *	tone(<0|1>)  - control the 22kHz tone 0:off, 1:on + *	voltage(<0|13|18>) - control the LNB voltage 0v, 13v, or 18v + * 	toneburst(<a|b>) - issue a toneburst (mini command) for position A or B. + *	highvoltage(<0|1>) - control high lnb voltage for long cable runs 0: normal, 1:add 1v to LNB voltage. + *	dishnetworks(<integer>) - issue a dishnetworks legacy command. + *	wait(<integer>) - wait for the given number of milliseconds. + *	Dreset(<address>, <0|1>) - control the reset state of a DISEC device, 0:disable reset, 1:enable reset. + *	Dpower(<address>, <0|1>) - control the power of a DISEC device, 0:off, 1:on. + *	Dcommitted(<address>, <h|l|x>, <v|h|l|r|x>, <a|b|x>, <a|b|x>) - Write to the committed switches of a DISEC device. + * 		The parameters are for band, polarisation, satelliteposition, switchoption: + * 			band - h:high band, l:low band + * 			polarisation - v: vertical, h:horizontal,r:right,l:left + * 			satelliteposition - a:position A, b: position B + * 			switchoption - a:position A, b: position B + * 		The special value 'x' means "no change to this switch". + * + *	Duncommitted(<address>, <a|b|x>, <a|b|x>, <a|b|x>, <a|b|x>) - Write to the uncommitted switches of the a DISEC device. + * 		The parameters are for switch1, switch2, switch3, switch4, and may be set to position a or b. + * 		The special value 'x' means "no change to this switch". + * + * 	Dfrequency(<address>, <frequency in GHz>) - set the frequency of a DISEC device. + * 	Dchannel(<address>, <channel id>) - set the desired channel id of a DISEC device. + * 	Dgotopreset(<address>, <preset id>) - tell a DISEC satellite positioner to move to the given preset id. + * 	Dgotobearing(<address>, <bearing in degrees>) - tell a DISEQC terrestrial rotator to go to the + *		given bearing (range -256.0 -> 512.0 degrees, fractions allowed). + * + * 	In the above DISEQC commands, <address> is the integer (normally in hex format) address of the + * 		diseqc device to communicate with. A list of possiblities is as follows: + * + * 	DISEQC_ADDRESS_ANY_DEVICE		= 0x00 + * + *	DISEQC_ADDRESS_ANY_LNB_SWITCHER_SMATV	= 0x10 + *	DISEQC_ADDRESS_LNB			= 0x11 + *	DISEQC_ADDRESS_LNB_WITH_LOOP		= 0x12 + *	DISEQC_ADDRESS_SWITCHER			= 0x14 + *	DISEQC_ADDRESS_SWITCHER_WITH_LOOP	= 0x15 + *	DISEQC_ADDRESS_SMATV			= 0x18 + * + *	DISEQC_ADDRESS_ANY_POLARISER		= 0x20 + *	DISEQC_ADDRESS_LINEAR_POLARISER		= 0x21 + * + *	DISEQC_ADDRESS_ANY_POSITIONER		= 0x30 + *	DISEQC_ADDRESS_POLAR_AZIMUTH_POSITIONER	= 0x31 + *	DISEQC_ADDRESS_ELEVATION_POSITIONER	= 0x32 + * + *	DISEQC_ADDRESS_ANY_INSTALLER_AID	= 0x40 + *	DISEQC_ADDRESS_SIGNAL_STRENGTH		= 0x41 + * + *	DISEQC_ADDRESS_ANY_INTERFACE		= 0x70 + *	DISEQC_ADDRESS_HEADEND_INTERFACE	= 0x71 + * + *	DISEQC_ADDRESS_REALLOC_BASE		= 0x60 + *	DISEQC_ADDRESS_OEM_BASE			= 0xf0 + */ + +#ifndef DVBSEC_CFG_H +#define DVBSEC_CFG_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdio.h> +#include <stdint.h> +#include <libdvbsec/dvbsec_api.h> + +/** + * Callback function used in dvbsec_cfg_load(). + * + * @param arg Private information to caller. + * @param channel The current channel details. + * @return 0 to continue, 1 to stop loading. + */ +typedef int (*dvbsec_cfg_callback)(void *arg, struct dvbsec_config *sec); + +/** + * Load an SEC file. + * + * @param f File to load from. + * @param arg Value to pass to 'arg' in callback above. + * @param cb Callback function called for each sec loaded from the file. + * @return 0 on success, or nonzero error code on failure. + */ +extern int dvbsec_cfg_load(FILE *f, void *arg, +			   dvbsec_cfg_callback cb); + +/** + * Convenience function to parse an SEC config file. This will also consult the set + * of hardcoded defaults if no config file was supplied, or a match was not found in + * the config file. + * + * @param config_file Config filename to load, or NULL to just check defaults. + * @param sec_id ID of SEC configuration. + * @param sec Where to put the details if found. + * @return 0 on success, nonzero on error. + */ +extern int dvbsec_cfg_find(const char *config_file, +			   const char *sec_id, +			   struct dvbsec_config *sec); + +/** + * Save SEC format config file. + * + * @param f File to save to. + * @param secs Pointer to array of SECs to save. + * @param count Number of entries in the above array. + * @return 0 on success, or nonzero error code on failure. + */ +extern int dvbsec_cfg_save(FILE *f, +			   struct dvbsec_config *secs, +			   int count); + +#ifdef __cplusplus +} +#endif + +#endif | 
