Logo Search packages:      
Sourcecode: xawtv version File versions  Download package

radio.c

/*
 * radio.c - (c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>
 *
 * test tool for bttv + WinTV/Radio
 *
 */

/* Changes:
 * 20 Jun 99 - Juli Merino (JMMV) <jmmv@mail.com> - Added some features:
 *             visual menu, manual 'go to' function, negative symbol and a
 *             good interface. See code for more details.
 * 30 Aug 2001 - Gunther Mayer <Gunther.Mayer@t-online.de>
 *             Scan for Stations, ad-hoc algorithm for signal strength
 *             analysis.  My Temic 4009FR5 finds all 19 stations here,
 *             a Samsung TPI8PSB02P misses two stations below 90MHz,
 *             which are received fine, but the tuner doesn't indicate
 *             signal strength.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <curses.h>
#include <sys/time.h>
#include <sys/ioctl.h>

#include "videodev.h"

#define FREQ_MIN    87500000
#define FREQ_MAX   108000000
#define FREQ_STEP      50000

#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))

/* JMMV: WINDOWS for radio */
int ncurses = 0;
int debug = 0;
char *device = "/dev/radio";
WINDOW *wfreq, *woptions, *wstations, *wcommand;
int freqfact = 16;

static int
radio_setfreq(int fd, float freq)
{
    int ifreq = (freq + .5/freqfact) * freqfact;
    return ioctl(fd, VIDIOCSFREQ, &ifreq);
}

static int radio_getfreq(int fd, float *freq)
{
    int ioctl_status;
    int ifreq;
    ioctl_status = ioctl(fd,VIDIOCGFREQ, &ifreq);
    if (ioctl_status == -1)
        return ioctl_status;
    *freq = (float) ifreq / freqfact;
    return 0;
}

static void
radio_unmute(int fd)
{
    struct video_audio vid_aud;

    if (ioctl(fd, VIDIOCGAUDIO, &vid_aud))
      perror("VIDIOCGAUDIO");
    if (vid_aud.volume == 0)
      vid_aud.volume = 65535;
    vid_aud.flags &= ~VIDEO_AUDIO_MUTE;
    if (ioctl(fd, VIDIOCSAUDIO, &vid_aud))
      perror("VIDIOCSAUDIO");
}

static void
radio_mute(int fd)
{
    struct video_audio vid_aud;

    if (ioctl(fd, VIDIOCGAUDIO, &vid_aud))
      perror("VIDIOCGAUDIO");
    vid_aud.flags |= VIDEO_AUDIO_MUTE;
    if (ioctl(fd, VIDIOCSAUDIO, &vid_aud))
      perror("VIDIOCSAUDIO");
}

static void
radio_getstereo(int fd)
{
    struct video_audio va;
    va.mode=-1;

    if (!ncurses)
      return;
    
    if (ioctl (fd, VIDIOCGAUDIO, &va) < 0)
      mvwprintw(wfreq,2,1,"     ");
    mvwprintw(wfreq,2,1,"%s", va.mode == VIDEO_SOUND_STEREO ?
            "STEREO":" MONO ");
}

static int
radio_getsignal(int fd)
{
    struct video_tuner vt;
    int i,signal;

    memset(&vt,0,sizeof(vt));
    ioctl (fd, VIDIOCGTUNER, &vt);
    signal=vt.signal>>13;

    if (!ncurses)
      return signal;

    for(i=0;i<8;i++)
        mvwprintw(wfreq,3,i+1,"%s", signal>i ? "*":" ");
    return signal;
}

static int
select_wait(int sec)
{
    struct timeval  tv;
    fd_set          se;
    
    FD_ZERO(&se);
    FD_SET(0,&se);
    tv.tv_sec = sec;
    tv.tv_usec = 0;
    return select(1,&se,NULL,NULL,&tv);
}

/* ---------------------------------------------------------------------- */

char *digit[3][10] = {
   { " _ ", "   ", " _ ", " _ ", "   ", " _ ", " _ ", " _ ", " _ ", " _ " },
   { "| |", " | ", " _|", " _|", "|_|", "|_ ", "|_ ", "  |", "|_|", "|_|" },
   { "|_|", " | ", "|_ ", " _|", "  |", " _|", "|_|", "  |", "|_|", " _|" }
};

static void print_freq(float freq)
{
    int x,y,i;
    char text[10]; 
    sprintf(text,"%6.2f",freq);
    for (i = 0, x = 8; i < 6; i++, x+=4) {
      if (text[i] >= '0' && text[i] <= '9') {
          for (y = 0; y < 3; y++)
            mvwprintw(wfreq,y+1,x,"%s",digit[y][text[i]-'0']);
      } else if (text[i] == '.') {
          mvwprintw(wfreq,3,x,".");
          x -= 2;
      } else {
          for (y = 0; y < 3; y++)
            mvwprintw(wfreq,y+1,x,"   ");
      }
    }
    wrefresh(wfreq);
}

/* ---------------------------------------------------------------------- */

int   fkeys[8];

int   freqs[99];
char *labels[99];
int   stations;

static void
read_kradioconfig(void)
{
    char   name[80],file[256],n;
    int    ifreq;
    FILE   *fp;

    sprintf(file,"%.225s/.kde/share/config/kradiorc",getenv("HOME"));
    if (NULL == (fp = fopen(file,"r"))) {
      sprintf(file,"%.225s/.radio",getenv("HOME"));
      if (NULL == (fp = fopen(file,"r")))
          return;
    }
    while (NULL != fgets(file,255,fp)) {
      if (2 == sscanf(file,"%c=%d",&n,&ifreq) && n >= '1' && n <= '8') {
          fkeys[n - '1'] = ifreq;
      } else if (2 == sscanf(file,"%d=%30[^\n]",&ifreq,name) && stations < 99) {
          freqs[stations]  = ifreq;
          labels[stations] = strdup(name);
          stations++;
      }
    }
}

static char*
find_label(int ifreq)
{
    int i;

    for (i = 0; i < stations; i++) {
      if (ifreq == freqs[i])
          return labels[i];
    }
    return NULL;
}

static char *
make_label(int ifreq)
{
    static char text[20],*l;

    if (NULL != (l = find_label(ifreq)))
      return l;
    sprintf(text,"%6.2f MHz",(float)ifreq/1000000);
    return text;
}

/* ---------------------------------------------------------------------- */
/* autoscan                                                               */

float g[411],baseline;
int astation[100],max_astation=0,current_astation=-1;
int write_config;

static void
foundone(int m)
{
    int i;
    
    for (i=0; i<100 && astation[i]; i++) {
        if(abs(astation[i]-m) <5 )  // 20 kHz width 
          break;
    }
    if (g[m] > g[astation[i]]) {  //  select bigger signal
      astation[i]=m;
      max_astation=i;
      fprintf(stderr,"Station %2d: %6.2f MHz - %.2f\n",i,87.5+m*0.05,g[m]);
      if (write_config)
          printf("%d0000=scan-%d\n",(int)((87.5+m*0.05)*100),i);
    }
}

static void 
maxi(int m)
{
    int i,l,r;
    float halbwert;

    if (debug)
      fprintf(stderr,"maxi i %d %f %f\n",m,87.5+m*0.05,g[m]);
    if(g[m]<baseline)
        return;
    halbwert=(g[m]-baseline)/2+baseline;
    
    for(i=m;i>0;i--)
      if(g[i]< halbwert)
          break;
    l=i;
    if (debug)
      fprintf(stderr,"Left   i %d %f %f\n",i,87.5+i*0.05,g[i]);
    
    for(i=m;i<411;i++)
      if(g[i]< halbwert)
          break;
    if (debug)
      fprintf(stderr,"Right  i %d %f %f\n",i,87.5+i*0.05,g[i]);
    r=i;
    m=(l+r)/2;
    if (debug)
      fprintf(stderr,"Middle %d %f %f\n",m,87.5+m*0.05,g[m]);
    foundone(m);
}

static void 
findmax(void)
{
    int i;
    
    for (i = 0; i < ARRAY_SIZE(g)-1; i++){
        if (g[i+1] < g[i])
          maxi(i);
    }
}

// find the baseline for this tuners signal strength
static float
get_baseline(float ming, float maxg)
{
    int unt,i,nullfound=0;
    float nullinie=0,u;

    if (debug)
      fprintf(stderr,"get_baseline:  min=%f max=%f\n",ming,maxg);
    for(u=ming;u<maxg; u+=0.1) {
      unt=0;
      for (i=0; i< ARRAY_SIZE(g); i++)
          if (g[i] < u) {
            unt++;
          }
      if(unt>300 && !nullfound) {
          fprintf(stderr,"baseline at %.2f\n",u);
          nullinie=u;
          nullfound=1;
      }
      if (debug)
          fprintf(stderr,"%f %d\n",u,unt);
    }
    return nullinie;
}

static void 
findstations(void)
{
    float maxg=0,ming=8;
    int i;

    for (i=0; i< ARRAY_SIZE(g); i++) {
      if (g[i]<ming) ming=g[i];
      if (g[i]>maxg) maxg=g[i];
    }

    if (write_config)
      printf("[Stations]\n");
    baseline=get_baseline(ming,maxg);
    findmax();
}

static void do_scan(int fd,int scan)
{
    FILE * fmap=NULL;
    float freq,s; 
    int i,j;

    if(scan > 1)
      fmap=fopen("radio.fmmap","w");
    for (i=0; i< ARRAY_SIZE(g); i++) {
      freq = (FREQ_MIN + i * FREQ_STEP)/1e6;
      s = 0;
      radio_setfreq(fd,freq);
      usleep(10000); /* give the tuner some time to settle */
      for(j=0;j<5;j++) {
          s+=radio_getsignal(fd);
          radio_getstereo(fd);
          usleep(1000);
      }
      g[i]=s/5; // average
      if (scan > 1)
          fprintf(fmap,"%f %f\n", freq,s);
      fprintf(stderr,"scanning: %6.2f MHz - %.2f\r", freq,s);
    }
    fprintf(stderr,"%40s\r","");
    if (scan > 1)
      fclose(fmap);
    findstations();
}

/* ---------------------------------------------------------------------- */

static void
usage(FILE *out)
{
    fprintf(out,
          "radio -- interactive ncurses radio application\n"
          "usage:\n"
          "  radio [ options ]\n"
          "\n"
          "options:\n"
          "  -h       print this text\n"
          "  -d       enable debug output\n"
          "  -m       mute radio\n"
          "  -f freq  tune given frequency (also unmutes)\n"
          "  -c dev   use given device        [default: %s]\n"
          "  -s       scan\n"
          "  -S       scan + write radio.fmmap\n"
          "  -i       scan, write initial ~/.radio config file to\n"
          "           stdout and quit\n"
          "  -q       quit.  Useful with other options to control the\n"
          "           radio device without entering interactive mode,\n"
          "           i.e. \"radio -qf 91.4\"\n"
          "\n"
          "(c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>\n"
          "interface by Juli Merino <jmmv@mail.com>\n"
          "channel scan by Gunther Mayer <Gunther.Mayer@t-online.de>\n",
          device);
}

int
main(int argc, char *argv[])
{
    /* JMMV: lastfreq set to 1 to start radio at 0.0 */
    int    fd,key=0,done,i,ifreq = 0,lastfreq = 1, mute=1;
    char   *name;
    /* Variables set by JMMV */
    float  ffreq, newfreq = 0;
    int    stset = 0, c;
    int    quit=0, scan=0, arg_mute=0;
    struct video_tuner tuner;

    /* parse args */
    for (;;) {
      c = getopt(argc, argv, "mhiqdsSf:c:");
      if (c == -1)
          break;
      switch (c) {
      case 'm':
          arg_mute = 1;
          break;
      case 'q':
          quit = 1;
          break;
      case 'd':
          debug= 1;
          break;
      case 'S':
          scan = 2;
          break;
      case 's':
          scan = 1;
          break;
      case 'i':
          write_config = 1;
          scan = 1;
          quit = 1;
          break;
      case 'f':
          if (1 == sscanf(optarg,"%f",&ffreq)) {
            ifreq = (int)(ffreq * 1000000);
            ifreq += FREQ_STEP/2;
            ifreq -= ifreq % FREQ_STEP;
          }
          break;
      case 'c':
          device = optarg;
          break;
      case 'h':
          usage(stdout);
          exit(0);
      default:
          usage(stderr);
          exit(1);
      }
    }
    
    if (-1 == (fd = open(device, O_RDONLY))) {
      fprintf(stderr,"open %s: %s\n",device,strerror(errno));
      exit(1);
    }

    memset(&tuner,0,sizeof(tuner));
    if (0 == ioctl(fd, VIDIOCGTUNER, &tuner) &&
      (tuner.flags & VIDEO_TUNER_LOW))
      freqfact = 16000;

    /* non-interactive stuff */
    if (scan) {
      do_scan(fd,scan);
      if (!ifreq  &&  max_astation) {
          current_astation = 0;
            ifreq = FREQ_MIN + astation[current_astation]*50000;
      }
    }
    if (ifreq) {
      ffreq = (float)ifreq / 1000000;
      fprintf(stderr,"tuned %.2f MHz\n",ffreq);
      radio_setfreq(fd,ffreq);
      radio_unmute(fd);
    }
    if (arg_mute) {
      fprintf(stderr,"muted radio\n");
      radio_mute(fd);
    }
    if (quit)
      exit(0);

    read_kradioconfig();
    if (!ifreq && fkeys[0])
      ifreq = fkeys[0];

    /* enter interactive mode -- init ncurses */
    ncurses=1;
    initscr();
    start_color();
    cbreak();
    noecho();
    keypad(stdscr,1);
    curs_set(0);
    
    /* JMMV: Set colors and windows */
    /* XXX: Color definitions are wrong! BLUE is RED, CYAN is YELLOW and
     * viceversa */
    init_pair(1,COLOR_WHITE,COLOR_BLACK);
    init_pair(2,COLOR_CYAN,COLOR_BLUE);
    init_pair(3,COLOR_WHITE,COLOR_RED);
    bkgd(A_BOLD | COLOR_PAIR(1));
    refresh();

    wfreq = newwin(7,32,1,2);
    wbkgd(wfreq,A_BOLD | COLOR_PAIR(2));
    werase(wfreq);
    box(wfreq, 0, 0);
    mvwprintw(wfreq, 0, 1, " Tuner ");
    
    woptions = newwin(7,COLS-38,1,36);
    wbkgd(woptions,A_BOLD | COLOR_PAIR(3));
    werase(woptions);
    box(woptions, 0, 0);
    mvwprintw(woptions, 0, 1, " Main menu ");

    wstations = newwin(LINES-14,COLS-4,9,2);
    wbkgd(wstations,A_BOLD | COLOR_PAIR(3));
    werase(wstations);
    box(wstations, 0, 0);
    mvwprintw(wstations, 0, 1, " Preset stations ");
    
    wcommand = newwin(3,COLS-4,LINES-4,2);
    wbkgd(wcommand,A_BOLD | COLOR_PAIR(3));
    werase(wcommand);
    box(wcommand,0,0);
    mvwprintw(wcommand, 0, 1, " Command window ");
    wrefresh(wcommand);    
    
    /* JMMV: Added key information and windows division */
    mvwprintw(woptions, 1, 1, "Up/Down     - inc/dec frequency");
    mvwprintw(woptions, 2, 1, "PgUp/PgDown - next/prev station");
    mvwprintw(woptions, 3, 1, "g           - go to frequency...");
    mvwprintw(woptions, 4, 1, "x           - exit");
    mvwprintw(woptions, 5, 1, "ESC, q, e   - mute and exit");
    wrefresh(woptions);
    for (i = 0, c = 1; i < 8; i++) {
      if (fkeys[i]) {
          mvwprintw(wstations,c,2,"F%d: %s",i+1,make_label(fkeys[i]));
          c++;
          stset = 1;
      }
    }
    if (!stset)
      mvwprintw(wstations,1,1,"[none]");
    wrefresh(wstations);

    if (ifreq == 0) {
      float ffreq;
      radio_getfreq(fd,&ffreq);
      ifreq = ffreq * 1000000;
    }
    
    radio_unmute(fd);
    for (done = 0; done == 0;) {
      if (ifreq != lastfreq) {
          lastfreq = ifreq;
          ffreq = (float)ifreq / 1000000;
          radio_setfreq(fd,ffreq);
          print_freq(ffreq);
          if (NULL != (name = find_label(ifreq)))
            mvwprintw(wfreq,5,2,"%-20.20s",name);
          else
            mvwprintw(wfreq,5,2,"%-20.20s","");
      }
      radio_getstereo(fd);
      radio_getsignal(fd);
      wrefresh(wfreq);
      wrefresh(wcommand);

      if (0 == select_wait(1)) {
          mvwprintw(wcommand,1,1,"%50.50s","");
          wrefresh(wcommand);
          continue;
      }
      key = getch();
      switch (key) {
      case EOF:
      case 'x':
      case 'X':
          mute = 0;
          /* fall throuth */
      case 27: /* ESC */
      case 'q':
      case 'Q':
      case 'e':
      case 'E':
          done = 1;
          break;
      case 'g':
      case 'G':
          /* JMMV: Added 'go to frequency' function */
          mvwprintw(wcommand,1,2,"GO: Enter frequency: ");
          curs_set(1);
          echo();
          wrefresh(wcommand);
          wscanw(wcommand,"%f",&newfreq);
          noecho();
          curs_set(0);
          wrefresh(wcommand);
          if ((newfreq >= FREQ_MIN/1e6) && (newfreq <= FREQ_MAX/1e6) )
            ifreq = newfreq * 1000000;
          else
            mvwprintw(wcommand, 1, 2,
                    "Frequency out of range (87.5-108 MHz)");
          break;
      case KEY_UP:
            ifreq += FREQ_STEP;
            if (ifreq > FREQ_MAX)
            ifreq = FREQ_MIN;
          mvwprintw(wcommand, 1, 2, "Increment frequency");
          break;
      case KEY_DOWN:
            ifreq -= FREQ_STEP;
            if (ifreq < FREQ_MIN)
            ifreq = FREQ_MAX;
          mvwprintw(wcommand, 1, 2, "Decrease frequency");
          break;
      case KEY_PPAGE:
      case KEY_NPAGE:
      case ' ':
          if (max_astation) {
            current_astation += (key == KEY_NPAGE) ? -1 : 1;
            if(current_astation<0)
                current_astation=max_astation;
            if(current_astation>max_astation)
                current_astation=0;
            ifreq=FREQ_MIN+astation[current_astation]*FREQ_STEP;
          } else {
            for (i = 0; i < stations; i++) {
                if (ifreq == freqs[i])
                  break;
            }
            if (i != stations) {
                i += (key == KEY_NPAGE) ? -1 : 1;
                if (i < 0 || i >= stations)
                  i = 0;
                ifreq = freqs[i];
            }
          }
          break;
        case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case KEY_F(1):
      case KEY_F(2):
      case KEY_F(3):
      case KEY_F(4):
      case KEY_F(5):
      case KEY_F(6):
      case KEY_F(7):
      case KEY_F(8):
          i = (key >= '1' && key <= '8')  ?  key - '1' : key - KEY_F(1);
          if (fkeys[i]) {
            ifreq = fkeys[i];
            mvwprintw(wcommand, 1, 2, "Go to preset station %d", i+1);
          }
          break;
      case 'L' & 0x1f:  /* Ctrl-L */
          redrawwin(stdscr);
          redrawwin(wfreq);
          redrawwin(woptions);
          redrawwin(wstations);
          redrawwin(wcommand);
          wrefresh(stdscr);
          wrefresh(wfreq);
          wrefresh(woptions);
          wrefresh(wstations);
          wrefresh(wcommand);
          break;
      }
    }
    if (mute)
      radio_mute(fd);
    close(fd);

    bkgd(0);
    clear();
    refresh();
    endwin();
    return 0;
}

Generated by  Doxygen 1.6.0   Back to index