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.
|