diff options
Diffstat (limited to '')
-rw-r--r-- | util/szap/tzap.c | 344 |
1 files changed, 282 insertions, 62 deletions
diff --git a/util/szap/tzap.c b/util/szap/tzap.c index 2527c23..cd87bfa 100644 --- a/util/szap/tzap.c +++ b/util/szap/tzap.c @@ -1,3 +1,24 @@ +/* tzap -- DVB-T zapping utility + */ + +/* + * Added recording to a file + * arguments: + * + * -t timeout (seconds) + * -o filename output filename (use -o - for stdout) + * -s only print summary + * -S run silently (no output) + * + * Bernard Hatt 24/2/04 + */ + + + +#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE_SOURCE 1 +#define _LARGEFILE64_SOURCE 1 + #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> @@ -9,15 +30,19 @@ #include <fcntl.h> #include <ctype.h> #include <errno.h> +#include <signal.h> #include <linux/dvb/frontend.h> #include <linux/dvb/dmx.h> - static char FRONTEND_DEV [80]; static char DEMUX_DEV [80]; +static char DVR_DEV [80]; +static int timeout_flag=0; +static int silent=0,timeout=0; +static int exit_after_tuning; -#define CHANNEL_FILE "/.tzap/channels.conf" +#define CHANNEL_FILE "channels.conf" #define ERROR(x...) \ do { \ @@ -68,14 +93,16 @@ static const Param guard_list [] = { {"GUARD_INTERVAL_1_16", GUARD_INTERVAL_1_16}, {"GUARD_INTERVAL_1_32", GUARD_INTERVAL_1_32}, {"GUARD_INTERVAL_1_4", GUARD_INTERVAL_1_4}, - {"GUARD_INTERVAL_1_8", GUARD_INTERVAL_1_8} + {"GUARD_INTERVAL_1_8", GUARD_INTERVAL_1_8}, + {"GUARD_INTERVAL_AUTO", GUARD_INTERVAL_AUTO} }; static const Param hierarchy_list [] = { { "HIERARCHY_1", HIERARCHY_1 }, { "HIERARCHY_2", HIERARCHY_2 }, { "HIERARCHY_4", HIERARCHY_4 }, - { "HIERARCHY_NONE", HIERARCHY_NONE } + { "HIERARCHY_NONE", HIERARCHY_NONE }, + { "HIERARCHY_AUTO", HIERARCHY_AUTO } }; static const Param constellation_list [] = { @@ -84,12 +111,14 @@ static const Param constellation_list [] = { { "QAM_16", QAM_16 }, { "QAM_256", QAM_256 }, { "QAM_32", QAM_32 }, - { "QAM_64", QAM_64 } + { "QAM_64", QAM_64 }, + { "QAM_AUTO", QAM_AUTO } }; static const Param transmissionmode_list [] = { { "TRANSMISSION_MODE_2K", TRANSMISSION_MODE_2K }, { "TRANSMISSION_MODE_8K", TRANSMISSION_MODE_8K }, + { "TRANSMISSION_MODE_AUTO", TRANSMISSION_MODE_AUTO } }; #define LIST_SIZE(x) sizeof(x)/sizeof(Param) @@ -100,7 +129,7 @@ int parse_param (int fd, const Param * plist, int list_size, int *param) { char c; int character = 0; - int index = 0; + int _index = 0; while (1) { if (read(fd, &c, 1) < 1) @@ -111,9 +140,9 @@ int parse_param (int fd, const Param * plist, int list_size, int *param) break; while (toupper(c) != plist->name[character]) { - index++; + _index++; plist++; - if (index >= list_size) /* parse error, no valid */ + if (_index >= list_size) /* parse error, no valid */ return -2; /* parameter name found */ } @@ -150,7 +179,10 @@ int parse_int(int fd, int *val) return -3; /* to fit in 32 bit */ }; + errno = 0; *val = strtol(number, NULL, 10); + if (errno == ERANGE) + return -4; return 0; } @@ -167,13 +199,18 @@ int find_channel(int fd, const char *channel) if (read(fd, &c, 1) < 1) return -1; /* EOF! */ - if (c == ':' && channel[character] == '\0') - break; - - if (toupper(c) == toupper(channel[character])) - character++; - else + if ( '\n' == c ) /* start of line */ character = 0; + else if ( character >= 0 ) { /* we are in the namefield */ + + if (c == ':' && channel[character] == '\0') + break; + + if (toupper(c) == toupper(channel[character])) + character++; + else + character = -1; + } }; return 0; @@ -211,12 +248,32 @@ int try_parse_param(int fd, const Param * plist, int list_size, int *param, return err; } +static int check_fec(fe_code_rate_t *fec) +{ + switch (*fec) + { + case FEC_NONE: + *fec = FEC_AUTO; + case FEC_AUTO: + case FEC_1_2: + case FEC_2_3: + case FEC_3_4: + case FEC_5_6: + case FEC_7_8: + return 0; + default: + ; + } + return 1; +} + int parse(const char *fname, const char *channel, struct dvb_frontend_parameters *frontend, int *vpid, int *apid) { int fd; int err; + int tmp; if ((fd = open(fname, O_RDONLY | O_NONBLOCK)) < 0) { PERROR ("could not open file '%s'", fname); @@ -229,54 +286,57 @@ int parse(const char *fname, const char *channel, return -2; } - if ((err = try_parse_int(fd, &frontend->frequency, "frequency"))) + if ((err = try_parse_int(fd, &tmp, "frequency"))) return -3; + frontend->frequency = tmp; if ((err = try_parse_param(fd, inversion_list, LIST_SIZE(inversion_list), - (int *) &frontend->inversion, - "inversion"))) + &tmp, "inversion"))) return -4; + frontend->inversion = tmp; if ((err = try_parse_param(fd, bw_list, LIST_SIZE(bw_list), - (int *) &frontend->u.ofdm.bandwidth, - "bandwidth"))) + &tmp, "bandwidth"))) return -5; + frontend->u.ofdm.bandwidth = tmp; if ((err = try_parse_param(fd, fec_list, LIST_SIZE(fec_list), - (int *) &frontend->u.ofdm.code_rate_HP, - "code_rate_HP"))) + &tmp, "code_rate_HP"))) + return -6; + frontend->u.ofdm.code_rate_HP = tmp; + if (check_fec(&frontend->u.ofdm.code_rate_HP)) return -6; if ((err = try_parse_param(fd, fec_list, LIST_SIZE(fec_list), - (int *) &frontend->u.ofdm.code_rate_LP, - "code_rate_LP"))) + &tmp, "code_rate_LP"))) + return -7; + frontend->u.ofdm.code_rate_LP = tmp; + if (check_fec(&frontend->u.ofdm.code_rate_LP)) return -7; if ((err = try_parse_param(fd, constellation_list, LIST_SIZE(constellation_list), - (int *) &frontend->u.ofdm.constellation, - "constellation"))) + &tmp, "constellation"))) return -8; + frontend->u.ofdm.constellation = tmp; if ((err = try_parse_param(fd, transmissionmode_list, LIST_SIZE(transmissionmode_list), - (int *) &frontend->u.ofdm. - transmission_mode, - "transmission_mode"))) + &tmp, "transmission_mode"))) return -9; + frontend->u.ofdm.transmission_mode = tmp; if ((err = try_parse_param(fd, guard_list, LIST_SIZE(guard_list), - (int *) &frontend->u.ofdm. - guard_interval, "guard_interval"))) + &tmp, "guard_interval"))) return -10; + frontend->u.ofdm.guard_interval = tmp; if ((err = try_parse_param(fd, hierarchy_list, LIST_SIZE(hierarchy_list), - (int *) &frontend->u.ofdm. - hierarchy_information, - "hierarchy_information"))) + &tmp, "hierarchy_information"))) return -11; + frontend->u.ofdm.hierarchy_information = tmp; if ((err = try_parse_int(fd, vpid, "Video PID"))) return -12; @@ -330,7 +390,8 @@ int setup_frontend (int fe_fd, struct dvb_frontend_parameters *frontend) return -1; } - printf ("tuning to %i Hz\n", frontend->frequency); + if (silent<2) + fprintf (stderr,"tuning to %i Hz\n", frontend->frequency); if (ioctl(fe_fd, FE_SET_FRONTEND, frontend) < 0) { PERROR("ioctl FE_SET_FRONTEND failed"); @@ -340,38 +401,115 @@ int setup_frontend (int fe_fd, struct dvb_frontend_parameters *frontend) return 0; } +static void +do_timeout(int x) +{ + (void)x; + if (timeout_flag==0) + { + timeout_flag=1; + alarm(2); + signal(SIGALRM, do_timeout); + } + else + { + /* something has gone wrong ... exit */ + exit(1); + } +} -static -int check_frontend (int fe_fd) +static void +print_frontend_stats (int fe_fd, int human_readable) { fe_status_t status; - uint16_t snr, signal; + uint16_t snr, _signal; uint32_t ber, uncorrected_blocks; - do { - ioctl(fe_fd, FE_READ_STATUS, &status); - ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal); - ioctl(fe_fd, FE_READ_SNR, &snr); - ioctl(fe_fd, FE_READ_BER, &ber); - ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks); + ioctl(fe_fd, FE_READ_STATUS, &status); + ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &_signal); + ioctl(fe_fd, FE_READ_SNR, &snr); + ioctl(fe_fd, FE_READ_BER, &ber); + ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks); + + if (human_readable) { + printf ("status %02x | signal %3u%% | snr %3u%% | ber %d | unc %d | ", + status, (_signal * 100) / 0xffff, (snr * 100) / 0xffff, ber, uncorrected_blocks); + } else { + fprintf (stderr, "status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ", + status, _signal, snr, ber, uncorrected_blocks); + } - printf ("status %02x | signal %04x | snr %04x | " - "ber %08x | unc %08x | ", - status, signal, snr, ber, uncorrected_blocks); + if (status & FE_HAS_LOCK) + fprintf(stderr,"FE_HAS_LOCK"); - if (status & FE_HAS_LOCK) - printf("FE_HAS_LOCK"); + fprintf(stderr,"\n"); +} +static +int check_frontend (int fe_fd, int human_readable) +{ + fe_status_t status; + do { + ioctl(fe_fd, FE_READ_STATUS, &status); + if (!silent) + print_frontend_stats(fe_fd, human_readable); + if (exit_after_tuning && (status & FE_HAS_LOCK)) + break; usleep(1000000); - - printf("\n"); - } while (1); + } while (!timeout_flag); + if (silent < 2) + print_frontend_stats (fe_fd, human_readable); return 0; } +#define BUFLEN (188*256) +static +void copy_to_file(int in_fd, int out_fd) +{ + char buf[BUFLEN]; + int r; + long long int rc = 0LL; + while(timeout_flag==0) + { + r=read(in_fd,buf,BUFLEN); + if (r < 0) { + if (errno == EOVERFLOW) { + printf("buffer overrun\n"); + continue; + } + PERROR("Read failed"); + break; + } + if (write(out_fd,buf,r) < 0) { + PERROR("Write failed"); + break; + } + rc+=r; + } + if (silent<2) + { + fprintf(stderr, "copied %lld bytes (%lld Kbytes/sec)\n",rc,rc/(1024*timeout)); + } +} -static const char *usage = "\nusage: %s [-a adapter_num] [-f frontend_id] [-d demux_id] [-c conf_file] [-r] <channel name>\n\n"; +static char *usage = + "usage:\n" + " tzap [options] <channel_name>\n" + " zap to channel channel_name (case insensitive)\n" + " -a number : use given adapter (default 0)\n" + " -f number : use given frontend (default 0)\n" + " -d number : use given demux (default 0)\n" + " -c file : read channels list from 'file'\n" + " -x : exit after tuning\n" + " -r : set up /dev/dvb/adapterX/dvr0 for TS recording\n" + " -s : only print summary\n" + " -S : run silently (no output)\n" + " -H : human readable output\n" + " -F : set up frontend only, don't touch demux\n" + " -t number : timeout (seconds)\n" + " -o file : output filename (use -o - for stdout)\n" + " -h -? : display this help and exit\n"; int main(int argc, char **argv) @@ -382,10 +520,14 @@ int main(int argc, char **argv) char *channel = NULL; int adapter = 0, frontend = 0, demux = 0, dvr = 0; int vpid, apid; - int frontend_fd, audio_fd, video_fd; + int frontend_fd, audio_fd = 0, video_fd = 0, dvr_fd, file_fd; int opt; + int record = 0; + int frontend_only = 0; + char *filename = NULL; + int human_readable = 0; - while ((opt = getopt(argc, argv, "hrn:a:f:d:c:")) != -1) { + while ((opt = getopt(argc, argv, "H?hrxRsFSn:a:f:d:c:t:o:")) != -1) { switch (opt) { case 'a': adapter = strtoul(optarg, NULL, 0); @@ -396,12 +538,34 @@ int main(int argc, char **argv) case 'd': demux = strtoul(optarg, NULL, 0); break; + case 't': + timeout = strtoul(optarg, NULL, 0); + break; + case 'o': + filename = strdup(optarg); + record=1; + /* fall through */ case 'r': dvr = 1; break; + case 'x': + exit_after_tuning = 1; + break; case 'c': confname = optarg; break; + case 's': + silent = 1; + break; + case 'S': + silent = 2; + break; + case 'F': + frontend_only = 1; + break; + case 'H': + human_readable = 1; + break; case '?': case 'h': default: @@ -424,17 +588,25 @@ int main(int argc, char **argv) snprintf (DEMUX_DEV, sizeof(DEMUX_DEV), "/dev/dvb/adapter%i/demux%i", adapter, demux); - printf ("using '%s' and '%s'\n", FRONTEND_DEV, DEMUX_DEV); + snprintf (DVR_DEV, sizeof(DVR_DEV), + "/dev/dvb/adapter%i/dvr%i", adapter, demux); + + if (silent<2) + fprintf (stderr,"using '%s' and '%s'\n", FRONTEND_DEV, DEMUX_DEV); if (!confname) { + int len = strlen(homedir) + strlen(CHANNEL_FILE) + 18; if (!homedir) ERROR ("$HOME not set"); - confname = malloc (strlen(homedir) + strlen(CHANNEL_FILE) + 1); - memcpy (confname, homedir, strlen(homedir)); - memcpy (confname + strlen(homedir), CHANNEL_FILE, - strlen(CHANNEL_FILE) + 1); + confname = malloc (len); + snprintf (confname, len, "%s/.tzap/%i/%s", + homedir, adapter, CHANNEL_FILE); + if (access (confname, R_OK)) + snprintf (confname, len, "%s/.tzap/%s", + homedir, CHANNEL_FILE); } + printf("reading channels from file '%s'\n", confname); memset(&frontend_param, 0, sizeof(struct dvb_frontend_parameters)); @@ -449,12 +621,17 @@ int main(int argc, char **argv) if (setup_frontend (frontend_fd, &frontend_param) < 0) return -1; + if (frontend_only) + goto just_the_frontend_dude; + if ((video_fd = open(DEMUX_DEV, O_RDWR)) < 0) { PERROR("failed opening '%s'", DEMUX_DEV); return -1; } - printf ("video pid 0x%04x, audio pid 0x%04x\n", vpid, apid); + if (silent<2) + fprintf (stderr,"video pid 0x%04x, audio pid 0x%04x\n", vpid, apid); + if (set_pesfilter (video_fd, vpid, DMX_PES_VIDEO, dvr) < 0) return -1; @@ -466,7 +643,51 @@ int main(int argc, char **argv) if (set_pesfilter (audio_fd, apid, DMX_PES_AUDIO, dvr) < 0) return -1; - check_frontend (frontend_fd); + signal(SIGALRM,do_timeout); + if (timeout>0) + alarm(timeout); + + + if (record) + { + if (filename!=NULL) + { + if (strcmp(filename,"-")!=0) + { + file_fd = open (filename,O_WRONLY|O_LARGEFILE|O_CREAT,0644); + if (file_fd<0) + { + PERROR("open of '%s' failed",filename); + return -1; + } + } + else + { + file_fd=1; + } + } + else + { + PERROR("Record mode but no filename!"); + return -1; + } + + if ((dvr_fd = open(DVR_DEV, O_RDONLY)) < 0) { + PERROR("failed opening '%s'", DVR_DEV); + return -1; + } + if (silent<2) + print_frontend_stats (frontend_fd, human_readable); + + copy_to_file(dvr_fd,file_fd); + + if (silent<2) + print_frontend_stats (frontend_fd, human_readable); + } + else { +just_the_frontend_dude: + check_frontend (frontend_fd, human_readable); + } close (audio_fd); close (video_fd); @@ -474,4 +695,3 @@ int main(int argc, char **argv) return 0; } - |