Logo Search packages:      
Sourcecode: w-scan version File versions  Download package

parse-dvbscan.c

/*
 * Simple MPEG/DVB parser to achieve network/service information without initial tuning data
 *
 * Copyright (C) 2006, 2007, 2008, 2009 Winfried Koehler 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 * The author can be reached at: handygewinnspiel AT gmx DOT de
 *
 * The project's page is http://wirbel.htpc-forum.de/w_scan/index2.html
 */


/******************************************************************************
 * reading dvbscan initial_tuning_data.
 * 
 * NOTE: READBACK IS *ONLY* GUARANTEED IF FILES ARE GENERATED BY w_scan AND
 * NOT MODIFIED. WORKING WITHOUT INIT TRANSPONDER FILES IS MAIN PHILOSOPHY.
 *
 * readback not tested yet. - added wk 20090303 -
 *****************************************************************************/


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <linux/dvb/frontend.h>
#include "scan.h"
#include "parse-dvbscan.h"
#include "dvbscan.h"
#include "satellites.h"
#include "dump-vdr.h"

#define MAX_LINE_LENGTH 1024  // paranoia, but still possible
#define DELIMITERS    " \r\n\t"

enum __dvbscan_args {
      qpsk_frequency,
      qpsk_polarization,
      qpsk_symbol_rate,
      qpsk_fec_inner,
      qpsk_rolloff,           // optional
      qpsk_modulation,  // optional
      qpsk_END_READING,
      qam_frequency,
      qam_symbol_rate,
      qam_fec_inner,
      qam_modulation,
      qam_END_READING,  
      ofdm_frequency,
      ofdm_bandwidth,
      ofdm_fec_high_priority,
      ofdm_fec_low_priority,
      ofdm_modulation,
      ofdm_transmission_mode,
      ofdm_guard_interval,
      ofdm_hierarchy,
      ofdm_END_READING,
      atsc_frequency,
      atsc_modulation,
      atsc_END_READING,
      end_of_line,
      STOP,
};

enum __extflags {
      ignore,
      wscan_version,
      tuning_timeout,
      filter_timeout,
      fe_type,
      list_idx
};


void parse_w_scan_flags(const char * input_buffer, struct w_scan_flags * flags) {
      char *copy = (char *) malloc(strlen(input_buffer) + 1);
      char *token = strtok(copy, DELIMITERS);
      enum __extflags arg = ignore;

      strcpy(copy, input_buffer);
      if (NULL == token) {
            free(copy);
            return;
            }
      while (NULL != (token = strtok(0, DELIMITERS))) {
            if (0 == strcasecmp(token, "<w_scan>")) {
                  arg = wscan_version;
                  continue;
                  }
            if (0 == strcasecmp(token, "</w_scan>")) {
                  arg = ignore;
                  continue;
                  }
            switch(arg++) {
                  case wscan_version:
                        flags->version = strtoul(token, NULL, 10);
                        break;
                  case tuning_timeout:
                        flags->tuning_timeout = strtoul(token, NULL, 10);
                        break;
                  case filter_timeout:
                        flags->filter_timeout = strtoul(token, NULL, 10);
                        break;
                  case fe_type:
                        flags->fe_type = txt_to_fe_type(token);
                        break;                        
                  case list_idx:
                        flags->list_id = strtoul(token, NULL, 10);
                        break;
                  case ignore:
                  default:
                        continue;
                  }
            }
      free(copy);
}

int dvbscan_parse_tuningdata(const char * tuningdata, struct w_scan_flags * flags) {
      FILE * initdata = NULL;
      char * buf = (char *) malloc(MAX_LINE_LENGTH);
      enum __dvbscan_args arg;
      struct transponder * tn;
      int count = 0;

      if (tuningdata == NULL) {
            error("could not open initial tuning data: file name is NULL\n");
            return 0; // err
            }
      info("parsing initial tuning data \"%s\"..\n", tuningdata);
      initdata = fopen(tuningdata, "r");
      if (initdata == NULL) {
            error("cannot open '%s': error %d %m\n", tuningdata, errno);
            return 0; // err
            }
      memset(buf, 0, sizeof(buf));
      while (fgets(buf, MAX_LINE_LENGTH, initdata) != NULL) {
            char * copy = (char *) malloc(strlen(buf) + 1);
            char * token;

            if (copy == NULL) {
                  fatal("Could not allocate memory.\n");
                  }
            memset(&tn, 0, sizeof(tn));
            /* strtok will modify it's first argument, but working 
             * on a copy is safe. Be really careful here -
             * 'copy' should NOT be referred to after usage of strtok()
             * -wk-
             */
            strcpy(copy, buf);
            token = strtok(copy, DELIMITERS);
            if (NULL == token)
                  continue;
            switch (toupper(token[0])) {
                  case 'A':
                        tn = alloc_transponder(0);
                        tn->type = FE_ATSC;
                        break;
                  case 'C':
                        tn = alloc_transponder(0);
                        tn->type = FE_QAM;
                        break;
                  case 'S':
                        tn = alloc_transponder(0);
                        tn->type = FE_QPSK;
                        break;
                  case 'T':
                        tn = alloc_transponder(0);
                        tn->type = FE_OFDM;
                        break;
                  case '#':
                        if (strlen(token) > 2)
                              switch (token[1]) {
                                    case '!':
                                          parse_w_scan_flags(buf, flags);
                                          continue;
                                    default:;
                                    }
                        continue;
                  default:
                        error("could not parse %s\n", tuningdata);
                        return 0; // err
                  }
            flags->fe_type = tn->type;
            switch (tn->type) {
                  case FE_QPSK:
                        tn->param.u.qpsk.modulation_system = SYS_DVBS;
                        if (strlen(token) >= 2)
                              if (token[1] == '2') {
                                    flags->need_2g_fe = 1;
                                    tn->param.u.qpsk.modulation_system = SYS_DVBS2;
                                    }
                        arg = qpsk_frequency;
                        tn->param.inversion = INVERSION_AUTO;
                        tn->param.u.qpsk.fec_inner = FEC_AUTO;
                        tn->param.u.qpsk.pilot = PILOT_AUTO;
                        tn->param.u.qpsk.modulation_type = QPSK;
                        tn->param.u.qpsk.rolloff = ROLLOFF_35;
                        break;
                  case FE_QAM:
                        tn->param.u.qam.delivery_system = SYS_DVBC_ANNEX_AC;
                        if (strlen(token) >= 2)
                              if (token[1] == '2') {
                                    flags->need_2g_fe = 1;
                                    }
                        arg = qam_frequency;
                        tn->param.inversion = INVERSION_AUTO;
                        tn->param.u.qam.modulation = QAM_AUTO;
                        tn->param.u.qam.symbol_rate = 6900000;
                        tn->param.u.qam.fec_inner = FEC_NONE;
                        break;
                  case FE_OFDM:
                        tn->param.u.ofdm.delivery_system = SYS_DVBT;
                        if (strlen(token) >= 2)
                              if (token[1] == '2') {
                                    flags->need_2g_fe = 1;
                                    }
                        arg = ofdm_frequency;
                        tn->param.inversion = INVERSION_AUTO;
                        tn->param.u.ofdm.bandwidth = BANDWIDTH_AUTO;
                        tn->param.u.ofdm.code_rate_HP = FEC_AUTO;
                        tn->param.u.ofdm.code_rate_LP = FEC_NONE;
                        tn->param.u.ofdm.constellation = QAM_AUTO;
                        tn->param.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
                        tn->param.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
                        tn->param.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
                        break;
                  case FE_ATSC:
                        tn->param.u.vsb.delivery_system = SYS_ATSC;
                        if (strlen(token) >= 2)
                              if (token[1] == '2') {
                                    flags->need_2g_fe = 1;
                                    }
                        arg = atsc_frequency;
                        tn->param.inversion = INVERSION_AUTO;
                        tn->param.u.vsb.modulation = VSB_8;
                        break;
                  default:
                        error("could not parse '%s' - undefined fe_type\n", buf);
                        return 0; // err
                  }

            while (NULL != (token = strtok(0, DELIMITERS))) {
                  switch (arg++) {
                        case qpsk_frequency:
                        case qam_frequency:
                        case ofdm_frequency:
                        case atsc_frequency:
                              tn->param.frequency = strtoul(token, NULL, 10);
                              break;
                        case qpsk_polarization:
                              tn->param.u.qpsk.polarization = txt_to_qpsk_pol(token);
                              break;
                        case qpsk_symbol_rate:
                              tn->param.u.qpsk.symbol_rate = strtoul(token, NULL, 10);
                              break;
                        case qpsk_fec_inner:
                              tn->param.u.qpsk.fec_inner = txt_to_qpsk_fec(token);
                              count++;
                              break;
                        case qpsk_rolloff:
                              tn->param.u.qpsk.rolloff = txt_to_qpsk_rolloff(token);
                              break;
                        case qpsk_modulation:
                              tn->param.u.qpsk.modulation_type = txt_to_qpsk_mod(token);
                              break;
                        case qam_symbol_rate:
                              tn->param.u.qam.symbol_rate = strtoul(token, NULL, 0);
                              break;
                        case qam_fec_inner:
                              tn->param.u.qam.fec_inner = txt_to_qam_fec(token);
                              break;
                        case qam_modulation:
                              tn->param.u.qam.modulation = txt_to_qam_mod(token);
                              count++;
                              break;
                        case ofdm_bandwidth:
                              tn->param.u.ofdm.bandwidth = txt_to_ofdm_bw(token);
                              break;
                        case ofdm_fec_high_priority:
                              tn->param.u.ofdm.code_rate_HP = txt_to_ofdm_fec(token);
                              break;
                        case ofdm_fec_low_priority:
                              tn->param.u.ofdm.code_rate_LP = txt_to_ofdm_fec(token);
                              break;
                        case ofdm_modulation:
                              tn->param.u.ofdm.constellation = txt_to_ofdm_mod(token);
                              break;
                        case ofdm_transmission_mode:
                              tn->param.u.ofdm.transmission_mode = txt_to_ofdm_transmission(token);
                              break;
                        case ofdm_guard_interval:
                              tn->param.u.ofdm.guard_interval = txt_to_ofdm_guard(token);
                              break;
                        case ofdm_hierarchy:
                              tn->param.u.ofdm.hierarchy_information = txt_to_ofdm_hierarchy(token);
                              count++;
                              break;
                        case atsc_modulation:
                              tn->param.u.vsb.modulation = txt_to_atsc_mod(token);
                              count++;
                              break;
                        case qam_END_READING:
                        case qpsk_END_READING:
                        case ofdm_END_READING:
                        case atsc_END_READING:
                        case end_of_line:
                        case STOP:
                        default:
                              arg = end_of_line;                        
                              break;
                        }
                  if ((arg == STOP) || (arg == end_of_line))
                        break;
                  }
            free(copy);
            copy = NULL;
            memset(buf, 0, sizeof(buf));
            print_transponder(buf, tn);
            info("\ttransponder %s\n", buf);
            memset(buf, 0, sizeof(buf));        
            }
      free(buf);
      fclose(initdata);
      if (count == 0) {
            info("Unexpected end of file..\n");
            return 0;
            }
      return 1; // success
}

/*****************************************************************************/

/******************************************************************************
 * reading rotor configuration.
 * 
 * NOTE: READING IS *ONLY* GUARANTEED IF FILES ARE USING FILE FORMAT AS
 * DESCRIBED IN doc/README.file_formats
 *
 * NOTE: VDR plugin 'rotor' rotor.conf file format is inofficially supported
 * too, but reading is not guaranteed. So don't bother me is some files in this
 * file format are not accepted. wk 20090501 -
 *****************************************************************************/


enum __rotor_args {     
      rotor_position,
      sat_id,
      end_of_line_rotor,
      READ_STOP,
      plug_rotor_sat_id,
      plug_rotor_rotor_position
};

enum __rotor_file_formats {
      rotor_fileformat_undef,
      rotor_fileformat_wscan,
      rotor_fileformat_vdrpluginrotor
};

struct pos_item {
      int         position;
      char *            id;
};

#define ROTOR_DELIMITERS    " \t=\r\n"

/* 
 * needs to be kept in sync with vdr's source enum (sat only)
 */
enum vdr_source_types {
      stNone  = 0x0000,
      stSat   = 0x8000,
      st_Mask = 0xC000,
      st_Neg  = 0x0800,
      st_Pos  = 0x07FF,
      };

/*
 * convert a string token to source-id used by vdr (sat only)
 */
int vdr_code_from_token(const char * token) {
      int code = -1;
      int pos = 0;
      int dot = 0;
      int neg = 0;

      switch (toupper(*token)) {
            case 'S':
                  code = stSat;
                  break;
            default:
                  fatal("%s: could not parse %s\n",
                        __FUNCTION__, token);
            }

      while (*++token) {
            switch (toupper(*token)) {
                  case '0' ... '9':
                        pos *= 10;
                        pos += *token - '0';
                        break;
                  case '.':
                        dot++;
                        break;
                        case 'E':
                        neg++; // no break, fall through
                        case 'W':
                        if (!dot)
                              pos *= 10;
                        break;
                        default: fatal("%s: unknown source character '%c'",
                              __FUNCTION__, *token);
                  }
            }
      if (neg)
            pos |= st_Neg;
      code |= pos;
      return code;
}

/*
 * convert a source-id used by vdr to the matching string used in channels.conf
 * (sat only). returned value is copied to buffer.
 */
void vdr_source_to_str(int id, char * buffer, int bufsize) {
      char *q = buffer;
      switch (id & st_Mask) {
            case stSat: *q++ = 'S';
                  {
                  int pos = id & ~st_Mask;
                  if ((pos & ~st_Neg) % 10)
                        q += snprintf(q, bufsize - 2, "%u.%u",
                              (pos & ~st_Neg) / 10,
                              (pos & ~st_Neg) % 10);
                  else
                        q += snprintf(q, bufsize - 2, "%u",
                              (pos & ~st_Neg) / 10);
                  *q++ = (id & st_Neg) ? 'E' : 'W';
                  }
                  break;
            default:
                  *q++ = id + '0';
            }
      *q = 0;
}

/*
 * parse a rotor.conf in w_scans file format.
 *
 * file format as described in doc/README.file_formats
 * # R <position> <satellite id>    [# comment]
 * R  1           S4E8
 * R  7           S19E2
 *
 * - satellite_id has to match w_scans identifiers, see option -s
 * - rotor position 1..255 (positions < 1 are ignored)
 * -------------------------------------------------------------
 * NOTE: the rotor.conf from vdr 'rotor' plugin is also accepted,
 * but not officially supported:
 * S4.8E = 1
 * S19.2E = 7
 * -------------------------------------------------------------
 */
int dvbscan_parse_rotor_positions(const char * positiondata) {
      FILE * data = NULL;
      char * buf = (char *) malloc(MAX_LINE_LENGTH);
      enum __rotor_args arg = end_of_line_rotor;
      enum __rotor_file_formats fformat = rotor_fileformat_undef;
      struct pos_item item = {0, NULL};
      int count = 0;

      if (positiondata == NULL) {
            error("could not open rotor position tuning data: file name is NULL\n");
            return 0; // err
            }
      info("parsing rotor data \"%s\"..\n", positiondata);
      data = fopen(positiondata, "r");
      if (data == NULL) {
            error("cannot open '%s': error %d %m\n", positiondata, errno);
            return 0; // err
            }
      memset(buf, 0, sizeof(buf));
      while (fgets(buf, MAX_LINE_LENGTH, data) != NULL) {
            char * copy = (char *) malloc(strlen(buf) + 1);
            char * token;
      
            if (copy == NULL)
                  fatal("Could not allocate memory.\n");

            strcpy(copy, buf);
            token = strtok(copy, ROTOR_DELIMITERS);
            if (NULL == token)
                  continue;

            switch (toupper(token[0])) {
                  case 'R':
                        arg = rotor_position;
                        fformat = rotor_fileformat_wscan;
                        break;
                  case 'S':
                        {
                        char buffer[16];
                        int code = vdr_code_from_token(token);
                        vdr_source_to_str(code, buffer, sizeof(buffer));
                        item.id = (char *) malloc(strlen(vdr_name_to_short_name(buffer))+1);
                        strcpy(item.id, vdr_name_to_short_name(buffer));
                        arg = plug_rotor_rotor_position;
                        fformat = rotor_fileformat_vdrpluginrotor;
                        break;
                        }
                  case '#':
                        continue;
                  default:
                        error("could not parse %s\n", positiondata);
                        goto err;                     
                  }           

            while (NULL != (token = strtok(0, DELIMITERS))) {
                  switch (arg++) {
                        case rotor_position:
                              switch (toupper(token[0])) {
                                    case '0' ... '9':
                                          item.position = strtoul(token, NULL, 10);
                                          if (item.position < 1)
                                                continue;
                                          break;
                                    case '-':
                                          item.position = -1;
                                          arg = end_of_line_rotor;
                                          continue;
                                    default:
                                          error("could not parse %s\n", positiondata);
                                          goto err;
                                    }
                        case sat_id:
                              if (item.id)
                                    free(item.id);
                              item.id = (char *) malloc(strlen(token)+1);
                              strcpy(item.id, token);
                              break;
                        case plug_rotor_rotor_position:
                              if (! strcmp("=", token)) {
                                    // fixme: we hit a "=" 
                                    arg--;
                                    break;
                                    }
                              switch (toupper(token[0])) {
                                    case '0' ... '9':
                                          item.position = strtoul(token, NULL, 10);
                                          if (item.position < 1)
                                                continue;
                                          break;
                                    case '-':
                                          item.position = -1;
                                          arg = end_of_line_rotor;
                                          continue;
                                    default:
                                          error("could not parse %s\n", positiondata);
                                          goto err;
                                    }
                        case end_of_line_rotor:
                        case READ_STOP:
                        default:
                              arg = end_of_line;                        
                              break;
                        }
                  if ((arg == STOP) || (arg == end_of_line))
                        break;
                  }
            free(copy);
            copy = NULL;
            if (item.position > 0) {
                  if (txt_to_satellite(item.id) < 0) {
                        info("Satellite ID \"%s\" not defined.\n", item.id);
                        goto err;
                        }
                  if (item.position > 255) {
                        info("Invalid satellite position %d.\n", item.position);
                        goto err;
                        }
                  sat_list[txt_to_satellite(item.id)].rotor_position = item.position;
                  count++;    
                  info("\trotor position %3d = %6s\n", item.position, item.id);
                  }
            memset(buf, 0, sizeof(buf));        
            }
      if (item.id)
            free(item.id);
      free(buf);
      fclose(data);
      if (count == 0) {
            info("Unexpected end of file..\n");
            return 0;
            }
      return 1; // success
err:
      // clean up and leave with error.
      info("line causing error was \n\"%s\n", buf);
      if (item.id)
            free(item.id);
      free(buf);
      fclose(data);
      return 0; //err
}

Generated by  Doxygen 1.6.0   Back to index