#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <argp.h>
 
#ifdef ENABLE_NLS
# define _(string) gettext(string)
# include "gettext.h"
# include <locale.h>
# include <langinfo.h>
# include <iconv.h>
#else
# define _(string) string
#endif
 
# define N_(string) string
 
#include <linux/dvb/dmx.h>
 
#define PROGRAM_NAME    "dvbv5-scan"
#define DEFAULT_OUTPUT  "dvb_channel.conf"
 
const char *argp_program_version = PROGRAM_NAME " version " V4L_UTILS_VERSION;
const char *argp_program_bug_address = "Mauro Carvalho Chehab <mchehab@kernel.org>";
 
struct arguments {
        char *confname, *lnb_name, *output, *demux_dev;
        unsigned adapter, n_adapter, adapter_fe, adapter_dmx, frontend, demux, get_detected, get_nit;
        int lna, lnb, sat_number, freq_bpf;
        unsigned diseqc_wait, dont_add_new_freqs, timeout_multiply;
        unsigned other_nit;
        const char *cc;
 
        
        unsigned n_status_lines;
};
 
static const struct argp_option options[] = {
        {"adapter",     'a',    N_("adapter#"),         0, N_("use given adapter (default 0)"), 0},
        {"frontend",    'f',    N_("frontend#"),        0, N_("use given frontend (default 0)"), 0},
        {"demux",       'd',    N_("demux#"),           0, N_("use given demux (default 0)"), 0},
        {"lnbf",        'l',    N_("LNBf_type"),        0, N_("type of LNBf to use. 'help' lists the available ones"), 0},
        {"lna",         'w',    N_("LNA (0, 1, -1)"),   0, N_("enable/disable/auto LNA power"), 0},
        {"sat_number",  'S',    N_("satellite_number"), 0, N_("satellite number. If not specified, disable DISEqC"), 0},
        {"freq_bpf",    'U',    N_("frequency"),        0, N_("SCR/Unicable band-pass filter frequency to use, in kHz"), 0},
        {"wait",        'W',    N_("time"),             0, N_("adds additional wait time for DISEqC command completion"), 0},
        {"nit",         'N',    NULL,                   0, N_("use data from NIT table on the output file"), 0},
        {"get_frontend",'G',    NULL,                   0, N_("use data from get_frontend on the output file"), 0},
        {"verbose",     'v',    NULL,                   0, N_("be (very) verbose"), 0},
        {"output",      'o',    N_("file"),             0, N_("output filename (default: ") DEFAULT_OUTPUT ")", 0},
        {"file-freqs-only", 'F', NULL,                  0, N_("don't use the other frequencies discovered during scan"), 0},
        {"timeout-multiply", 'T', N_("factor"),         0, N_("Multiply scan timeouts by this factor"), 0},
        {"parse-other-nit", 'p', NULL,                  0, N_("Parse the other NIT/SDT tables"), 0},
        {"input-format", 'I',   N_("format"),           0, N_("Input format: CHANNEL, DVBV5 (default: DVBV5)"), 0},
        {"output-format", 'O',  N_("format"),           0, N_("Output format: VDR, CHANNEL, ZAP, DVBV5 (default: DVBV5)"), 0},
        {"cc",          'C',    N_("country_code"),     0, N_("Set the default country to be used (in ISO 3166-1 two letter code)"), 0},
        {"help",        '?',    0,              0,      N_("Give this help list"), -1},
        {"usage",       -3,     0,              0,      N_("Give a short usage message")},
        {"version",     'V',    0,              0,      N_("Print program version"), -1},
        { 0, 0, 0, 0, 0, 0 }
};
 
static int verbose = 0;
#define CHANNEL_FILE "channels.conf"
 
#define ERROR(x...)                                                     \
        do {                                                            \
                fprintf(stderr, _("ERROR: "));                             \
                fprintf(stderr, x);                                     \
                fprintf(stderr, "\n");                                 \
        } while (0)
 
#define PERROR(x...)                                                    \
        do {                                                            \
                fprintf(stderr, _("ERROR: "));                             \
                fprintf(stderr, x);                                     \
                fprintf(stderr, " (%s)\n", strerror(errno));            \
        } while (0)
 
static int print_frontend_stats(struct arguments *args,
{
        char buf[512], *p;
        int rc, i, len, show;
        uint32_t status = 0;
 
        
        if (isatty(STDERR_FILENO) && args->n_status_lines)
                fprintf(stderr, "\r\x1b[%dA\x1b[J", args->n_status_lines);
 
        args->n_status_lines = 0;
 
        if (isatty(STDERR_FILENO)) {
                if (rc)
                        status = 0;
                if (status & FE_HAS_LOCK)
                        fprintf(stderr, "\x1b[1;32m");
                else
                        fprintf(stderr, "\x1b[33m");
        }
 
        p = buf;
        len = sizeof(buf);
 
        for (i = 0; i < MAX_DTV_STATS; i++) {
                show = 1;
 
                                     i, &p, &len, &show);
 
                                     i, &p, &len, &show);
 
                                     i, &p, &len, &show);
 
                                     i,  &p, &len, &show);
 
                                     i,  &p, &len, &show);
 
                                     i,  &p, &len, &show);
 
                                     i,  &p, &len, &show);
 
                if (p != buf) {
                        if (args->n_status_lines)
                                fprintf(stderr, "\t%s\n", buf);
                        else
                                fprintf(stderr, "%s\n", buf);
 
                        args->n_status_lines++;
 
                        p = buf;
                        len = sizeof(buf);
                }
        }
 
        fflush(stderr);
 
        return 0;
}
 
static int check_frontend(void *__args,
{
        struct arguments *args = __args;
        int rc, i;
        fe_status_t status;
 
        args->n_status_lines = 0;
        for (i = 0; i < args->timeout_multiply * 40; i++) {
                        return 0;
                if (rc)
                        PERROR(_("dvb_fe_get_stats failed"));
 
                if (rc)
                        status = 0;
                print_frontend_stats(args, parms);
                if (status & FE_HAS_LOCK)
                        break;
                usleep(100000);
        };
 
        if (isatty(STDERR_FILENO)) {
                fprintf(stderr, "\x1b[0m");
        }
 
        return (status & FE_HAS_LOCK) ? 0 : -1;
}
 
static int run_scan(
struct arguments *args, 
struct dvb_device *dvb)
 
{
        int count = 0, shift;
        uint32_t freq, sys;
 
        
        case SYS_DVBT:
        case SYS_DVBS:
        case SYS_DVBC_ANNEX_A:
        case SYS_ATSC:
                break;
        case SYS_DVBC_ANNEX_C:
                sys = SYS_DVBC_ANNEX_A;
                break;
        case SYS_DVBC_ANNEX_B:
                sys = SYS_ATSC;
                break;
        case SYS_ISDBT:
        case SYS_DTMB:
                sys = SYS_DVBT;
                break;
        default:
                sys = SYS_UNDEFINED;
                break;
        }
                                    args->input_format);
                return -2;
 
        
        if (!dmx_fd) {
                perror(_("opening demux failed"));
                return -3;
        }
 
                uint32_t stream_id;
 
                
                        continue;
                shift = dvb_estimate_freq_shift(parms);
 
 
                        stream_id = NO_STREAM_ID_FILTER;
 
                                                  freq, shift, pol, stream_id))
                        continue;
 
                count++;
                dvb_log(_("Scanning frequency #%d %d"), count, freq);
 
                
 
                
 
                                                &check_frontend, args,
                                                args->other_nit,
                                                args->timeout_multiply);
 
                        break;
                }
                if (!dvb_scan_handler)
                        continue;
 
                
                                  args->get_detected, args->get_nit);
 
                
                if (!args->dont_add_new_freqs)
 
                
 
        }
 
        if (dvb_file_new)
 
        if (dvb_file_new)
 
        return 0;
}
 
static error_t parse_opt(int k, char *optarg, struct argp_state *state)
{
        struct arguments *args = state->input;
        switch (k) {
        case 'a':
                args->adapter = strtoul(optarg, NULL, 0);
                args->n_adapter++;
                break;
        case 'f':
                args->frontend = strtoul(optarg, NULL, 0);
                args->adapter_fe = args->adapter;
                break;
        case 'd':
                args->demux = strtoul(optarg, NULL, 0);
                args->adapter_dmx = args->adapter;
                break;
        case 'w':
                if (!strcasecmp(optarg,"on")) {
                        args->lna = 1;
                } else if (!strcasecmp(optarg,"off")) {
                        args->lna = 0;
                } else if (!strcasecmp(optarg,"auto")) {
                        args->lna = LNA_AUTO;
                } else {
                        int val = strtoul(optarg, NULL, 0);
                        if (!val)
                                args->lna = 0;
                        else if (val > 0)
                                args->lna = 1;
                        else
                                args->lna = LNA_AUTO;
                }
                break;
        case 'l':
                args->lnb_name = optarg;
                break;
        case 'S':
                args->sat_number = strtoul(optarg, NULL, 0);
                break;
        case 'U':
                args->freq_bpf = strtoul(optarg, NULL, 0);
                break;
        case 'W':
                args->diseqc_wait = strtoul(optarg, NULL, 0);
                break;
        case 'N':
                args->get_nit++;
                break;
        case 'G':
                args->get_detected++;
                break;
        case 'F':
                args->dont_add_new_freqs++;
                break;
        case 'p':
                args->other_nit++;
                break;
        case 'v':
                verbose++;
                break;
        case 'T':
                args->timeout_multiply = strtoul(optarg, NULL, 0);
                break;
        case 'I':
                break;
        case 'O':
                break;
        case 'o':
                args->output = optarg;
                break;
        case 'C':
                args->cc = strndup(optarg, 2);
                break;
        case '?':
                argp_state_help(state, state->out_stream,
                                ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG
                                | ARGP_HELP_DOC);
                fprintf(state->out_stream, _("\nReport bugs to %s.\n"), argp_program_bug_address);
                exit(0);
        case 'V':
                fprintf (state->out_stream, "%s\n", argp_program_version);
                exit(0);
        case -3:
                argp_state_help(state, state->out_stream, ARGP_HELP_USAGE);
                exit(0);
        default:
                return ARGP_ERR_UNKNOWN;
        };
        return 0;
}
 
static int *timeout_flag;
 
static void do_timeout(int x)
{
        (void)x;
        if (*timeout_flag == 0) {
                *timeout_flag = 1;
                alarm(5);
                signal(SIGALRM, do_timeout);
        } else {
                
                exit(1);
        }
}
 
 
int main(int argc, char **argv)
{
        struct arguments args = {};
        int err, lnb = -1,idx = -1;
        const struct argp argp = {
                .options = options,
                .parser = parse_opt,
                .doc = N_("scan DVB services using the channel file"),
                .args_doc = N_("<initial file>"),
        };
 
#ifdef ENABLE_NLS
        setlocale (LC_ALL, "");
        bindtextdomain (PACKAGE, LOCALEDIR);
        textdomain (PACKAGE);
#endif
 
        memset(&args, 0, sizeof(args));
        args.sat_number = -1;
        args.output = DEFAULT_OUTPUT;
        args.timeout_multiply = 1;
        args.adapter = (unsigned)-1;
        args.lna = LNA_AUTO;
 
        if (argp_parse(&argp, argc, argv, ARGP_NO_HELP | ARGP_NO_EXIT, &idx, &args)) {
                argp_help(&argp, stderr, ARGP_HELP_SHORT_USAGE, PROGRAM_NAME);
                return -1;
        }
 
        if (args.timeout_multiply == 0)
                args.timeout_multiply = 1;
 
        if (args.n_adapter == 1) {
                args.adapter_fe = args.adapter;
                args.adapter_dmx = args.adapter;
        }
 
        if (args.lnb_name) {
                if (lnb < 0) {
                        printf(_("Please select one of the LNBf's below:\n"));
                        exit(1);
                } else {
                        printf(_("Using LNBf "));
                }
        }
 
        if (idx < argc)
                args.confname = argv[idx];
 
        if (!args.confname || idx < 0) {
                argp_help(&argp, stderr, ARGP_HELP_STD_HELP, PROGRAM_NAME);
                return -1;
        }
                fprintf(stderr, _("ERROR: Please specify a valid format\n"));
                argp_help(&argp, stderr, ARGP_HELP_STD_HELP, PROGRAM_NAME);
                return -1;
        }
 
        if (!dvb)
                return -1;
 
        if (!dvb_dev) {
                fprintf(stderr, _("Couldn't find demux device node\n"));
                return -1;
        }
 
        if (verbose)
                fprintf(stderr, _("using demux '%s'\n"), args.demux_dev);
 
        if (!dvb_dev)
                return -1;
 
                free(args.demux_dev);
                return -1;
        }
        if (lnb >= 0)
        if (args.sat_number >= 0)
        if (err < 0)
                fprintf(stderr, _("Failed to set the country code:%s\n"), args.cc);
 
        timeout_flag = &parms->
abort;
        signal(SIGTERM, do_timeout);
        signal(SIGINT, do_timeout);
 
        err = run_scan(&args, dvb);
 
 
        return err;
}
Provides ancillary code to convert ISO 3166-1 country codes.
Provides interfaces to deal with DVB demux.
Provides interfaces to handle Digital TV devices.
struct dvb_dev_list * dvb_dev_seek_by_adapter(struct dvb_device *dvb, unsigned int adapter, unsigned int num, enum dvb_dev_type type)
Find a device that matches the search criteria given by this functions's parameters.
Provides interfaces to deal with DVB channel and program files.
@ FILE_ZAP
File is at the dvb-apps "dvbzap" format.
@ FILE_UNKNOWN
File format is unknown.
@ FILE_DVBV5
File is at libdvbv5 format.
Provides interfaces to scan programs inside MPEG-TS digital TV streams.
Provides libdvbv5 defined properties for the frontend.
void dvb_dev_free(struct dvb_device *dvb)
free a struct dvb_device
struct dvb_open_descriptor * dvb_dev_open(struct dvb_device *dvb, const char *sysname, int flags)
Opens a dvb device.
int dvb_dev_find(struct dvb_device *dvb, dvb_dev_change_t handler, void *user_priv)
finds all DVB devices on the local machine
void dvb_dev_set_log(struct dvb_device *dvb, unsigned verbose, dvb_logfunc logfunc)
Sets the DVB verbosity and log function.
struct dvb_device * dvb_dev_alloc(void)
Allocate a struct dvb_device.
void dvb_dev_close(struct dvb_open_descriptor *open_dev)
Closes a dvb device.
dvb_file_formats
Known file formats.
struct dvb_file * dvb_read_file_format(const char *fname, uint32_t delsys, enum dvb_file_formats format)
Read a file on any format natively supported by the library.
int dvb_retrieve_entry_prop(struct dvb_entry *entry, uint32_t cmd, uint32_t *value)
Retrieves the value associated witha key on a DVB file entry.
int dvb_write_file_format(const char *fname, struct dvb_file *dvb_file, uint32_t delsys, enum dvb_file_formats format)
Write a file on any format natively supported by the library.
static void dvb_file_free(struct dvb_file *dvb_file)
Deallocates memory associated with a struct dvb_file.
int dvb_store_channel(struct dvb_file **dvb_file, struct dvb_v5_fe_parms *parms, struct dvb_v5_descriptors *dvb_desc, int get_detected, int get_nit)
stored a new scanned channel into a dvb_file struct
enum dvb_file_formats dvb_parse_format(const char *name)
Ancillary function that parses the name of a file format.
struct dvb_v5_descriptors * dvb_dev_scan(struct dvb_open_descriptor *open_dev, struct dvb_entry *entry, check_frontend_t *check_frontend, void *args, unsigned other_nit, unsigned timeout_multiply)
Scans a DVB dvb_add_scaned_transponder.
void dvb_add_scaned_transponders(struct dvb_v5_fe_parms *parms, struct dvb_v5_descriptors *dvb_scan_handler, struct dvb_entry *first_entry, struct dvb_entry *entry)
Add new transponders to a dvb_file.
void dvb_scan_free_handler_table(struct dvb_v5_descriptors *dvb_scan_handler)
frees a struct dvb_v5_descriptors
int dvb_fe_set_default_country(struct dvb_v5_fe_parms *parms, const char *country)
Set default country variant of delivery systems like ISDB-T.
#define DTV_BER
Bit Error Rate.
int dvb_fe_retrieve_stats(struct dvb_v5_fe_parms *parms, unsigned cmd, uint32_t *value)
Retrieve the stats for a DTV layer from cache.
int dvb_fe_snprintf_stat(struct dvb_v5_fe_parms *parms, uint32_t cmd, char *display_name, int layer, char **buf, int *len, int *show_layer_name)
Ancillary function to sprintf on ENG format.
#define DTV_STATUS
Lock status of a DTV frontend.
#define DTV_QUALITY
A quality indicator that represents if a locked channel provides a good, OK or poor signal.
#define DTV_PER
Packet Error Rate.
#define DTV_POLARIZATION
Satellite polarization (for Satellite delivery systems)
#define DTV_PRE_BER
Bit Error Rate before Viterbi.
int dvb_fe_get_stats(struct dvb_v5_fe_parms *parms)
Retrieve the stats from the Kernel.
void dvb_print_all_lnb(void)
Prints all LNBf entries at STDOUT.
dvb_sat_polarization
Polarization types for Satellite systems.
int dvb_print_lnb(int index)
prints the contents of a LNBf entry at STDOUT.
const struct dvb_sat_lnb * dvb_sat_get_lnb(int index)
gets a LNBf entry at its internal database
int dvb_sat_search_lnb(const char *name)
search for a LNBf entry
Digital TV device node properties.
Digital TV list of devices.
struct dvb_v5_fe_parms * fe_parms
Represents one entry on a DTV file.
Describes an entire DVB file opened.
struct dvb_entry * first_entry
Opaque struct with a DVB open file descriptor.
Contains the descriptors needed to scan the Service ID and other relevant info at a MPEG-TS Digital T...
Keeps data needed to handle the DVB frontend.
const struct dvb_sat_lnb * lnb
fe_delivery_system_t current_sys