/* * dtvsignal.c * Copyright (C) 2002-2005, 2006 pcHDTV * * Compile with 'gcc -Wall -O dtvsignal.c -o dtvsignal' * * Use: * dtvsignal /dev/dtv 42 * dtvsignal takes a dtv device and dtv station channel and prints out the * signal strength for that channel to stdout * * dtvsignal 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. * * dtvsignal 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#define DEBUG_RCV 1 //#define DEEP_DEBUG 1 //#define DEBUG_ERR_MSG 1 static int in_file; //static int frontend_fd; static int dvbtype=0; static int modulation_vsb=1; static int n_channels; /* Added by MFT to allow a list of channels; */ /* used to modify printing behaviour when muliple channels are used */ /* FIXES for standard videodev includes */ #ifndef VIDIOCGSIGNAL struct video_signal { unsigned int strength;/* strength signal snr after eq & sig lock */ unsigned int aux; /* strength snr before eq */ }; #define VIDIOCGSIGNAL _IOR('v',30,struct video_signal) #endif #ifndef VIDEO_MODE_ATSC #define VIDEO_MODE_ATSC 3 #endif /* US broadcast */ /* First two entries are to make the entries line up with the channel number as index */ static unsigned long ntsc_dvb[ ] = { 0, 0, 57, 63, 69, 79, 85, 177, 183, 189 , 195, 201, 207, 213, 473, 479, 485, 491, 497, 503 , 509, 515, 521, 527, 533, 539, 545, 551, 557, 563 , 569, 575, 581, 587, 593, 599, 605, 611, 617, 623 , 629, 635, 641, 647, 653, 659, 665, 671, 677, 683 , 689, 695, 701, 707, 713, 719, 725, 731, 737, 743 , 749, 755, 761, 767, 773, 779, 785, 791, 797, 803 , 809, 815, 821, 827, 833, 839, 845, 851, 857, 863 , 869, 875, 881, 887, 893, 899, 905, 911, 917, 923 , 929, 935, 941, 947, 953, 959, 965, 971, 977, 983 , 989, 995, 1001, 1007, 1013, 1019, 1025, 1031, 1037, 1043 }; #define MAX_ATSC_CHAN 109 static unsigned long catv_dvb[] = { 0, 0, 57, 63, 69, 79, 85, 177, 183, 189, 195, 201, 207, 213, 123, 129, 135, 141, 147, 153, 159, 165, 171, 219, 225, 231, 237, 243, 249, 255, 261, 267, 273, 279, 285, 291, 297, 303, 309, 315, 321, 327, 333, 339, 345, 351, 357, 363, 369, 375, 381, 387, 393, 399, 405, 411, 417, 423, 429, 435, 441, 447, 453, 459, 465, 471, 477, 483, 489, 495, 501, 507, 513, 519, 525, 531, 537, 543, 549, 555, 561, 567, 573, 579, 585, 591, 597, 603, 609, 615, 621, 627, 633, 639, 645, 93, 99, 105, 111, 117, 651, 657, 663, 669, 675, 681, 687, 693, 699, 705, 711, 717, 723, 729, 735, 741, 747, 753, 759, 765, 771, 777, 783, 789, 795, 781, 807, 813, 819, 825, 831, 837, 843, 849, 855, 861, 867, 873, 879, 885, 891, 897, 903, 909, 915, 921, 927, 933, 939, 945, 951, 957, 963, 969, 975, 981, 987, 993, 999 }; #define MAX_CATV_CHAN 158 char sig[51][51] = { ".", "-", "--", "---", "----", "-----", "------", "-------", "--------", "---------", "----------", "-----------", "------------", "-------------", "--------------", "---------------", "----------------", "-----------------", "------------------", "-------------------", "--------------------", "---------------------", "----------------------", "-----------------------", "------------------------", "-------------------------", "=========================", "==========================", "===========================", "============================", "=============================", "##############################", "###############################", "################################", "#################################", "##################################", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" }; /************** DVB routines *****************/ #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 char FRONTEND_DEV [80]; static char DEMUX_DEV [80]; static int set_pesfilter (int fd, int pid, dmx_pes_type_t type, int dvr) { struct dmx_pes_filter_params pesfilter; if (pid <= 0 || pid >= 0x1fff) return 0; pesfilter.pid = pid; pesfilter.input = DMX_IN_FRONTEND; pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; pesfilter.pes_type = type; pesfilter.flags = DMX_IMMEDIATE_START; if (ioctl(fd, DMX_SET_PES_FILTER, &pesfilter) < 0) { PERROR ("ioctl(DMX_SET_PES_FILTER) for %s PID failed", type == DMX_PES_AUDIO ? "Audio" : type == DMX_PES_VIDEO ? "Video" : "??"); return -1; } return 0; } static int setup_frontend (int fe_fd, struct dvb_frontend_parameters *frontend) { struct dvb_frontend_info fe_info; if (ioctl(fe_fd, FE_GET_INFO, &fe_info) < 0) { PERROR("ioctl FE_GET_INFO failed"); return -1; } if (fe_info.type != FE_ATSC) { ERROR ("frontend device is not an ATSC (VSB/QAM) device"); return -1; } if (n_channels==1) {printf ("tuning to %i Hz\n", frontend->frequency);} if (ioctl(fe_fd, FE_SET_FRONTEND, frontend) < 0) { PERROR("ioctl FE_SET_FRONTEND failed"); return -1; } return 0; } #if 0 static int check_frontend (int fe_fd) { fe_status_t status; uint16_t snr, signal; uint32_t ber, uncorrected_blocks; int i; // do { for(i=0;i<3;i++) { 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); printf ("status %02x | signal %04x | snr %04x | " "ber %08x | unc %08x | ", status, signal, snr, ber, uncorrected_blocks); if (status & FE_HAS_LOCK) printf("FE_HAS_LOCK"); usleep(1000000); printf("\n"); } //while (1); return 0; } #endif static int dvbsetup(int adapter, int frontend, int demux, int dvr, int chan) { struct dvb_frontend_parameters frontend_param; // char *homedir = getenv ("HOME"); // char *confname = NULL; // char *channel = NULL; int vpid=0x21, apid=0x24; int frontend_fd, audio_fd, video_fd; snprintf (FRONTEND_DEV, sizeof(FRONTEND_DEV), "/dev/dvb/adapter%i/frontend%i", adapter, frontend); snprintf (DEMUX_DEV, sizeof(DEMUX_DEV), "/dev/dvb/adapter%i/demux%i", adapter, demux); if (n_channels==1) {printf ("using '%s' and '%s'\n", FRONTEND_DEV, DEMUX_DEV);} memset(&frontend_param, 0, sizeof(struct dvb_frontend_parameters)); if ((frontend_fd = open(FRONTEND_DEV, O_RDWR)) < 0) { PERROR ("failed opening '%s'", FRONTEND_DEV); return -1; } if(modulation_vsb) { frontend_param.frequency = ntsc_dvb[chan]*1000000; frontend_param.u.vsb.modulation = VSB_8; } else { if (n_channels==1) printf("setting frontend to QAM cable\n"); frontend_param.frequency = catv_dvb[chan]*1000000; frontend_param.u.vsb.modulation = QAM_256; // frontend_param.inversion = INVERSION_OFF; } if (setup_frontend (frontend_fd, &frontend_param) < 0) return -1; if ((video_fd = open(DEMUX_DEV, O_RDWR)) < 0) { PERROR("failed opening '%s'", DEMUX_DEV); return -1; } if(n_channels==1) {printf ("video pid 0x%04x, audio pid 0x%04x\n", vpid, apid);} if (set_pesfilter (video_fd, vpid, DMX_PES_VIDEO, dvr) < 0) return -1; if ((audio_fd = open(DEMUX_DEV, O_RDWR)) < 0) { PERROR("failed opening '%s'", DEMUX_DEV); return -1; } if (set_pesfilter (audio_fd, apid, DMX_PES_AUDIO, dvr) < 0) return -1; // check_frontend (frontend_fd); close (audio_fd); close (video_fd); // close (frontend_fd); return(frontend_fd); } static void scan_loop (int device,int chan,int dvbtype) { struct v4l2_tuner t; struct v4l2_frequency f; int signal = -1; int sig_ave = 0; int ioctlval; unsigned long freq; int i_loop=0; fe_status_t status; uint16_t snr, snl; uint32_t ber, uncorrected_blocks; if(dvbtype) { if(modulation_vsb) { freq = ntsc_dvb[chan]*1000000; } else { freq = catv_dvb[chan]*1000000; if (n_channels==1) {fprintf (stderr, "channel = %d freq = %ldHz table %ld\n", chan, freq, catv_dvb[chan]);} } } else { if(modulation_vsb) { freq = ((ntsc_dvb[chan]*100 - 175)*16)/100; } else { printf("QAM not supported in V4L driver.\n"); return; //freq = ((catv_dvb[chan]*100 - 175)*16)/100; } if (n_channels==1) {fprintf (stderr, "channel = %d freq*16 = %ld\n",chan,freq);} ioctlval = ioctl(device,VIDIOC_G_FREQUENCY,&f); f.frequency = freq; ioctlval = ioctl(device,VIDIOC_S_FREQUENCY,&f); } if (n_channels==1) {fprintf (stderr, "channel = %d freq = %ldHz\n",chan,freq); fprintf (stderr, " 30db 0%c 25%c 50%c 75%c 100%c\n",'%','%','%','%','%'); fprintf (stderr, "Signal: | . : . | ._____:_____._____|\n"); } while((n_channels==1)|(i_loop++<10)) { /* should make 10 an input parameter! MFT*/ if(dvbtype) { ioctl(device, FE_READ_STATUS, &status); ioctl(device, FE_READ_SIGNAL_STRENGTH, &snl); ioctl(device, FE_READ_SNR, &snr); ioctl(device, FE_READ_BER, &ber); ioctl(device, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks); #if 0 printf ("status %02x | signal %04x | snr %04x | " "ber %08x | unc %08x | ", status, snl, snr, ber, uncorrected_blocks); if (status & FE_HAS_LOCK) printf("FE_HAS_LOCK"); printf("\n"); continue; #endif if(status & FE_HAS_LOCK) signal = snl/655; // signal range is 0-65535 for 0-100% else signal = 0; } else { ioctlval = ioctl(device,VIDIOC_G_TUNER,&t); signal = t.signal/655; } if(signal < 0) { if (n_channels==1) {fprintf (stderr, "Signal < 0\n");} signal = 0; } if(signal > 100) { if (n_channels==1) {fprintf (stderr, "Signal %d > 100\n",signal);} signal = 100; } sig_ave = (sig_ave + signal)>>1; if (n_channels==1) {fprintf (stderr, "Signal: %03d %s\033[K\r",signal,sig[signal/2]);} else {fprintf (stderr, "%3d: %03d %s\033[K\r",chan,sig_ave,sig[sig_ave/2]);} } usleep(100000); } const char usage[] = "\ usage: dtvsignal [-q] [-dvb ] [device] channel [channel2] [channel3]...\n\ -q : enable QAM decoding\n\ -dvb : use DVB devices under adapter\n\ device : V4L2 device name (-dvb option will override)\n\ channel : channel to tune for signal strength\n\ Note if multiple channels are specified, they will be tuned sequentially in a loop\n"; char default_device_file[] = "/dev/dtv"; int main (int argc, char ** argv) { int ioctlval; unsigned long freq = 884; struct v4l2_frequency f; int chan = 2; int i; char* in_file_ptr; int dvb_adapter = 0; int try_dvb_dev = 1; // Added by M. F. Toups to sequentially loop through a sequence of channels int channel_list [100]; /* Mulitiple channel list is limited to 100 channels */ int i_channel; n_channels=0; i_channel=0; modulation_vsb = 1; dvbtype = 0; in_file_ptr = default_device_file; // fprintf (stderr, "main: argc %d argv[1] %s\n",argc,argv[1]); if (argc < 2) { fprintf(stderr, usage); return (1); } for (i=1; i < argc; i++) { // Flagged options defined in switch statement if (argv[i][0] == '-'){ switch(argv[i][1]) { case 'q': modulation_vsb=0; dvbtype = 1; break; case 'd': dvbtype=1; i++; if (isdigit(argv[i][0])){ dvb_adapter = atoi(argv[i]); } else { fprintf(stderr, "Bad argument to -dvb option.\n"); exit(-1); } break; default: fprintf(stderr, usage); exit(1); } continue; } else { // positional options deciphered here if (isdigit(argv[i][0])) { chan = atoi(argv[i]); if (chan < 2) chan = 2; // Added by M. F. Toups to sequentially loop through a sequence of channels if(n_channels<100){channel_list[n_channels++]=chan;} /*Test ignores more channels than will fit in channel_list array */ } else { in_file_ptr = argv[i]; try_dvb_dev = 0; } } // end if flagged options } // end for i // Added by M. F. Toups to sequentially loop through a sequence of channels fprintf (stderr, "dtvsignal ver 1.0.4 - by Jack Kelliher (c) 2002,2005,2006\n"); fprintf (stderr, "modified by M. F. Toups (c) 2006\n\n"); while (1) { if (n_channels>1) { fprintf (stderr, "Channel 0%c 25%c 50%c 75%c 100%c\n",'%','%','%','%','%'); fprintf (stderr, " Signal| . : . | ._____:_____._____|\n"); } for (i_channel=0; i_channel1) {fprintf(stderr,"%3d:",channel_list[i_channel]);} chan=channel_list[i_channel]; if (dvbtype) { if (((modulation_vsb)&&(chan > MAX_ATSC_CHAN))||(chan > MAX_CATV_CHAN)){ fprintf(stderr, "Channel out of range.\n"); exit(-1); } in_file = dvbsetup(dvb_adapter,0,0,0,chan); if (0 > in_file) { exit(1); } } else { if (chan > MAX_ATSC_CHAN) { fprintf(stderr, "Channel out of range.\n"); exit(-1); } in_file = open(in_file_ptr, O_RDWR); if (in_file < 0) { if (try_dvb_dev) { if((in_file = dvbsetup(0,0,0,0,chan)) != 0) { dvbtype = 1; } else { fprintf(stderr, "failed opening any device\n"); exit(1); } } else { fprintf(stderr, "failed opening %s\n", in_file_ptr); exit(1); } } } if((chan == 0) && (dvbtype == 0)) { ioctlval = ioctl(in_file,VIDIOC_G_FREQUENCY,&f); // fprintf (stderr, "main: ioctl 1 rtn %0x\n",ioctlval); f.frequency = freq; ioctlval = ioctl(in_file,VIDIOC_S_FREQUENCY,&f); // fprintf (stderr, "main: ioctl 2 rtn %0x\n",ioctlval); return(0); } if(in_file ) { if(dvbtype == 0) { ioctlval = ioctl(in_file,VIDIOC_G_FREQUENCY,&f); // fprintf (stderr, "main: ioctl 1 rtn %0x\n",ioctlval); f.frequency = freq; ioctlval = ioctl(in_file,VIDIOC_S_FREQUENCY,&freq); // fprintf (stderr, "main: ioctl 2 rtn %0x\n",ioctlval); } } else { fprintf (stderr, "error need device name\n"); return(0); } scan_loop(in_file,chan,dvbtype); close(in_file); fprintf (stderr, "\n"); } fprintf(stderr,"\033[%dA",(n_channels+2)); } fprintf (stderr, "dtvsignal ver 1.0.4 - by Jack Kelliher (c) 2002,2005,2006\n"); fprintf (stderr, "modifications - by M. F. Toups (c) 2006\n"); return 0; }