1/*
2 *  TI FM kernel driver's sample application.
3 *
4 *  Copyright (C) 2010 Texas Instruments
5 *
6 *  This program is free software; you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License version 2 as
8 *  published by the Free Software Foundation.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with this program; if not, write to the Free Software
17 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 *
19 */
20
21#include <stdio.h>
22#include <fcntl.h>
23#include <linux/videodev2.h>
24#include <math.h>
25#include <pthread.h>
26#include <errno.h>
27#include <signal.h>
28#include <string.h>
29#include <stdlib.h>
30#include <tinyalsa/asoundlib.h>
31#include <poll.h>
32
33#include "kfmapp.h"
34
35static unsigned int pdevice = 0;                        /* playback device */
36static unsigned int cdevice = 1;                        /* capture device */
37static int fm_aud_enable;
38struct pcm *pcm_p = NULL;
39struct pcm *pcm_c = NULL;
40struct mixer *mixer;
41
42/* #define V4L2_TUNER_SUB_RDS 0x10 */
43
44static char *g_mutemodes[]={"Mute ON","Mute OFF","Attenuate Voice"};
45/*
46static char *g_bands[]={"Europe/US","Japan"};
47static char *g_sm_modes[]={"Stereo","Mono"};
48static char *g_rx_deemphasis_modes[]={"50 usec","75 usec"};
49static char *g_rds_opmodes[]={"RDS","RBDS"};
50static char *g_af_switch_mode[]={"Off","On"};
51*/
52static char *g_rds_modes[]={"Off","On"};
53static int g_vol_to_set;
54static pthread_t g_rds_thread_ptr;
55volatile char g_rds_thread_terminate,g_rds_thread_running;
56
57static int g_radio_fd;
58
59/* Program Type */
60static char *pty_str[]= {"None", "News", "Current Affairs",
61                         "Information","Sport", "Education",
62                         "Drama", "Culture","Science",
63                         "Varied Speech", "Pop Music",
64                         "Rock Music","Easy Listening",
65                         "Light Classic Music", "Serious Classics",
66                         "other Music","Weather", "Finance",
67                         "Childrens Progs","Social Affairs",
68                         "Religion", "Phone In", "Travel",
69                         "Leisure & Hobby","Jazz", "Country",
70                         "National Music","Oldies","Folk",
71                         "Documentary", "Alarm Test", "Alarm"};
72
73void fmapp_display_tx_menu(void)
74{
75   printf("Available FM TX Commands:\n");
76   printf("f <freq> tune to freq(in MHz)\n");
77   printf("gf get frequency(MHz)\n");
78   printf("e <val> set pre-emphasis filter value"
79           "(0 = OFF, 1 = 50 usec and 2 = 75 usec)\n");
80/*   printf("ge get pre-emphasis filter\n");*/
81   printf("p <val> set FM TX powerlevel (91 - 122)\n");
82/*   printf("gp get deemphasis filter\n");
83   printf("i <val> set FM TX antenna impedance value (0 = 50, 1 = 200 and 2 = 500)\n");
84   printf("gi get FM TX antenna impedance value\n");*/
85   printf("1 to set RDS Radio Text\n");
86   printf("2 to set RDS Radio PS Name\n");
87   printf("3 <value> to set RDS Radio PI code\n");
88   printf("4 <value> to set RDS Radio PTY\n");
89   printf("5 <AF Freq in KHz> to set RDS Radio Alternate Frequency\n");
90}
91void fmapp_display_rx_menu(void)
92{
93   printf("Available FM RX Commands:\n");
94/* printf("p power on/off\n"); */
95   printf("f <freq> tune to freq(in MHz)\n");
96   printf("gf get frequency(MHz)\n");
97   printf("gr get rssi level\n");
98   printf("t  turns RDS on/off\n");
99   printf("gt get RDS on/off\n");
100   printf("+ increases the volume\n");
101   printf("- decreases the volume\n");
102   printf("v <0-65535> sets the volume\n");
103   printf("gv get volume\n");
104   printf("b<value> switches Japan / Eur-Us (0=US/Eur & 1=Japan)\n");
105   printf("gb get band\n");
106   printf("s switches stereo / mono\n");
107   printf("gs get stereo/mono mode\n");
108   printf("m changes mute mode\n");
109   printf("gm get mute mode\n");
110/* printf("e set deemphasis filter\n");
111   printf("ge get deemphasis filter\n");
112   printf("d set rf dependent mute\n");
113   printf("gd get rf dependent mute\n");
114   printf("z set rds system\n");
115   printf("gz get rds system\n"); */
116   printf("c<value> set rds af switch(0-OFF & 1=ON)\n");
117   printf("gc get rds af switch\n");
118   printf("< seek down\n");
119   printf("> seek up\n");
120   printf("? <(0)-(127)> set RSSI threshold\n");
121   printf("g? get rssi threshold\n");
122   printf("ga get tuner attributes\n");
123/* printf("gn auto scan\n"); */
124   printf("A Start FM RX Audio Routing\n");
125   printf("q quit rx menu\n");
126}
127int fmapp_get_tx_ant_imp(void)
128{
129    struct v4l2_control vctrl;
130    int res;
131
132    vctrl.id = V4L2_CID_TUNE_ANTENNA_CAPACITOR;
133
134    res = ioctl(g_radio_fd,VIDIOC_G_CTRL,&vctrl);
135    if(res < 0)
136    {
137        printf("Failed to get FM Tx antenna impedence value\n");
138        return res;
139    }
140
141    printf("FM Tx antenna impedence value is --> %d\n",vctrl.value);
142    return 0;
143}
144
145int fmapp_get_tx_power_level(void)
146{
147    struct v4l2_control vctrl;
148    int res;
149
150    vctrl.id = V4L2_CID_TUNE_POWER_LEVEL;
151
152    res = ioctl(g_radio_fd,VIDIOC_G_CTRL,&vctrl);
153    if(res < 0)
154    {
155        printf("Failed to get FM Tx power level\n");
156        return res;
157    }
158
159    printf("FM Tx Power level is --> %d\n",vctrl.value);
160    return 0;
161}
162int fmapp_get_premphasis_filter_mode(void)
163{
164    struct v4l2_control vctrl;
165    int res;
166
167    vctrl.id = V4L2_CID_TUNE_PREEMPHASIS;
168
169    res = ioctl(g_radio_fd,VIDIOC_G_CTRL,&vctrl);
170    if(res < 0)
171    {
172        printf("Failed to get preemphasis filter val\n");
173        return res;
174    }
175
176    printf("Preemphasis filter val is --> %d\n",vctrl.value);
177    return 0;
178}
179int fmapp_get_tx_frequency(void)
180{
181    struct v4l2_frequency vf;
182    struct v4l2_modulator vm;
183    int res, div;
184
185    vm.index = 0;
186    res = ioctl(g_radio_fd, VIDIOC_G_MODULATOR, &vm);
187    if(res < 0)
188    {
189        printf("Failed to get modulator capabilities\n");
190        return res;
191    }
192
193    res = ioctl(g_radio_fd, VIDIOC_G_FREQUENCY,&vf);
194    if(res < 0)
195    {
196        printf("Failed to read current frequency\n");
197        return res;
198    }
199
200    div = (vm.capability & V4L2_TUNER_CAP_LOW) ? 1000 : 1;
201
202    printf("Transmitting at Frequency %3.2f MHz\n",vf.frequency /
203            ( 16000.0 * div));
204    return 0;
205}
206int fmapp_get_rx_frequency(void)
207{
208   struct v4l2_frequency vf;
209   struct v4l2_tuner vt;
210   int res, div;
211
212   vt.index = 0;
213   res = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vt);
214   if(res < 0)
215   {
216       printf("Failed to get tuner capabilities\n");
217       return res;
218   }
219
220   res = ioctl(g_radio_fd, VIDIOC_G_FREQUENCY,&vf);
221   if(res < 0)
222   {
223     printf("Failed to read current frequency\n");
224     return res;
225   }
226
227   div = (vt.capability & V4L2_TUNER_CAP_LOW) ? 1000 : 1;
228
229   printf("Tuned to frequency %3.2f MHz \n",vf.frequency / ( 16.0 * div));
230   return 0;
231}
232
233int fmapp_set_tx_rds_radio_text(void)
234{
235    struct v4l2_ext_controls_kfmapp vec;
236    struct v4l2_ext_control_kfmapp vctrls;
237    int res;
238    char rds_text[100];
239
240    vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX;
241    vec.count = 1;
242    vctrls.id = V4L2_CID_RDS_TX_RADIO_TEXT;
243    printf("Enter RDS text to transmit\n");
244    scanf("%s", rds_text);
245    vctrls.string = rds_text;
246    vctrls.size = strlen(rds_text) + 1;
247    vec.controls = &vctrls;
248
249    printf("Entered RDS text is - %s and strlen = %d\n",vctrls.string, vctrls.size);
250    res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec);
251    if(res < 0)
252    {
253        printf("Failed to set FM Tx RDS Radio text\n");
254        return res;
255    }
256
257    printf("FM Modulator RDS Radio text is set and transmitted\n");
258
259    return res;
260}
261
262int fmapp_set_tx_rds_radio_ps_name(void)
263{
264    struct v4l2_ext_controls_kfmapp vec;
265    struct v4l2_ext_control_kfmapp vctrls;
266    int res;
267    char rds_text[100];
268
269    vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX;
270    vec.count = 1;
271    vctrls.id = V4L2_CID_RDS_TX_PS_NAME;
272    printf("Enter RDS PS Name to transmit\n");
273    scanf("%s", rds_text);
274    vctrls.string = rds_text;
275    vctrls.size = strlen(rds_text) + 1;
276    vec.controls = &vctrls;
277
278    printf("Entered RDS text is - %s\n",vctrls.string);
279    res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec);
280    if(res < 0)
281    {
282        printf("Failed to set FM Tx RDS Radio PS Name\n");
283        return res;
284    }
285
286    printf("FM Modulator RDS Radio PS Name set and transmitted\n");
287
288    return res;
289}
290
291int fmapp_set_tx_rds_radio_pi_code(char *cmd)
292{
293        struct v4l2_ext_controls_kfmapp vec;
294        struct v4l2_ext_control_kfmapp vctrls;
295    int user_val;
296    int res;
297
298    sscanf(cmd, "%d", &user_val);
299
300        vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX;
301        vec.count = 1;
302        vctrls.id = V4L2_CID_RDS_TX_PI;
303        vctrls.value = user_val;
304        vctrls.size = 0;
305        vec.controls = &vctrls;
306
307        res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec);
308        if(res < 0)
309        {
310                printf("Failed to set FM Tx RDS PI Code\n");
311                return res;
312        }
313
314        printf("Setting FM Tx RDS PI Code is Succesful\n");
315
316        return res;
317
318}
319
320int fmapp_set_tx_rds_radio_af(char *cmd)
321{
322    int fd, res, af_freq;
323
324    fd = open(FMTX_RDS_AF_SYSFS_ENTRY, O_RDWR);
325    if (fd < 0) {
326        printf("Can't open %s", FMTX_RDS_AF_SYSFS_ENTRY);
327        return -1;
328    }
329
330    res = write(fd, cmd, FMAPP_AF_MAX_FREQ_RANGE);
331    if(res <= 0){
332        printf("Failed to set FM TX RDS Alternate Frequency\n");
333        goto exit;
334    }
335
336    printf("FM RDS Alternate Frequency is to %s Succesfully\n", cmd);
337exit:
338    close(fd);
339    return res;
340
341}
342int fmapp_set_tx_rds_radio_pty(char *cmd)
343{
344        struct v4l2_ext_controls_kfmapp vec;
345        struct v4l2_ext_control_kfmapp vctrls;
346    int user_val;
347    int res;
348
349    sscanf(cmd, "%d", &user_val);
350
351        vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX;
352        vec.count = 1;
353        vctrls.id = V4L2_CID_RDS_TX_PTY;
354        vctrls.value = user_val;
355        vctrls.size = 0;
356        vec.controls = &vctrls;
357
358        res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec);
359        if(res < 0)
360        {
361                printf("Failed to set FM Tx RDS PTY\n");
362                return res;
363        }
364
365        printf("Setting FM Tx RDS PTY is Succesful\n");
366
367        return res;
368
369}
370int fmapp_set_tx_ant_imp(char *cmd)
371{
372    int user_val;
373    struct v4l2_control vctrl;
374    int res;
375
376    sscanf(cmd, "%d", &user_val);
377
378    vctrl.id = V4L2_CID_TUNE_ANTENNA_CAPACITOR;
379    vctrl.value = user_val;
380    res = ioctl(g_radio_fd,VIDIOC_S_CTRL,&vctrl);
381    if(res < 0)
382    {
383        printf("Failed to set FM Tx antenna impedence value\n");
384        return res;
385    }
386
387    printf("Setting FM Tx antenna impedence value to ---> %d\n",vctrl.value);
388    return 0;
389}
390
391int fmapp_set_tx_power_level(char *cmd)
392{
393        struct v4l2_ext_controls_kfmapp vec;
394        struct v4l2_ext_control_kfmapp vctrls;
395    int user_val;
396    int res;
397
398    sscanf(cmd, "%d", &user_val);
399
400        vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX;
401        vec.count = 1;
402        vctrls.id = V4L2_CID_TUNE_POWER_LEVEL;
403        vctrls.value = user_val;
404        vctrls.size = 0;
405        vec.controls = &vctrls;
406
407        res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec);
408        if(res < 0)
409        {
410                printf("Failed to set FM Tx power level\n");
411                return res;
412        }
413
414        printf("Setting FM Tx Power level to ---> %d\n", vctrls.value);
415
416        return res;
417
418}
419int fmapp_set_premphasis_filter_mode(char *cmd)
420{
421        struct v4l2_ext_controls_kfmapp vec;
422        struct v4l2_ext_control_kfmapp vctrls;
423    int user_val;
424    int res;
425
426    sscanf(cmd, "%d", &user_val);
427
428        vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX;
429        vec.count = 1;
430        vctrls.id = V4L2_CID_TUNE_PREEMPHASIS;
431        vctrls.value = user_val;
432        vctrls.size = 0;
433        vec.controls = &vctrls;
434
435        res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec);
436        if(res < 0)
437        {
438                printf("Failed to set preemphasis filter val\n");
439                return res;
440        }
441
442        printf("Setting preemphasis filter val success\n");
443
444        return res;
445
446}
447
448int fmapp_set_tx_frequency(char *cmd)
449{
450   float user_freq;
451   struct v4l2_frequency vf;
452   struct v4l2_modulator vm;
453   int res, div;
454
455   sscanf(cmd, "%f", &user_freq);
456
457   vm.index = 0;
458   res = ioctl(g_radio_fd, VIDIOC_G_MODULATOR, &vm);
459   if(res < 0)
460   {
461       printf("Failed to get modulator capabilities\n");
462       return res;
463   }
464
465   vf.tuner = 0;
466   vf.frequency = rint(user_freq * 16000 + 0.5);
467
468   div = (vm.capability & V4L2_TUNER_CAP_LOW) ? 1000 : 1;
469   if (div == 1)
470       vf.frequency /= 1000;
471
472   res = ioctl(g_radio_fd, VIDIOC_S_FREQUENCY, &vf);
473   if(res < 0)
474   {
475       printf("Failed to set frequency %f\n",user_freq);
476       return res;
477   }
478   printf("Started Transmitting at %3.2f MHz Frequency\n", vf.frequency /
479           (16.0 * div));
480
481   return res;
482}
483int fmapp_set_rx_frequency(char *cmd)
484{
485   float user_freq;
486   struct v4l2_frequency vf;
487   struct v4l2_tuner vt;
488   int res, div;
489
490   sscanf(cmd, "%f", &user_freq);
491
492   vf.tuner = 0;
493   /* As per V4L2 specifications VIDIOC_S_FREQUENCY ioctl expects tuning
494    * frequency in units of 62.5 KHz, or if the struct v4l2_tuner or struct
495    * v4l2_modulator capabilities flag V4L2_TUNER_CAP_LOW is set, in units
496    * of 62.5 Hz. But FM ST v4l2 driver presently handling the frequency in
497    * units of 1 KHz
498    */
499   vf.frequency = rint(user_freq * 16000 + 0.5);
500
501   vt.index = 0;
502   res = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vt);
503   if(res < 0)
504   {
505       printf("Failed to get tuner capabilities\n");
506       return res;
507   }
508
509   div = (vt.capability & V4L2_TUNER_CAP_LOW) ? 1000 : 1;
510   if (div == 1)
511    vf.frequency /= 1000;
512
513   if(vf.frequency < vt.rangelow || vf.frequency > vt.rangehigh){
514    printf("Failed to set frequency: Frequency is not in range"
515        "(%3.2f MHz to %3.2f MHz)\n", (vt.rangelow/(16.0 * div)),
516        (vt.rangehigh/(16.0 * div)));
517    return -EINVAL;
518   }
519
520   res = ioctl(g_radio_fd, VIDIOC_S_FREQUENCY, &vf);
521   if(res < 0)
522   {
523       printf("Failed to set frequency %f\n",user_freq);
524       return res;
525   }
526   printf("Tuned to frequency %3.2f MHz\n", vf.frequency / (16.0 * div));
527   return 0;
528}
529
530inline void display_volume_bar(void)
531{
532  int index;
533  printf("\nVolume: ");
534  for(index=1; index<g_vol_to_set; index = index*1000)
535     printf("#");
536
537  printf("\nVolume is : %d\n",g_vol_to_set);
538
539}
540int fmapp_set_rx_volume(char *cmd,int interactive,int vol_to_set)
541{
542   struct v4l2_control vctrl;
543   int res;
544
545   if(interactive == FMAPP_INTERACTIVE)
546     sscanf(cmd, "%d", &g_vol_to_set);
547   else
548     g_vol_to_set = vol_to_set;
549
550   vctrl.id = V4L2_CID_AUDIO_VOLUME;
551   vctrl.value = g_vol_to_set;
552   res = ioctl(g_radio_fd,VIDIOC_S_CTRL,&vctrl);
553   if(res < 0)
554   {
555     g_vol_to_set = 0;
556     printf("Failed to set volume\n");
557     return res;
558   }
559   printf("Setting volume to %d \n",g_vol_to_set);
560   return 0;
561}
562
563int fmapp_get_rx_volume(void)
564{
565   struct v4l2_control vctrl;
566   int res;
567
568   vctrl.id = V4L2_CID_AUDIO_VOLUME;
569   res = ioctl(g_radio_fd,VIDIOC_G_CTRL,&vctrl);
570   if(res < 0)
571   {
572     printf("Failed to get volume\n");
573     return res;
574   }
575   g_vol_to_set = vctrl.value;
576
577   printf("Radio Volume is set to %d\n",g_vol_to_set);
578//   display_volume_bar();
579   return 0;
580}
581
582int fmapp_rx_increase_volume(void)
583{
584   int ret;
585
586   g_vol_to_set +=1;
587   if(g_vol_to_set > 70)
588      g_vol_to_set = 70;
589
590   ret = fmapp_set_rx_volume(NULL,FMAPP_BATCH,g_vol_to_set);
591   if(ret < 0)
592     return ret;
593
594   display_volume_bar();
595   return 0;
596}
597int fmapp_rx_decrease_volume(void)
598{
599   int ret;
600   g_vol_to_set -=1;
601   if(g_vol_to_set < 0)
602      g_vol_to_set = 0;
603
604   ret = fmapp_set_rx_volume(NULL,FMAPP_BATCH,g_vol_to_set);
605   if(ret < 0)
606    return ret;
607
608   display_volume_bar();
609   return 0;
610}
611int fmapp_set_rx_mute_mode(void)
612{
613   struct v4l2_control vctrl;
614   static short int mute_mode = FM_MUTE_OFF;
615   int res;
616
617   vctrl.value = 0;
618   printf("Mutemode = %d\n",mute_mode);
619   switch (mute_mode)
620   {
621     case FM_MUTE_OFF:
622          mute_mode = FM_MUTE_ON;
623          break;
624
625     case FM_MUTE_ON:
626          mute_mode = FM_MUTE_OFF;
627          break;
628   }
629
630   vctrl.id = V4L2_CID_AUDIO_MUTE;
631   vctrl.value = mute_mode;
632   res = ioctl(g_radio_fd,VIDIOC_S_CTRL,&vctrl);
633   if(res < 0)
634   {
635     printf("Failed to set mute mode\n");
636     return res;
637   }
638
639  printf("Setting to \"%s\" \n",g_mutemodes[mute_mode]);
640  return 0;
641}
642int fmapp_get_rx_mute_mode(void)
643{
644   struct v4l2_control vctrl;
645   int res;
646
647   vctrl.id = V4L2_CID_AUDIO_MUTE;
648   res = ioctl(g_radio_fd,VIDIOC_G_CTRL,&vctrl);
649   if(res < 0)
650   {
651     printf("Failed to get mute mode\n");
652     return res;
653   }
654
655   printf("%s\n",g_mutemodes[vctrl.value]);
656   return 0;
657}
658int fmapp_rx_seek(int seek_direction)
659{
660   struct ti_v4l2_hw_freq_seek frq_seek;
661   int res;
662
663   printf("Seeking %s..\n",seek_direction?"up":"down");
664   frq_seek.type = 1;
665   frq_seek.seek_upward = seek_direction;
666   frq_seek.spacing = 200000;
667   frq_seek.wrap_around = 0;
668   errno = 0;
669   res = ioctl(g_radio_fd,VIDIOC_S_HW_FREQ_SEEK,&frq_seek);
670   if(errno == EAGAIN)
671   {
672     printf("Band limit reached\n");
673   }
674   else if(res <0)
675   {
676     printf("Seek operation failed\n");
677     return res;
678   }
679   /* Display seeked freq */
680   fmapp_get_rx_frequency();
681   return 0;
682}
683
684int fmapp_set_rx_af_switch(char *cmd)
685{
686    int fd, res;
687
688    fd = open(FMRX_RDS_AF_SYSFS_ENTRY, O_RDWR);
689    if (fd < 0) {
690        printf("Can't open %s", FMRX_RDS_AF_SYSFS_ENTRY);
691        return -1;
692    }
693
694    res = write(fd, cmd, sizeof(char));
695    if(res <= 0){
696        printf("Failed to set FM  RDS AF Switch\n");
697        goto exit;
698    }
699
700    printf("FM RDS Alternate Frequency is %s\n",
701            atoi(cmd) == 0 ? "OFF":"ON");
702exit:
703    close(fd);
704    return res;
705}
706
707int fmapp_get_rx_af_switch(void)
708{
709    unsigned char fm_rds_af;
710    int fd, res;
711
712    fd = open(FMRX_RDS_AF_SYSFS_ENTRY, O_RDONLY);
713    if (fd < 0) {
714        printf("Can't open %s", FMRX_RDS_AF_SYSFS_ENTRY);
715        return -1;
716    }
717
718    res = read(fd, &fm_rds_af, 1);
719    if(res < 0){
720        printf("reading %s failed %s\n",
721                FMRX_RDS_AF_SYSFS_ENTRY,strerror(res));
722        goto exit;
723    }
724
725    printf("FM RDS Alternate Frequency is %s \n",
726            (atoi((char *) &fm_rds_af)) == 0?"OFF":"ON");
727exit:
728    close(fd);
729    return 0;
730}
731
732int fmapp_get_rx_rssi_threshold(void)
733{
734    unsigned char fm_rssi_threshhold;
735    int fd, res;
736
737    fd = open(FMRX_RSSI_LVL_SYSFS_ENTRY, O_RDONLY);
738    if (fd < 0) {
739        printf("Can't open %s", FMRX_RSSI_LVL_SYSFS_ENTRY);
740        return -1;
741    }
742
743    res = read(fd, &fm_rssi_threshhold, 3);
744    if(res < 0){
745        printf("reading %s failed %s\n",
746                FMRX_RSSI_LVL_SYSFS_ENTRY,strerror(res));
747        goto exit;
748    }
749
750    printf("Current FM RSSI threshold level is %d \n",
751            atoi((char *) &fm_rssi_threshhold));
752
753exit:
754    close(fd);
755    return res;
756}
757
758int fmapp_set_rx_rssi_threshold(char *cmd)
759{
760    int fd, res;
761
762    fd = open(FMRX_RSSI_LVL_SYSFS_ENTRY, O_RDWR);
763    if (fd < 0) {
764        printf("Can't open %s", FMRX_RSSI_LVL_SYSFS_ENTRY);
765        return -1;
766    }
767
768    res = write(fd, cmd, sizeof(char) * 3);
769    if(res <= 0){
770        printf("Failed to set FM RSSI threshold level\n");
771        goto exit;
772    }
773
774    printf("FM RSSI threshold level is set to %d\n", atoi(cmd));
775
776exit:
777    close(fd);
778    return res;
779}
780
781int fmapp_set_band(char *cmd)
782{
783    int fd, res;
784
785    fd = open(FMRX_BAND_SYSFS_ENTRY, O_RDWR);
786    if (fd < 0) {
787        printf("Can't open %s", FMRX_BAND_SYSFS_ENTRY);
788        return -1;
789    }
790
791    res = write(fd, cmd, sizeof(char));
792    if(res <= 0){
793        printf("Failed to set FM Band\n");
794        goto exit;
795    }
796
797    printf("FM Band is set to %s\n", atoi(cmd) == 0?"US/EUROPE":"JAPAN");
798exit:
799    close(fd);
800    return res;
801}
802
803int fmapp_get_band(void)
804{
805    unsigned char fm_band;
806    int fd, res;
807
808    fd = open(FMRX_BAND_SYSFS_ENTRY, O_RDONLY);
809    if (fd < 0) {
810        printf("Can't open %s", FMRX_BAND_SYSFS_ENTRY);
811        return -1;
812    }
813
814    res = read(fd, &fm_band, 1);
815    if(res < 0){
816        printf("reading %s failed %s\n",FMRX_BAND_SYSFS_ENTRY,strerror(res));
817        goto exit;
818    }
819
820    printf("Present FM Band is %s \n",
821            (atoi((char *) &fm_band)) == 0?"US/EUROPE":"JAPAN");
822exit:
823    close(fd);
824    return res;
825}
826static void tinymix_set_value(struct mixer *mixer, unsigned int id,
827        int value)
828{
829  struct mixer_ctl *ctl;
830  enum mixer_ctl_type type;
831  unsigned int i, num_values;
832
833  ctl = mixer_get_ctl(mixer, id);
834  type = mixer_ctl_get_type(ctl);
835  num_values = mixer_ctl_get_num_values(ctl);
836
837  for(i=0; i<num_values; i++) {
838      if (mixer_ctl_set_value(ctl, i, value)) {
839          fprintf(stderr, "Error: invalid value\n");
840          return;
841      }
842  }
843}
844
845int fmapp_start_audio()
846{
847   struct pcm_config config;
848
849   mixer = mixer_open(0);
850   if (!mixer) {
851       fprintf(stderr, "Failed to open mixer\n");
852       return EXIT_FAILURE;
853   }
854
855   config.channels = 2;
856   config.rate = 48000;
857   config.period_size = 1024;
858   config.period_count = 4;
859   config.format = PCM_FORMAT_S16_LE;
860   config.silence_threshold = 0;
861   config.stop_threshold = -1;
862
863   if (fm_aud_enable == 0){
864       /* Set Tinymix controles */
865       tinymix_set_value(mixer, 77, 2);
866       tinymix_set_value(mixer, 76, 2);
867       tinymix_set_value(mixer, 64, 1);
868       tinymix_set_value(mixer, 65, 4);
869       tinymix_set_value(mixer, 55, 12);
870       tinymix_set_value(mixer, 54, 11);
871       tinymix_set_value(mixer, 51, 1);
872       tinymix_set_value(mixer, 9, 120);
873       tinymix_set_value(mixer, 72, 1);
874       tinymix_set_value(mixer, 73, 1);
875       tinymix_set_value(mixer, 34, 1);
876       tinymix_set_value(mixer, 50, 1);
877
878       pcm_p = pcm_open(0, pdevice, PCM_OUT, &config);
879       if (!pcm_p || !pcm_is_ready(pcm_p)) {
880           fprintf(stderr, "Unable to open PCM device (%s)\n",
881                   pcm_get_error(pcm_p));
882           return 0;
883       }
884       printf("Playback device opened successfully");
885       pcm_c = pcm_open(0, cdevice, PCM_IN, &config);
886       if (!pcm_c || !pcm_is_ready(pcm_c)) {
887           fprintf(stderr, "Unable to open PCM device (%s)\n",
888                   pcm_get_error(pcm_c));
889           return 0;
890       }
891       printf("Capture device opened successfully");
892       pcm_start(pcm_c);
893       pcm_start(pcm_p);
894       printf(" Trigered the loopback");
895       fm_aud_enable = 1;
896   }
897   else {
898       /* Set Tinymix controls to Normal*/
899       tinymix_set_value(mixer, 77, 0);
900       tinymix_set_value(mixer, 76, 0);
901       tinymix_set_value(mixer, 64, 0);
902       tinymix_set_value(mixer, 65, 0);
903       tinymix_set_value(mixer, 55, 0);
904       tinymix_set_value(mixer, 54, 0);
905       tinymix_set_value(mixer, 51, 0);
906       tinymix_set_value(mixer, 9, 0);
907       tinymix_set_value(mixer, 72, 0);
908       tinymix_set_value(mixer, 73, 0);
909       tinymix_set_value(mixer, 34, 0);
910       tinymix_set_value(mixer, 50, 0);
911
912       /* close the device */
913       pcm_stop(pcm_p);
914       pcm_stop(pcm_c);
915       pcm_close(pcm_p);
916       pcm_close(pcm_c);
917       fm_aud_enable = 0;
918   }
919   printf("FM RX Audio Routing Done\n");
920   return 0;
921}
922
923int fmapp_get_rx_rssi_lvl(void)
924{
925    struct v4l2_tuner vtun;
926    float rssi_lvl;
927    int res;
928
929    vtun.index = 0;
930    res = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vtun);
931    if(res < 0)
932    {
933        printf("Failed to get tunner attributes\n");
934        return res;
935    }
936    rssi_lvl = ((float)vtun.signal / 0xFFFF) * 100;
937    printf("Signal Strength: %d%%\n",(unsigned int)rssi_lvl);
938
939    return 0;
940}
941int fmapp_set_stereo_mono_mode(void)
942{
943    struct v4l2_tuner vtun;
944    int res = 0;
945
946    vtun.index = 0;
947    res = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vtun);
948    if(res < 0)
949    {
950        printf("Failed to set stereo-mono mode\n");
951        return res;
952    }
953
954    if(V4L2_TUNER_MODE_STEREO == vtun.audmode)
955        vtun.audmode = V4L2_TUNER_MODE_MONO;
956    else
957        vtun.audmode = V4L2_TUNER_MODE_STEREO;
958
959    res = ioctl(g_radio_fd, VIDIOC_S_TUNER, &vtun);
960    if(res < 0)
961    {
962        printf("Failed to set stereo-mono mode\n");
963        return res;
964    }
965    printf("Audio Mode set to: %s\n",(vtun.audmode == V4L2_TUNER_MODE_STEREO) ? "STEREO":"MONO");
966
967    return 0;
968}
969int fmapp_get_stereo_mono_mode(void)
970{
971    struct v4l2_tuner vtun;
972    int res;
973
974    vtun.index = 0;
975    res = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vtun);
976    if(res < 0)
977    {
978        printf("Failed to get tunner attributes\n");
979        return res;
980    }
981    printf("Audio Mode: %s\n",(vtun.audmode == V4L2_TUNER_MODE_STEREO) ? "STEREO":"MONO");
982
983    return 0;
984}
985int fmapp_get_rx_tunner_attributes(void)
986{
987   struct v4l2_tuner vtun;
988   float sigstrength_percentage;
989   int res;
990
991   vtun.index = 0;
992   res = ioctl(g_radio_fd,VIDIOC_G_TUNER,&vtun);
993   if(res < 0)
994   {
995     printf("Failed to get tunner attributes\n");
996     return res;
997   }
998   printf("-----------------------\n");
999   printf("Tuner Name: %s\n",vtun.name);
1000   /* TODO: FM driver is not setting V4L2_TUNER_CAP_LOW flag , but its returning vtun.rangelow
1001    * and vtun.rangehigh ranges in HZ . This needs to be corrected in FM driver */
1002   printf("  Low Freq: %d KHz\n",
1003           (unsigned int )((float)vtun.rangelow * 0.0625));
1004   printf(" High Freq: %d KHz\n",
1005           (unsigned int) ((float)vtun.rangehigh * 0.0625));
1006   printf("Audio Mode: %s\n",(vtun.audmode == V4L2_TUNER_MODE_STEREO) ? "STEREO":"MONO");
1007   sigstrength_percentage = ((float)vtun.signal /0xFFFF) * 100;
1008   printf("Signal Strength: %d%%\n",(unsigned int)sigstrength_percentage);
1009   printf("-----------------------\n");
1010   return 0;
1011}
1012
1013int fmapp_get_scan_valid_frequencies(void)
1014{
1015    int ret;
1016    struct v4l2_tuner vtun;
1017    struct v4l2_frequency vf;
1018    struct v4l2_control vctrl;
1019    float freq_multiplicator,start_frq,end_frq,
1020          freq,perc,threshold,divide_by;
1021    long totsig;
1022    unsigned char index;
1023
1024    vtun.index = 0;
1025    ret = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vtun); /* get frequency range */
1026    if (ret < 0) {
1027    printf("Failed to get frequency range");
1028    return ret;
1029    }
1030    freq_multiplicator = (62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW)
1031                              ? 1 : 1000));
1032
1033    divide_by = (vtun.capability & V4L2_TUNER_CAP_LOW) ? 1000000 : 1000;
1034    start_frq = ((float)vtun.rangelow * freq_multiplicator)/divide_by;
1035    end_frq = ((float)vtun.rangehigh * freq_multiplicator)/divide_by;
1036
1037    threshold = FMAPP_ASCAN_SIGNAL_THRESHOLD_PER;
1038
1039    /* Enable Mute */
1040    vctrl.id = V4L2_CID_AUDIO_MUTE;
1041    vctrl.value = FM_MUTE_ON;
1042    ret = ioctl(g_radio_fd,VIDIOC_S_CTRL,&vctrl);
1043    if(ret < 0)
1044    {
1045      printf("Failed to set mute mode\n");
1046      return ret;
1047   }
1048   printf("Auto Scanning..\n");
1049   for(freq=start_frq;freq<=end_frq;freq+=0.1)
1050   {
1051    vf.tuner = 0;
1052    vf.frequency = rint(freq*1000);
1053    ret = ioctl(g_radio_fd, VIDIOC_S_FREQUENCY, &vf);    /* tune */
1054        if (ret < 0) {
1055        printf("failed to set freq");
1056        return ret;
1057    }
1058    totsig = 0;
1059    for(index=0;index<FMAPP_ASCAN_NO_OF_SIGNAL_SAMPLE;index++)
1060    {
1061        vtun.index = 0;
1062        ret = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vtun);    /* get info */
1063        if (ret < 0) {
1064            printf("Failed to get frequency range");
1065            return ret;
1066        }
1067        totsig += vtun.signal;
1068        perc = (totsig / (65535.0 * index));
1069        usleep(1);
1070        }
1071    perc = (totsig / (65535.0 * FMAPP_ASCAN_NO_OF_SIGNAL_SAMPLE));
1072    if ((perc*100.0) > threshold)
1073       printf("%2.1f MHz(%d%%)\n",freq,((unsigned short)(perc * 100.0)));
1074   }
1075   /* Disable Mute */
1076   vctrl.id = V4L2_CID_AUDIO_MUTE;
1077   vctrl.value = FM_MUTE_OFF;
1078   ret = ioctl(g_radio_fd,VIDIOC_S_CTRL,&vctrl);
1079   if(ret < 0)
1080   {
1081      printf("Failed to set mute mode\n");
1082      return ret;
1083   }
1084   printf("Scan Completed\n");
1085   return 0;
1086}
1087int fmapp_get_rds_onoff(void)
1088{
1089    struct v4l2_tuner vtun;
1090    int res = 0;
1091
1092    vtun.index = 0;
1093    res = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vtun);
1094    if(res < 0)
1095    {
1096        printf("Failed to read RDS state\n");
1097        return res;
1098    }
1099    printf("RDS is: %s\n",(vtun.rxsubchans & V4L2_TUNER_SUB_RDS) ? "ON":"OFF");
1100
1101    return 0;
1102}
1103void fmapp_rds_decode(int blkno, int byte1, int byte2)
1104{
1105    static char rds_psn[9];
1106    static char rds_txt[65];
1107    static int  rds_pty,ms_code;
1108    static int group,spare,blkc_byte1,blkc_byte2;
1109
1110    switch (blkno) {
1111    case 0: /* Block A */
1112        printf("----------------------------------------\n");
1113        printf("block A - id=%d\n",(byte1 << 8) | byte2);
1114    break;
1115    case 1: /* Block B */
1116    printf("block B - group=%d%c tp=%d pty=%d spare=%d\n",
1117            (byte1 >> 4) & 0x0f,
1118            ((byte1 >> 3) & 0x01) + 'A',
1119            (byte1 >> 2) & 0x01,
1120            ((byte1 << 3) & 0x18) | ((byte2 >> 5) & 0x07),
1121            byte2 & 0x1f);
1122    group = (byte1 >> 3) & 0x1f;
1123    spare = byte2 & 0x1f;
1124    rds_pty = ((byte1 << 3) & 0x18) | ((byte2 >> 5) & 0x07);
1125        ms_code = (byte2 >> 3)& 0x1;
1126    break;
1127    case 2: /* Block C */
1128        printf("block C - 0x%02x 0x%02x\n",byte1,byte2);
1129    blkc_byte1 = byte1;
1130    blkc_byte2 = byte2;
1131    break;
1132    case 3 : /* Block D */
1133    printf("block D - 0x%02x 0x%02x\n",byte1,byte2);
1134    switch (group) {
1135    case 0: /* Group 0A */
1136        rds_psn[2*(spare & 0x03)+0] = byte1;
1137        rds_psn[2*(spare & 0x03)+1] = byte2;
1138        if ((spare & 0x03) == 0x03)
1139            printf("PSN: %s, PTY: %s, MS: %s\n",rds_psn,
1140                            pty_str[rds_pty],ms_code?"Music":"Speech");
1141        break;
1142    case 4: /* Group 2A */
1143        rds_txt[4*(spare & 0x0f)+0] = blkc_byte1;
1144        rds_txt[4*(spare & 0x0f)+1] = blkc_byte2;
1145        rds_txt[4*(spare & 0x0f)+2] = byte1;
1146        rds_txt[4*(spare & 0x0f)+3] = byte2;
1147            /* Display radio text once we get 16 characters */
1148//        if ((spare & 0x0f) == 0x0f)
1149        if (spare > 16)
1150            {
1151            printf("Radio Text: %s\n",rds_txt);
1152//              memset(&rds_txt,0,sizeof(rds_txt));
1153            }
1154        break;
1155         }
1156         printf("----------------------------------------\n");
1157         break;
1158     default:
1159         printf("unknown block [%d]\n",blkno);
1160    }
1161}
1162void *rds_thread(void *data)
1163{
1164  unsigned char buf[600];
1165  int radio_fd;
1166  int ret,index;
1167  struct pollfd pfd;
1168
1169  radio_fd = (int)data;
1170
1171  while(!g_rds_thread_terminate)
1172  {
1173    while(1){
1174        memset(&pfd, 0, sizeof(pfd));
1175        pfd.fd = radio_fd;
1176        pfd.events = POLLIN;
1177        ret = poll(&pfd, 1, 10);
1178        if (ret == 0){
1179            /* Break the poll after RDS data available */
1180            break;
1181        }
1182    }
1183
1184    ret = read(radio_fd,buf,500);
1185    if(ret < 0) {
1186
1187       break;
1188    }
1189    else if( ret > 0)
1190    {
1191       for(index=0;index<ret;index+=3)
1192         fmapp_rds_decode(buf[index+2] & 0x7,buf[index+1],buf[index]);
1193    }
1194  }
1195/* TODO: Need to conform thread termination.
1196 * below msg is not coming ,have a doubt on thread termination.
1197 * Fix this later.  */
1198  printf("RDS thread exiting..\n");
1199  return NULL;
1200}
1201int fmapp_set_rds_onoff(unsigned char fmapp_mode)
1202{
1203    struct v4l2_tuner vtun;
1204    int ret;
1205    static unsigned char rds_mode = FM_RDS_DISABLE;
1206
1207    vtun.index = 0;
1208    ret = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vtun);
1209    if(ret < 0)
1210    {
1211        printf("Failed to get tuner capabilities\n");
1212        return ret;
1213    }
1214    if(rds_mode == FM_RDS_DISABLE) {
1215        vtun.rxsubchans |= V4L2_TUNER_SUB_RDS;
1216        rds_mode = FM_RDS_ENABLE;
1217    } else {
1218        vtun.rxsubchans &= ~V4L2_TUNER_SUB_RDS;
1219        rds_mode = FM_RDS_DISABLE;
1220    }
1221
1222    ret = ioctl(g_radio_fd, VIDIOC_S_TUNER, &vtun);
1223    if(ret < 0)
1224    {
1225        printf("Failed to set rds on/off status\n");
1226        return ret;
1227    }
1228    /* Create rds receive thread once */
1229    if(fmapp_mode == FM_MODE_RX && rds_mode == FM_RDS_ENABLE &&
1230        g_rds_thread_running == 0)
1231    {
1232        g_rds_thread_running = 1;
1233        pthread_create(&g_rds_thread_ptr,NULL,rds_thread,(void *)g_radio_fd);
1234    }
1235
1236    printf("RDS %s\n",g_rds_modes[rds_mode]);
1237    return 0;
1238}
1239
1240void fmapp_execute_tx_get_command(char *cmd)
1241{
1242    switch(cmd[0])
1243    {
1244        case 'f':
1245            fmapp_get_tx_frequency();
1246            break;
1247        case 'e':
1248            fmapp_get_premphasis_filter_mode();
1249            break;
1250        case 'p':
1251            fmapp_get_tx_power_level();
1252            break;
1253        case 'i':
1254            fmapp_get_tx_ant_imp();
1255            break;
1256        default:
1257            printf("unknown command; type 'h' for help\n");
1258    }
1259
1260}
1261void fmapp_execute_rx_get_command(char *cmd)
1262{
1263   switch(cmd[0])
1264   {
1265     case 'f':
1266          fmapp_get_rx_frequency();
1267          break;
1268     case 'r':
1269      fmapp_get_rx_rssi_lvl();
1270          break;
1271     case 't':
1272          fmapp_get_rds_onoff();
1273          break;
1274     case 'v':
1275      fmapp_get_rx_volume();
1276          break;
1277     case 'm':
1278          fmapp_get_rx_mute_mode();
1279          break;
1280     case 'b':
1281          fmapp_get_band();
1282          break;
1283     case 'c':
1284          fmapp_get_rx_af_switch();
1285      break;
1286     case '?':
1287      fmapp_get_rx_rssi_threshold();
1288      break;
1289#if 0
1290     case 'd':
1291      fmapp_get_rfmute(fm_snd_ctrl);
1292          break;
1293     case 'z':
1294          fmapp_get_rds_operation_mode(fm_snd_ctrl);
1295      break;
1296#endif
1297     case 's':
1298          fmapp_get_stereo_mono_mode();
1299          break;
1300#if 0
1301     case 'e':
1302          fmapp_get_rx_deemphasis_filter_mode(fm_snd_ctrl);
1303          break;
1304#endif
1305     case 'a':
1306      fmapp_get_rx_tunner_attributes();
1307          break;
1308#if 0
1309     case 'n':
1310      fmapp_get_scan_valid_frequencies();
1311      break;
1312#endif
1313     default:
1314          printf("unknown command; type 'h' for help\n");
1315   }
1316}
1317void fmapp_execute_rx_other_command(char *cmd)
1318{
1319   switch(cmd[0])
1320   {
1321#if 0
1322     case 'p':
1323          fmapp_change_rx_power_mode(fm_snd_ctrl);
1324          break;
1325#endif
1326     case 'f':
1327          fmapp_set_rx_frequency(cmd+1);
1328          break;
1329     case 't':
1330          fmapp_set_rds_onoff(FM_MODE_RX);
1331          break;
1332     case '+':
1333      fmapp_rx_increase_volume();
1334          break;
1335     case '-':
1336          fmapp_rx_decrease_volume();
1337          break;
1338     case 'v':
1339      fmapp_set_rx_volume(cmd+1,FMAPP_INTERACTIVE,0);
1340      break;
1341     case 'm':
1342          fmapp_set_rx_mute_mode();
1343          break;
1344     case '<':
1345          fmapp_rx_seek(FM_SEARCH_DIRECTION_DOWN);
1346      break;
1347     case '>':
1348          fmapp_rx_seek(FM_SEARCH_DIRECTION_UP);
1349      break;
1350     case 'b':
1351          fmapp_set_band(cmd+1);
1352          break;
1353     case 'h':
1354          fmapp_display_rx_menu();
1355          break;
1356     case 'c':
1357          fmapp_set_rx_af_switch(cmd+1);
1358      break;
1359     case '?':
1360          fmapp_set_rx_rssi_threshold(cmd+1);
1361      break;
1362#if 0
1363     case 'd':
1364      fmapp_set_rfmute(fm_snd_ctrl);
1365          break;
1366     case 'z':
1367      fmapp_set_rds_operation_mode(fm_snd_ctrl);
1368      break;
1369#endif
1370     case 's':
1371          fmapp_set_stereo_mono_mode();
1372          break;
1373#if 0
1374     case 'e':
1375          fmapp_set_rx_deemphasis_filter_mode(fm_snd_ctrl);
1376          break;
1377#endif
1378     case 'A':
1379      fmapp_start_audio();
1380      break;
1381  }
1382}
1383
1384void fmapp_execute_tx_other_command(char *cmd)
1385{
1386    switch(cmd[0])
1387    {
1388        case 'f':
1389            fmapp_set_tx_frequency(cmd+1);
1390            break;
1391        case 'e':
1392            fmapp_set_premphasis_filter_mode(cmd+1);
1393            break;
1394        case 'p':
1395            fmapp_set_tx_power_level(cmd+1);
1396            break;
1397        case 'i':
1398            fmapp_set_tx_ant_imp(cmd+1);
1399            break;
1400        case '1':
1401            fmapp_set_tx_rds_radio_text();
1402            break;
1403        case '2':
1404            fmapp_set_tx_rds_radio_ps_name();
1405            break;
1406        case '3':
1407            fmapp_set_tx_rds_radio_pi_code(cmd+1);
1408            break;
1409        case '4':
1410            fmapp_set_tx_rds_radio_pty(cmd+1);
1411            break;
1412        case '5':
1413            fmapp_set_tx_rds_radio_af(cmd+1);
1414            break;
1415        case 'h':
1416            fmapp_display_tx_menu();
1417            break;
1418    }
1419}
1420/* Switch to RX mode before accepting user commands for RX */
1421void fmapp_execute_rx_command(void)
1422{
1423    char cmd[100];
1424    struct v4l2_tuner vtun;
1425    int ret;
1426
1427    vtun.index = 0;
1428    vtun.audmode = V4L2_TUNER_MODE_STEREO;
1429    vtun.rxsubchans = V4L2_TUNER_SUB_RDS;
1430    ret = ioctl(g_radio_fd, VIDIOC_S_TUNER, &vtun);
1431    if(ret < 0)
1432    {
1433        printf("Failed to set RX mode\n");
1434        return;
1435    }
1436
1437    printf("Switched to RX menu\n");
1438    printf("type 'h' for help\n");
1439
1440    while(1)
1441    {
1442        fgets(cmd, sizeof(cmd), stdin);
1443        switch(cmd[0]) {
1444        case 'g':
1445            fmapp_execute_rx_get_command(cmd+1);
1446            break;
1447        case 'q':
1448        printf("quiting RX menu\n");
1449        if (pcm_p != NULL && pcm_c != NULL)
1450            fmapp_start_audio();
1451            return;
1452        default:
1453            fmapp_execute_rx_other_command(cmd);
1454            break;
1455        }
1456    }
1457}
1458void fmapp_execute_tx_command(void)
1459{
1460    char cmd[100];
1461    struct v4l2_modulator vmod;
1462    int ret;
1463
1464    vmod.index = 0;
1465    vmod.txsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS;
1466
1467    ret = ioctl(g_radio_fd, VIDIOC_S_MODULATOR, &vmod);
1468    if(ret < 0)
1469    {
1470        printf("Failed to set TX mode\n");
1471        return;
1472    }
1473
1474    printf("Switched to TX menu\n");
1475    printf("type 'h' for help\n");
1476
1477    while(1)
1478    {
1479        fgets(cmd, sizeof(cmd), stdin);
1480        switch(cmd[0]) {
1481        case 'g':
1482            fmapp_execute_tx_get_command(cmd+1);
1483            break;
1484        case 'q':
1485            printf("quiting TX menu\n");
1486            return;
1487        default:
1488            fmapp_execute_tx_other_command(cmd);
1489            break;
1490        }
1491    }
1492}
1493
1494int fmapp_read_anddisplay_capabilities(void)
1495{
1496  struct v4l2_capability cap;
1497  int res;
1498
1499  res = ioctl(g_radio_fd,VIDIOC_QUERYCAP,&cap);
1500  if(res < 0)
1501  {
1502    printf("Failed to read %s capabilities\n",DEFAULT_RADIO_DEVICE);
1503    return res;
1504  }
1505  if((cap.capabilities & V4L2_CAP_RADIO) == 0)
1506  {
1507    printf("%s is not radio devcie",DEFAULT_RADIO_DEVICE);
1508    return -1;
1509  }
1510  printf("\n***%s Info ****\n",DEFAULT_RADIO_DEVICE);
1511  printf("Driver       : %s\n",cap.driver);
1512  printf("Card         : %s\n",cap.card);
1513  printf("Bus          : %s\n",cap.bus_info);
1514  printf("Capabilities : 0x%x\n",cap.capabilities);
1515
1516  return 0;
1517}
1518
1519static void sig_handler()
1520{
1521  if(g_rds_thread_running)
1522      g_rds_thread_terminate = 1;
1523
1524  close(g_radio_fd);
1525  printf("Terminating..\n\n");
1526  exit(1);
1527}
1528int main()
1529{
1530   char choice[100];
1531   char exit_flag;
1532   int ret;
1533   struct sigaction sa;
1534
1535   printf("** TI Kernel Space FM Driver Test Application **\n");
1536
1537   printf("Opening device '%s'\n",DEFAULT_RADIO_DEVICE);
1538   g_radio_fd = open(DEFAULT_RADIO_DEVICE, O_RDWR);
1539   if(g_radio_fd < 0)
1540   {
1541       printf("Unable to open %s \nTerminating..\n",DEFAULT_RADIO_DEVICE);
1542       return 0;
1543   }
1544   ret = fmapp_read_anddisplay_capabilities();
1545   if(ret< 0)
1546   {
1547     close(g_radio_fd);
1548     return ret;
1549   }
1550   /* to handle ctrl + c and kill signals */
1551   memset(&sa, 0, sizeof(sa));
1552   sa.sa_handler = sig_handler;
1553   sigaction(SIGTERM, &sa, NULL);
1554   sigaction(SIGINT,  &sa, NULL);
1555
1556   exit_flag = 1;
1557   while(exit_flag)
1558   {
1559       printf("1 FM RX\n");
1560       printf("2 FM TX\n");
1561       printf("3 Exit\n");
1562       fgets(choice, sizeof(choice), stdin);
1563
1564       switch(atoi(choice))
1565       {
1566           case 1: /* FM RX */
1567               fmapp_execute_rx_command();
1568               break;
1569           case 2: /* FM TX */
1570               fmapp_execute_tx_command();
1571               break;
1572           case 3:
1573               printf("Terminating..\n\n");
1574               exit_flag = 0;
1575               break;
1576           default:
1577               printf("Invalid choice , try again\n");
1578               continue;
1579       }
1580   }
1581   if(g_rds_thread_running)
1582       g_rds_thread_terminate = 1; // Terminate RDS thread
1583
1584   close(g_radio_fd);
1585   return 0;
1586}
1587
1588
1589