Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * radio.c - (c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>
  3  *
  4  * test tool for bttv + WinTV/Radio
  5  *
  6  */
  7 
  8 /* Changes:
  9  * 20 Jun 99 - Juli Merino (JMMV) <jmmv@mail.com> - Added some features:
 10  *             visual menu, manual 'go to' function, negative symbol and a
 11  *             good interface. See code for more details.
 12  * 30 Aug 2001 - Gunther Mayer <Gunther.Mayer@t-online.de>
 13  *             Scan for Stations, ad-hoc algorithm for signal strength
 14  *             analysis.  My Temic 4009FR5 finds all 19 stations here,
 15  *             a Samsung TPI8PSB02P misses two stations below 90MHz,
 16  *             which are received fine, but the tuner doesn't indicate
 17  *             signal strength.
 18  */
 19 
 20 #include <stdio.h>
 21 #include <stdlib.h>
 22 #include <unistd.h>
 23 #include <string.h>
 24 #include <errno.h>
 25 #include <fcntl.h>
 26 #include <curses.h>
 27 #include <sys/time.h>
 28 #include <sys/ioctl.h>
 29 
 30 #include "videodev.h"
 31 
 32 #define FREQ_MIN    87500000
 33 #define FREQ_MAX   108000000
 34 #define FREQ_STEP      50000
 35 
 36 #define MIN(a,b) ((a)<(b)?(a):(b))
 37 #define MAX(a,b) ((a)>(b)?(a):(b))
 38 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
 39 
 40 /* JMMV: WINDOWS for radio */
 41 int ncurses = 0;
 42 int debug = 0;
 43 char *device = "/dev/radio";
 44 WINDOW *wfreq, *woptions, *wstations, *wcommand;
 45 int freqfact = 16;
 46 
 47 static int
 48 radio_setfreq(int fd, float freq)
 49 {
 50     int ifreq = (freq + .5/freqfact) * freqfact;
 51     return ioctl(fd, VIDIOCSFREQ, &ifreq);
 52 }
 53 
 54 static int radio_getfreq(int fd, float *freq)
 55 {
 56     int ioctl_status;
 57     int ifreq;
 58     ioctl_status = ioctl(fd,VIDIOCGFREQ, &ifreq);
 59     if (ioctl_status == -1)
 60         return ioctl_status;
 61     *freq = (float) ifreq / freqfact;
 62     return 0;
 63 }
 64 
 65 static void
 66 radio_unmute(int fd)
 67 {
 68     struct video_audio vid_aud;
 69 
 70     if (ioctl(fd, VIDIOCGAUDIO, &vid_aud))
 71         perror("VIDIOCGAUDIO");
 72     if (vid_aud.volume == 0)
 73         vid_aud.volume = 65535;
 74     vid_aud.flags &= ~VIDEO_AUDIO_MUTE;
 75     if (ioctl(fd, VIDIOCSAUDIO, &vid_aud))
 76         perror("VIDIOCSAUDIO");
 77 }
 78 
 79 static void
 80 radio_mute(int fd)
 81 {
 82     struct video_audio vid_aud;
 83 
 84     if (ioctl(fd, VIDIOCGAUDIO, &vid_aud))
 85         perror("VIDIOCGAUDIO");
 86     vid_aud.flags |= VIDEO_AUDIO_MUTE;
 87     if (ioctl(fd, VIDIOCSAUDIO, &vid_aud))
 88         perror("VIDIOCSAUDIO");
 89 }
 90 
 91 static void
 92 radio_getstereo(int fd)
 93 {
 94     struct video_audio va;
 95     va.mode=-1;
 96 
 97     if (!ncurses)
 98         return;
 99     
100     if (ioctl (fd, VIDIOCGAUDIO, &va) < 0)
101         mvwprintw(wfreq,2,1,"     ");
102     mvwprintw(wfreq,2,1,"%s", va.mode == VIDEO_SOUND_STEREO ?
103               "STEREO":" MONO ");
104 }
105 
106 static int
107 radio_getsignal(int fd)
108 {
109     struct video_tuner vt;
110     int i,signal;
111 
112     memset(&vt,0,sizeof(vt));
113     ioctl (fd, VIDIOCGTUNER, &vt);
114     signal=vt.signal>>13;
115 
116     if (!ncurses)
117         return signal;
118 
119     for(i=0;i<8;i++)
120         mvwprintw(wfreq,3,i+1,"%s", signal>i ? "*":" ");
121     return signal;
122 }
123 
124 static int
125 select_wait(int sec)
126 {
127     struct timeval  tv;
128     fd_set          se;
129     
130     FD_ZERO(&se);
131     FD_SET(0,&se);
132     tv.tv_sec = sec;
133     tv.tv_usec = 0;
134     return select(1,&se,NULL,NULL,&tv);
135 }
136 
137 /* ---------------------------------------------------------------------- */
138 
139 char *digit[3][10] = {
140    { " _ ", "   ", " _ ", " _ ", "   ", " _ ", " _ ", " _ ", " _ ", " _ " },
141    { "| |", " | ", " _|", " _|", "|_|", "|_ ", "|_ ", "  |", "|_|", "|_|" },
142    { "|_|", " | ", "|_ ", " _|", "  |", " _|", "|_|", "  |", "|_|", " _|" }
143 };
144 
145 static void print_freq(float freq)
146 {
147     int x,y,i;
148     char text[10]; 
149     sprintf(text,"%6.2f",freq);
150     for (i = 0, x = 8; i < 6; i++, x+=4) {
151         if (text[i] >= '' && text[i] <= '9') {
152             for (y = 0; y < 3; y++)
153                 mvwprintw(wfreq,y+1,x,"%s",digit[y][text[i]-'']);
154         } else if (text[i] == '.') {
155             mvwprintw(wfreq,3,x,".");
156             x -= 2;
157         } else {
158             for (y = 0; y < 3; y++)
159                 mvwprintw(wfreq,y+1,x,"   ");
160         }
161     }
162     wrefresh(wfreq);
163 }
164 
165 /* ---------------------------------------------------------------------- */
166 
167 int   fkeys[8];
168 
169 int   freqs[99];
170 char *labels[99];
171 int   stations;
172 
173 static void
174 read_kradioconfig(void)
175 {
176     char   name[80],file[256],n;
177     int    ifreq;
178     FILE   *fp;
179 
180     sprintf(file,"%.225s/.kde/share/config/kradiorc",getenv("HOME"));
181     if (NULL == (fp = fopen(file,"r"))) {
182         sprintf(file,"%.225s/.radio",getenv("HOME"));
183         if (NULL == (fp = fopen(file,"r")))
184             return;
185     }
186     while (NULL != fgets(file,255,fp)) {
187         if (2 == sscanf(file,"%c=%d",&n,&ifreq) && n >= '1' && n <= '8') {
188             fkeys[n - '1'] = ifreq;
189         } else if (2 == sscanf(file,"%d=%30[^\n]",&ifreq,name) && stations < 99) {
190             freqs[stations]  = ifreq;
191             labels[stations] = strdup(name);
192             stations++;
193         }
194     }
195 }
196 
197 static char*
198 find_label(int ifreq)
199 {
200     int i;
201 
202     for (i = 0; i < stations; i++) {
203         if (ifreq == freqs[i])
204             return labels[i];
205     }
206     return NULL;
207 }
208 
209 static char *
210 make_label(int ifreq)
211 {
212     static char text[20],*l;
213 
214     if (NULL != (l = find_label(ifreq)))
215         return l;
216     sprintf(text,"%6.2f MHz",(float)ifreq/1000000);
217     return text;
218 }
219 
220 /* ---------------------------------------------------------------------- */
221 /* autoscan                                                               */
222 
223 float g[411],baseline;
224 int astation[100],max_astation=0,current_astation=-1;
225 int write_config;
226 
227 static void
228 foundone(int m)
229 {
230     int i;
231     
232     for (i=0; i<100 && astation[i]; i++) {
233         if(abs(astation[i]-m) <5 )  // 20 kHz width 
234             break;
235     }
236     if (g[m] > g[astation[i]]) {  //  select bigger signal
237         astation[i]=m;
238         max_astation=i;
239         fprintf(stderr,"Station %2d: %6.2f MHz - %.2f\n",i,87.5+m*0.05,g[m]);
240         if (write_config)
241             printf("%d0000=scan-%d\n",(int)((87.5+m*0.05)*100),i);
242     }
243 }
244 
245 static void 
246 maxi(int m)
247 {
248     int i,l,r;
249     float halbwert;
250 
251     if (debug)
252         fprintf(stderr,"maxi i %d %f %f\n",m,87.5+m*0.05,g[m]);
253     if(g[m]<baseline)
254         return;
255     halbwert=(g[m]-baseline)/2+baseline;
256     
257     for(i=m;i>0;i--)
258         if(g[i]< halbwert)
259             break;
260     l=i;
261     if (debug)
262         fprintf(stderr,"Left   i %d %f %f\n",i,87.5+i*0.05,g[i]);
263     
264     for(i=m;i<411;i++)
265         if(g[i]< halbwert)
266             break;
267     if (debug)
268         fprintf(stderr,"Right  i %d %f %f\n",i,87.5+i*0.05,g[i]);
269     r=i;
270     m=(l+r)/2;
271     if (debug)
272         fprintf(stderr,"Middle %d %f %f\n",m,87.5+m*0.05,g[m]);
273     foundone(m);
274 }
275 
276 static void 
277 findmax(void)
278 {
279     int i;
280     
281     for (i = 0; i < ARRAY_SIZE(g)-1; i++){
282         if (g[i+1] < g[i])
283             maxi(i);
284     }
285 }
286 
287 // find the baseline for this tuners signal strength
288 static float
289 get_baseline(float ming, float maxg)
290 {
291     int unt,i,nullfound=0;
292     float nullinie=0,u;
293 
294     if (debug)
295         fprintf(stderr,"get_baseline:  min=%f max=%f\n",ming,maxg);
296     for(u=ming;u<maxg; u+=0.1) {
297         unt=0;
298         for (i=0; i< ARRAY_SIZE(g); i++)
299             if (g[i] < u) {
300                 unt++;
301             }
302         if(unt>300 && !nullfound) {
303             fprintf(stderr,"baseline at %.2f\n",u);
304             nullinie=u;
305             nullfound=1;
306         }
307         if (debug)
308             fprintf(stderr,"%f %d\n",u,unt);
309     }
310     return nullinie;
311 }
312 
313 static void 
314 findstations(void)
315 {
316     float maxg=0,ming=8;
317     int i;
318 
319     for (i=0; i< ARRAY_SIZE(g); i++) {
320         if (g[i]<ming) ming=g[i];
321         if (g[i]>maxg) maxg=g[i];
322     }
323 
324     if (write_config)
325         printf("[Stations]\n");
326     baseline=get_baseline(ming,maxg);
327     findmax();
328 }
329 
330 static void do_scan(int fd,int scan)
331 {
332     FILE * fmap=NULL;
333     float freq,s; 
334     int i,j;
335 
336     if(scan > 1)
337         fmap=fopen("radio.fmmap","w");
338     for (i=0; i< ARRAY_SIZE(g); i++) {
339         freq = (FREQ_MIN + i * FREQ_STEP)/1e6;
340         s = 0;
341         radio_setfreq(fd,freq);
342         usleep(10000); /* give the tuner some time to settle */
343         for(j=0;j<5;j++) {
344             s+=radio_getsignal(fd);
345             radio_getstereo(fd);
346             usleep(1000);
347         }
348         g[i]=s/5; // average
349         if (scan > 1)
350             fprintf(fmap,"%f %f\n", freq,s);
351         fprintf(stderr,"scanning: %6.2f MHz - %.2f\r", freq,s);
352     }
353     fprintf(stderr,"%40s\r","");
354     if (scan > 1)
355         fclose(fmap);
356     findstations();
357 }
358 
359 /* ---------------------------------------------------------------------- */
360 
361 static void
362 usage(FILE *out)
363 {
364     fprintf(out,
365             "radio -- interactive ncurses radio application\n"
366             "usage:\n"
367             "  radio [ options ]\n"
368             "\n"
369             "options:\n"
370             "  -h       print this text\n"
371             "  -d       enable debug output\n"
372             "  -m       mute radio\n"
373             "  -f freq  tune given frequency (also unmutes)\n"
374             "  -c dev   use given device        [default: %s]\n"
375             "  -s       scan\n"
376             "  -S       scan + write radio.fmmap\n"
377             "  -i       scan, write initial ~/.radio config file to\n"
378             "           stdout and quit\n"
379             "  -q       quit.  Useful with other options to control the\n"
380             "           radio device without entering interactive mode,\n"
381             "           i.e. \"radio -qf 91.4\"\n"
382             "\n"
383             "(c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>\n"
384             "interface by Juli Merino <jmmv@mail.com>\n"
385             "channel scan by Gunther Mayer <Gunther.Mayer@t-online.de>\n",
386             device);
387 }
388 
389 int
390 main(int argc, char *argv[])
391 {
392     /* JMMV: lastfreq set to 1 to start radio at 0.0 */
393     int    fd,key=0,done,i,ifreq = 0,lastfreq = 1, mute=1;
394     char   *name;
395     /* Variables set by JMMV */
396     float  ffreq, newfreq = 0;
397     int    stset = 0, c;
398     int    quit=0, scan=0, arg_mute=0;
399     struct video_tuner tuner;
400 
401     /* parse args */
402     for (;;) {
403         c = getopt(argc, argv, "mhiqdsSf:c:");
404         if (c == -1)
405             break;
406         switch (c) {
407         case 'm':
408             arg_mute = 1;
409             break;
410         case 'q':
411             quit = 1;
412             break;
413         case 'd':
414             debug= 1;
415             break;
416         case 'S':
417             scan = 2;
418             break;
419         case 's':
420             scan = 1;
421             break;
422         case 'i':
423             write_config = 1;
424             scan = 1;
425             quit = 1;
426             break;
427         case 'f':
428             if (1 == sscanf(optarg,"%f",&ffreq)) {
429                 ifreq = (int)(ffreq * 1000000);
430                 ifreq += FREQ_STEP/2;
431                 ifreq -= ifreq % FREQ_STEP;
432             }
433             break;
434         case 'c':
435             device = optarg;
436             break;
437         case 'h':
438             usage(stdout);
439             exit(0);
440         default:
441             usage(stderr);
442             exit(1);
443         }
444     }
445     
446     if (-1 == (fd = open(device, O_RDONLY))) {
447         fprintf(stderr,"open %s: %s\n",device,strerror(errno));
448         exit(1);
449     }
450 
451     memset(&tuner,0,sizeof(tuner));
452     if (0 == ioctl(fd, VIDIOCGTUNER, &tuner) &&
453         (tuner.flags & VIDEO_TUNER_LOW))
454         freqfact = 16000;
455 
456     /* non-interactive stuff */
457     if (scan) {
458         do_scan(fd,scan);
459         if (!ifreq  &&  max_astation) {
460             current_astation = 0;
461             ifreq = FREQ_MIN + astation[current_astation]*50000;
462         }
463     }
464     if (ifreq) {
465         ffreq = (float)ifreq / 1000000;
466         fprintf(stderr,"tuned %.2f MHz\n",ffreq);
467         radio_setfreq(fd,ffreq);
468         radio_unmute(fd);
469     }
470     if (arg_mute) {
471         fprintf(stderr,"muted radio\n");
472         radio_mute(fd);
473     }
474     if (quit)
475         exit(0);
476 
477     read_kradioconfig();
478     if (!ifreq && fkeys[0])
479         ifreq = fkeys[0];
480 
481     /* enter interactive mode -- init ncurses */
482     ncurses=1;
483     initscr();
484     start_color();
485     cbreak();
486     noecho();
487     keypad(stdscr,1);
488     curs_set(0);
489     
490     /* JMMV: Set colors and windows */
491     /* XXX: Color definitions are wrong! BLUE is RED, CYAN is YELLOW and
492      * viceversa */
493     init_pair(1,COLOR_WHITE,COLOR_BLACK);
494     init_pair(2,COLOR_CYAN,COLOR_BLUE);
495     init_pair(3,COLOR_WHITE,COLOR_RED);
496     bkgd(A_BOLD | COLOR_PAIR(1));
497     refresh();
498 
499     wfreq = newwin(7,32,1,2);
500     wbkgd(wfreq,A_BOLD | COLOR_PAIR(2));
501     werase(wfreq);
502     box(wfreq, 0, 0);
503     mvwprintw(wfreq, 0, 1, " Tuner ");
504     
505     woptions = newwin(7,COLS-38,1,36);
506     wbkgd(woptions,A_BOLD | COLOR_PAIR(3));
507     werase(woptions);
508     box(woptions, 0, 0);
509     mvwprintw(woptions, 0, 1, " Main menu ");
510 
511     wstations = newwin(LINES-14,COLS-4,9,2);
512     wbkgd(wstations,A_BOLD | COLOR_PAIR(3));
513     werase(wstations);
514     box(wstations, 0, 0);
515     mvwprintw(wstations, 0, 1, " Preset stations ");
516     
517     wcommand = newwin(3,COLS-4,LINES-4,2);
518     wbkgd(wcommand,A_BOLD | COLOR_PAIR(3));
519     werase(wcommand);
520     box(wcommand,0,0);
521     mvwprintw(wcommand, 0, 1, " Command window ");
522     wrefresh(wcommand);    
523     
524     /* JMMV: Added key information and windows division */
525     mvwprintw(woptions, 1, 1, "Up/Down     - inc/dec frequency");
526     mvwprintw(woptions, 2, 1, "PgUp/PgDown - next/prev station");
527     mvwprintw(woptions, 3, 1, "g           - go to frequency...");
528     mvwprintw(woptions, 4, 1, "x           - exit");
529     mvwprintw(woptions, 5, 1, "ESC, q, e   - mute and exit");
530     wrefresh(woptions);
531     for (i = 0, c = 1; i < 8; i++) {
532         if (fkeys[i]) {
533             mvwprintw(wstations,c,2,"F%d: %s",i+1,make_label(fkeys[i]));
534             c++;
535             stset = 1;
536         }
537     }
538     if (!stset)
539         mvwprintw(wstations,1,1,"[none]");
540     wrefresh(wstations);
541 
542     if (ifreq == 0) {
543         float ffreq;
544         radio_getfreq(fd,&ffreq);
545         ifreq = ffreq * 1000000;
546     }
547     
548     radio_unmute(fd);
549     for (done = 0; done == 0;) {
550         if (ifreq != lastfreq) {
551             lastfreq = ifreq;
552             ffreq = (float)ifreq / 1000000;
553             radio_setfreq(fd,ffreq);
554             print_freq(ffreq);
555             if (NULL != (name = find_label(ifreq)))
556                 mvwprintw(wfreq,5,2,"%-20.20s",name);
557             else
558                 mvwprintw(wfreq,5,2,"%-20.20s","");
559         }
560         radio_getstereo(fd);
561         radio_getsignal(fd);
562         wrefresh(wfreq);
563         wrefresh(wcommand);
564 
565         if (0 == select_wait(1)) {
566             mvwprintw(wcommand,1,1,"%50.50s","");
567             wrefresh(wcommand);
568             continue;
569         }
570         key = getch();
571         switch (key) {
572         case EOF:
573         case 'x':
574         case 'X':
575             mute = 0;
576             /* fall throuth */
577         case 27: /* ESC */
578         case 'q':
579         case 'Q':
580         case 'e':
581         case 'E':
582             done = 1;
583             break;
584         case 'g':
585         case 'G':
586             /* JMMV: Added 'go to frequency' function */
587             mvwprintw(wcommand,1,2,"GO: Enter frequency: ");
588             curs_set(1);
589             echo();
590             wrefresh(wcommand);
591             wscanw(wcommand,"%f",&newfreq);
592             noecho();
593             curs_set(0);
594             wrefresh(wcommand);
595             if ((newfreq >= FREQ_MIN/1e6) && (newfreq <= FREQ_MAX/1e6) )
596                 ifreq = newfreq * 1000000;
597             else
598                 mvwprintw(wcommand, 1, 2,
599                           "Frequency out of range (87.5-108 MHz)");
600             break;
601         case KEY_UP:
602             ifreq += FREQ_STEP;
603             if (ifreq > FREQ_MAX)
604                 ifreq = FREQ_MIN;
605             mvwprintw(wcommand, 1, 2, "Increment frequency");
606             break;
607         case KEY_DOWN:
608             ifreq -= FREQ_STEP;
609             if (ifreq < FREQ_MIN)
610                 ifreq = FREQ_MAX;
611             mvwprintw(wcommand, 1, 2, "Decrease frequency");
612             break;
613         case KEY_PPAGE:
614         case KEY_NPAGE:
615         case ' ':
616             if (max_astation) {
617                 current_astation += (key == KEY_NPAGE) ? -1 : 1;
618                 if(current_astation<0)
619                     current_astation=max_astation;
620                 if(current_astation>max_astation)
621                     current_astation=0;
622                 ifreq=FREQ_MIN+astation[current_astation]*FREQ_STEP;
623             } else {
624                 for (i = 0; i < stations; i++) {
625                     if (ifreq == freqs[i])
626                         break;
627                 }
628                 if (i != stations) {
629                     i += (key == KEY_NPAGE) ? -1 : 1;
630                     if (i < 0 || i >= stations)
631                         i = 0;
632                     ifreq = freqs[i];
633                 }
634             }
635             break;
636         case '1':
637         case '2':
638         case '3':
639         case '4':
640         case '5':
641         case '6':
642         case '7':
643         case '8':
644         case KEY_F(1):
645         case KEY_F(2):
646         case KEY_F(3):
647         case KEY_F(4):
648         case KEY_F(5):
649         case KEY_F(6):
650         case KEY_F(7):
651         case KEY_F(8):
652             i = (key >= '1' && key <= '8')  ?  key - '1' : key - KEY_F(1);
653             if (fkeys[i]) {
654                 ifreq = fkeys[i];
655                 mvwprintw(wcommand, 1, 2, "Go to preset station %d", i+1);
656             }
657             break;
658         case 'L' & 0x1f:  /* Ctrl-L */
659             redrawwin(stdscr);
660             redrawwin(wfreq);
661             redrawwin(woptions);
662             redrawwin(wstations);
663             redrawwin(wcommand);
664             wrefresh(stdscr);
665             wrefresh(wfreq);
666             wrefresh(woptions);
667             wrefresh(wstations);
668             wrefresh(wcommand);
669             break;
670         }
671     }
672     if (mute)
673         radio_mute(fd);
674     close(fd);
675 
676     bkgd(0);
677     clear();
678     refresh();
679     endwin();
680     return 0;
681 }
682 
  This page was automatically generated by the LXR engine.