diff options
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 |