/* * TI FM kernel driver's sample application. * * Copyright (C) 2010 Texas Instruments * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include "kfmapp.h" static unsigned int pdevice = 0; /* playback device */ static unsigned int cdevice = 1; /* capture device */ static int fm_aud_enable; struct pcm *pcm_p = NULL; struct pcm *pcm_c = NULL; struct mixer *mixer; /* #define V4L2_TUNER_SUB_RDS 0x10 */ static char *g_mutemodes[]={"Mute ON","Mute OFF","Attenuate Voice"}; /* static char *g_bands[]={"Europe/US","Japan"}; static char *g_sm_modes[]={"Stereo","Mono"}; static char *g_rx_deemphasis_modes[]={"50 usec","75 usec"}; static char *g_rds_opmodes[]={"RDS","RBDS"}; static char *g_af_switch_mode[]={"Off","On"}; */ static char *g_rds_modes[]={"Off","On"}; static int g_vol_to_set; static pthread_t g_rds_thread_ptr; volatile char g_rds_thread_terminate,g_rds_thread_running; static int g_radio_fd; /* Program Type */ static char *pty_str[]= {"None", "News", "Current Affairs", "Information","Sport", "Education", "Drama", "Culture","Science", "Varied Speech", "Pop Music", "Rock Music","Easy Listening", "Light Classic Music", "Serious Classics", "other Music","Weather", "Finance", "Childrens Progs","Social Affairs", "Religion", "Phone In", "Travel", "Leisure & Hobby","Jazz", "Country", "National Music","Oldies","Folk", "Documentary", "Alarm Test", "Alarm"}; void fmapp_display_tx_menu(void) { printf("Available FM TX Commands:\n"); printf("f tune to freq(in MHz)\n"); printf("gf get frequency(MHz)\n"); printf("e set pre-emphasis filter value" "(0 = OFF, 1 = 50 usec and 2 = 75 usec)\n"); /* printf("ge get pre-emphasis filter\n");*/ printf("p set FM TX powerlevel (91 - 122)\n"); /* printf("gp get deemphasis filter\n"); printf("i set FM TX antenna impedance value (0 = 50, 1 = 200 and 2 = 500)\n"); printf("gi get FM TX antenna impedance value\n");*/ printf("1 to set RDS Radio Text\n"); printf("2 to set RDS Radio PS Name\n"); printf("3 to set RDS Radio PI code\n"); printf("4 to set RDS Radio PTY\n"); printf("5 to set RDS Radio Alternate Frequency\n"); } void fmapp_display_rx_menu(void) { printf("Available FM RX Commands:\n"); /* printf("p power on/off\n"); */ printf("f tune to freq(in MHz)\n"); printf("gf get frequency(MHz)\n"); printf("gr get rssi level\n"); printf("t turns RDS on/off\n"); printf("gt get RDS on/off\n"); printf("+ increases the volume\n"); printf("- decreases the volume\n"); printf("v <0-65535> sets the volume\n"); printf("gv get volume\n"); printf("b switches Japan / Eur-Us (0=US/Eur & 1=Japan)\n"); printf("gb get band\n"); printf("s switches stereo / mono\n"); printf("gs get stereo/mono mode\n"); printf("m changes mute mode\n"); printf("gm get mute mode\n"); /* printf("e set deemphasis filter\n"); printf("ge get deemphasis filter\n"); printf("d set rf dependent mute\n"); printf("gd get rf dependent mute\n"); printf("z set rds system\n"); printf("gz get rds system\n"); */ printf("c set rds af switch(0-OFF & 1=ON)\n"); printf("gc get rds af switch\n"); printf("< seek down\n"); printf("> seek up\n"); printf("? <(0)-(127)> set RSSI threshold\n"); printf("g? get rssi threshold\n"); printf("ga get tuner attributes\n"); /* printf("gn auto scan\n"); */ printf("A Start FM RX Audio Routing\n"); printf("q quit rx menu\n"); } int fmapp_get_tx_ant_imp(void) { struct v4l2_control vctrl; int res; vctrl.id = V4L2_CID_TUNE_ANTENNA_CAPACITOR; res = ioctl(g_radio_fd,VIDIOC_G_CTRL,&vctrl); if(res < 0) { printf("Failed to get FM Tx antenna impedence value\n"); return res; } printf("FM Tx antenna impedence value is --> %d\n",vctrl.value); return 0; } int fmapp_get_tx_power_level(void) { struct v4l2_control vctrl; int res; vctrl.id = V4L2_CID_TUNE_POWER_LEVEL; res = ioctl(g_radio_fd,VIDIOC_G_CTRL,&vctrl); if(res < 0) { printf("Failed to get FM Tx power level\n"); return res; } printf("FM Tx Power level is --> %d\n",vctrl.value); return 0; } int fmapp_get_premphasis_filter_mode(void) { struct v4l2_control vctrl; int res; vctrl.id = V4L2_CID_TUNE_PREEMPHASIS; res = ioctl(g_radio_fd,VIDIOC_G_CTRL,&vctrl); if(res < 0) { printf("Failed to get preemphasis filter val\n"); return res; } printf("Preemphasis filter val is --> %d\n",vctrl.value); return 0; } int fmapp_get_tx_frequency(void) { struct v4l2_frequency vf; struct v4l2_modulator vm; int res, div; vm.index = 0; res = ioctl(g_radio_fd, VIDIOC_G_MODULATOR, &vm); if(res < 0) { printf("Failed to get modulator capabilities\n"); return res; } res = ioctl(g_radio_fd, VIDIOC_G_FREQUENCY,&vf); if(res < 0) { printf("Failed to read current frequency\n"); return res; } div = (vm.capability & V4L2_TUNER_CAP_LOW) ? 1000 : 1; printf("Transmitting at Frequency %3.2f MHz\n",vf.frequency / ( 16000.0 * div)); return 0; } int fmapp_get_rx_frequency(void) { struct v4l2_frequency vf; struct v4l2_tuner vt; int res, div; vt.index = 0; res = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vt); if(res < 0) { printf("Failed to get tuner capabilities\n"); return res; } res = ioctl(g_radio_fd, VIDIOC_G_FREQUENCY,&vf); if(res < 0) { printf("Failed to read current frequency\n"); return res; } div = (vt.capability & V4L2_TUNER_CAP_LOW) ? 1000 : 1; printf("Tuned to frequency %3.2f MHz \n",vf.frequency / ( 16.0 * div)); return 0; } int fmapp_set_tx_rds_radio_text(void) { struct v4l2_ext_controls_kfmapp vec; struct v4l2_ext_control_kfmapp vctrls; int res; char rds_text[100]; vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX; vec.count = 1; vctrls.id = V4L2_CID_RDS_TX_RADIO_TEXT; printf("Enter RDS text to transmit\n"); scanf("%s", rds_text); vctrls.string = rds_text; vctrls.size = strlen(rds_text) + 1; vec.controls = &vctrls; printf("Entered RDS text is - %s and strlen = %d\n",vctrls.string, vctrls.size); res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec); if(res < 0) { printf("Failed to set FM Tx RDS Radio text\n"); return res; } printf("FM Modulator RDS Radio text is set and transmitted\n"); return res; } int fmapp_set_tx_rds_radio_ps_name(void) { struct v4l2_ext_controls_kfmapp vec; struct v4l2_ext_control_kfmapp vctrls; int res; char rds_text[100]; vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX; vec.count = 1; vctrls.id = V4L2_CID_RDS_TX_PS_NAME; printf("Enter RDS PS Name to transmit\n"); scanf("%s", rds_text); vctrls.string = rds_text; vctrls.size = strlen(rds_text) + 1; vec.controls = &vctrls; printf("Entered RDS text is - %s\n",vctrls.string); res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec); if(res < 0) { printf("Failed to set FM Tx RDS Radio PS Name\n"); return res; } printf("FM Modulator RDS Radio PS Name set and transmitted\n"); return res; } int fmapp_set_tx_rds_radio_pi_code(char *cmd) { struct v4l2_ext_controls_kfmapp vec; struct v4l2_ext_control_kfmapp vctrls; int user_val; int res; sscanf(cmd, "%d", &user_val); vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX; vec.count = 1; vctrls.id = V4L2_CID_RDS_TX_PI; vctrls.value = user_val; vctrls.size = 0; vec.controls = &vctrls; res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec); if(res < 0) { printf("Failed to set FM Tx RDS PI Code\n"); return res; } printf("Setting FM Tx RDS PI Code is Succesful\n"); return res; } int fmapp_set_tx_rds_radio_af(char *cmd) { int fd, res, af_freq; fd = open(FMTX_RDS_AF_SYSFS_ENTRY, O_RDWR); if (fd < 0) { printf("Can't open %s", FMTX_RDS_AF_SYSFS_ENTRY); return -1; } res = write(fd, cmd, FMAPP_AF_MAX_FREQ_RANGE); if(res <= 0){ printf("Failed to set FM TX RDS Alternate Frequency\n"); goto exit; } printf("FM RDS Alternate Frequency is to %s Succesfully\n", cmd); exit: close(fd); return res; } int fmapp_set_tx_rds_radio_pty(char *cmd) { struct v4l2_ext_controls_kfmapp vec; struct v4l2_ext_control_kfmapp vctrls; int user_val; int res; sscanf(cmd, "%d", &user_val); vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX; vec.count = 1; vctrls.id = V4L2_CID_RDS_TX_PTY; vctrls.value = user_val; vctrls.size = 0; vec.controls = &vctrls; res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec); if(res < 0) { printf("Failed to set FM Tx RDS PTY\n"); return res; } printf("Setting FM Tx RDS PTY is Succesful\n"); return res; } int fmapp_set_tx_ant_imp(char *cmd) { int user_val; struct v4l2_control vctrl; int res; sscanf(cmd, "%d", &user_val); vctrl.id = V4L2_CID_TUNE_ANTENNA_CAPACITOR; vctrl.value = user_val; res = ioctl(g_radio_fd,VIDIOC_S_CTRL,&vctrl); if(res < 0) { printf("Failed to set FM Tx antenna impedence value\n"); return res; } printf("Setting FM Tx antenna impedence value to ---> %d\n",vctrl.value); return 0; } int fmapp_set_tx_power_level(char *cmd) { struct v4l2_ext_controls_kfmapp vec; struct v4l2_ext_control_kfmapp vctrls; int user_val; int res; sscanf(cmd, "%d", &user_val); vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX; vec.count = 1; vctrls.id = V4L2_CID_TUNE_POWER_LEVEL; vctrls.value = user_val; vctrls.size = 0; vec.controls = &vctrls; res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec); if(res < 0) { printf("Failed to set FM Tx power level\n"); return res; } printf("Setting FM Tx Power level to ---> %d\n", vctrls.value); return res; } int fmapp_set_premphasis_filter_mode(char *cmd) { struct v4l2_ext_controls_kfmapp vec; struct v4l2_ext_control_kfmapp vctrls; int user_val; int res; sscanf(cmd, "%d", &user_val); vec.ctrl_class = V4L2_CTRL_CLASS_FM_TX; vec.count = 1; vctrls.id = V4L2_CID_TUNE_PREEMPHASIS; vctrls.value = user_val; vctrls.size = 0; vec.controls = &vctrls; res = ioctl(g_radio_fd, VIDIOC_S_EXT_CTRLS, &vec); if(res < 0) { printf("Failed to set preemphasis filter val\n"); return res; } printf("Setting preemphasis filter val success\n"); return res; } int fmapp_set_tx_frequency(char *cmd) { float user_freq; struct v4l2_frequency vf; struct v4l2_modulator vm; int res, div; sscanf(cmd, "%f", &user_freq); vm.index = 0; res = ioctl(g_radio_fd, VIDIOC_G_MODULATOR, &vm); if(res < 0) { printf("Failed to get modulator capabilities\n"); return res; } vf.tuner = 0; vf.frequency = rint(user_freq * 16000 + 0.5); div = (vm.capability & V4L2_TUNER_CAP_LOW) ? 1000 : 1; if (div == 1) vf.frequency /= 1000; res = ioctl(g_radio_fd, VIDIOC_S_FREQUENCY, &vf); if(res < 0) { printf("Failed to set frequency %f\n",user_freq); return res; } printf("Started Transmitting at %3.2f MHz Frequency\n", vf.frequency / (16.0 * div)); return res; } int fmapp_set_rx_frequency(char *cmd) { float user_freq; struct v4l2_frequency vf; struct v4l2_tuner vt; int res, div; sscanf(cmd, "%f", &user_freq); vf.tuner = 0; /* As per V4L2 specifications VIDIOC_S_FREQUENCY ioctl expects tuning * frequency in units of 62.5 KHz, or if the struct v4l2_tuner or struct * v4l2_modulator capabilities flag V4L2_TUNER_CAP_LOW is set, in units * of 62.5 Hz. But FM ST v4l2 driver presently handling the frequency in * units of 1 KHz */ vf.frequency = rint(user_freq * 16000 + 0.5); vt.index = 0; res = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vt); if(res < 0) { printf("Failed to get tuner capabilities\n"); return res; } div = (vt.capability & V4L2_TUNER_CAP_LOW) ? 1000 : 1; if (div == 1) vf.frequency /= 1000; if(vf.frequency < vt.rangelow || vf.frequency > vt.rangehigh){ printf("Failed to set frequency: Frequency is not in range" "(%3.2f MHz to %3.2f MHz)\n", (vt.rangelow/(16.0 * div)), (vt.rangehigh/(16.0 * div))); return -EINVAL; } res = ioctl(g_radio_fd, VIDIOC_S_FREQUENCY, &vf); if(res < 0) { printf("Failed to set frequency %f\n",user_freq); return res; } printf("Tuned to frequency %3.2f MHz\n", vf.frequency / (16.0 * div)); return 0; } inline void display_volume_bar(void) { int index; printf("\nVolume: "); for(index=1; index 70) g_vol_to_set = 70; ret = fmapp_set_rx_volume(NULL,FMAPP_BATCH,g_vol_to_set); if(ret < 0) return ret; display_volume_bar(); return 0; } int fmapp_rx_decrease_volume(void) { int ret; g_vol_to_set -=1; if(g_vol_to_set < 0) g_vol_to_set = 0; ret = fmapp_set_rx_volume(NULL,FMAPP_BATCH,g_vol_to_set); if(ret < 0) return ret; display_volume_bar(); return 0; } int fmapp_set_rx_mute_mode(void) { struct v4l2_control vctrl; static short int mute_mode = FM_MUTE_OFF; int res; vctrl.value = 0; printf("Mutemode = %d\n",mute_mode); switch (mute_mode) { case FM_MUTE_OFF: mute_mode = FM_MUTE_ON; break; case FM_MUTE_ON: mute_mode = FM_MUTE_OFF; break; } vctrl.id = V4L2_CID_AUDIO_MUTE; vctrl.value = mute_mode; res = ioctl(g_radio_fd,VIDIOC_S_CTRL,&vctrl); if(res < 0) { printf("Failed to set mute mode\n"); return res; } printf("Setting to \"%s\" \n",g_mutemodes[mute_mode]); return 0; } int fmapp_get_rx_mute_mode(void) { struct v4l2_control vctrl; int res; vctrl.id = V4L2_CID_AUDIO_MUTE; res = ioctl(g_radio_fd,VIDIOC_G_CTRL,&vctrl); if(res < 0) { printf("Failed to get mute mode\n"); return res; } printf("%s\n",g_mutemodes[vctrl.value]); return 0; } int fmapp_rx_seek(int seek_direction) { struct ti_v4l2_hw_freq_seek frq_seek; int res; printf("Seeking %s..\n",seek_direction?"up":"down"); frq_seek.type = 1; frq_seek.seek_upward = seek_direction; frq_seek.spacing = 200000; frq_seek.wrap_around = 0; errno = 0; res = ioctl(g_radio_fd,VIDIOC_S_HW_FREQ_SEEK,&frq_seek); if(errno == EAGAIN) { printf("Band limit reached\n"); } else if(res <0) { printf("Seek operation failed\n"); return res; } /* Display seeked freq */ fmapp_get_rx_frequency(); return 0; } int fmapp_set_rx_af_switch(char *cmd) { int fd, res; fd = open(FMRX_RDS_AF_SYSFS_ENTRY, O_RDWR); if (fd < 0) { printf("Can't open %s", FMRX_RDS_AF_SYSFS_ENTRY); return -1; } res = write(fd, cmd, sizeof(char)); if(res <= 0){ printf("Failed to set FM RDS AF Switch\n"); goto exit; } printf("FM RDS Alternate Frequency is %s\n", atoi(cmd) == 0 ? "OFF":"ON"); exit: close(fd); return res; } int fmapp_get_rx_af_switch(void) { unsigned char fm_rds_af; int fd, res; fd = open(FMRX_RDS_AF_SYSFS_ENTRY, O_RDONLY); if (fd < 0) { printf("Can't open %s", FMRX_RDS_AF_SYSFS_ENTRY); return -1; } res = read(fd, &fm_rds_af, 1); if(res < 0){ printf("reading %s failed %s\n", FMRX_RDS_AF_SYSFS_ENTRY,strerror(res)); goto exit; } printf("FM RDS Alternate Frequency is %s \n", (atoi((char *) &fm_rds_af)) == 0?"OFF":"ON"); exit: close(fd); return 0; } int fmapp_get_rx_rssi_threshold(void) { unsigned char fm_rssi_threshhold; int fd, res; fd = open(FMRX_RSSI_LVL_SYSFS_ENTRY, O_RDONLY); if (fd < 0) { printf("Can't open %s", FMRX_RSSI_LVL_SYSFS_ENTRY); return -1; } res = read(fd, &fm_rssi_threshhold, 3); if(res < 0){ printf("reading %s failed %s\n", FMRX_RSSI_LVL_SYSFS_ENTRY,strerror(res)); goto exit; } printf("Current FM RSSI threshold level is %d \n", atoi((char *) &fm_rssi_threshhold)); exit: close(fd); return res; } int fmapp_set_rx_rssi_threshold(char *cmd) { int fd, res; fd = open(FMRX_RSSI_LVL_SYSFS_ENTRY, O_RDWR); if (fd < 0) { printf("Can't open %s", FMRX_RSSI_LVL_SYSFS_ENTRY); return -1; } res = write(fd, cmd, sizeof(char) * 3); if(res <= 0){ printf("Failed to set FM RSSI threshold level\n"); goto exit; } printf("FM RSSI threshold level is set to %d\n", atoi(cmd)); exit: close(fd); return res; } int fmapp_set_band(char *cmd) { int fd, res; fd = open(FMRX_BAND_SYSFS_ENTRY, O_RDWR); if (fd < 0) { printf("Can't open %s", FMRX_BAND_SYSFS_ENTRY); return -1; } res = write(fd, cmd, sizeof(char)); if(res <= 0){ printf("Failed to set FM Band\n"); goto exit; } printf("FM Band is set to %s\n", atoi(cmd) == 0?"US/EUROPE":"JAPAN"); exit: close(fd); return res; } int fmapp_get_band(void) { unsigned char fm_band; int fd, res; fd = open(FMRX_BAND_SYSFS_ENTRY, O_RDONLY); if (fd < 0) { printf("Can't open %s", FMRX_BAND_SYSFS_ENTRY); return -1; } res = read(fd, &fm_band, 1); if(res < 0){ printf("reading %s failed %s\n",FMRX_BAND_SYSFS_ENTRY,strerror(res)); goto exit; } printf("Present FM Band is %s \n", (atoi((char *) &fm_band)) == 0?"US/EUROPE":"JAPAN"); exit: close(fd); return res; } static void tinymix_set_value(struct mixer *mixer, unsigned int id, int value) { struct mixer_ctl *ctl; enum mixer_ctl_type type; unsigned int i, num_values; ctl = mixer_get_ctl(mixer, id); type = mixer_ctl_get_type(ctl); num_values = mixer_ctl_get_num_values(ctl); for(i=0; i threshold) printf("%2.1f MHz(%d%%)\n",freq,((unsigned short)(perc * 100.0))); } /* Disable Mute */ vctrl.id = V4L2_CID_AUDIO_MUTE; vctrl.value = FM_MUTE_OFF; ret = ioctl(g_radio_fd,VIDIOC_S_CTRL,&vctrl); if(ret < 0) { printf("Failed to set mute mode\n"); return ret; } printf("Scan Completed\n"); return 0; } int fmapp_get_rds_onoff(void) { struct v4l2_tuner vtun; int res = 0; vtun.index = 0; res = ioctl(g_radio_fd, VIDIOC_G_TUNER, &vtun); if(res < 0) { printf("Failed to read RDS state\n"); return res; } printf("RDS is: %s\n",(vtun.rxsubchans & V4L2_TUNER_SUB_RDS) ? "ON":"OFF"); return 0; } void fmapp_rds_decode(int blkno, int byte1, int byte2) { static char rds_psn[9]; static char rds_txt[65]; static int rds_pty,ms_code; static int group,spare,blkc_byte1,blkc_byte2; switch (blkno) { case 0: /* Block A */ printf("----------------------------------------\n"); printf("block A - id=%d\n",(byte1 << 8) | byte2); break; case 1: /* Block B */ printf("block B - group=%d%c tp=%d pty=%d spare=%d\n", (byte1 >> 4) & 0x0f, ((byte1 >> 3) & 0x01) + 'A', (byte1 >> 2) & 0x01, ((byte1 << 3) & 0x18) | ((byte2 >> 5) & 0x07), byte2 & 0x1f); group = (byte1 >> 3) & 0x1f; spare = byte2 & 0x1f; rds_pty = ((byte1 << 3) & 0x18) | ((byte2 >> 5) & 0x07); ms_code = (byte2 >> 3)& 0x1; break; case 2: /* Block C */ printf("block C - 0x%02x 0x%02x\n",byte1,byte2); blkc_byte1 = byte1; blkc_byte2 = byte2; break; case 3 : /* Block D */ printf("block D - 0x%02x 0x%02x\n",byte1,byte2); switch (group) { case 0: /* Group 0A */ rds_psn[2*(spare & 0x03)+0] = byte1; rds_psn[2*(spare & 0x03)+1] = byte2; if ((spare & 0x03) == 0x03) printf("PSN: %s, PTY: %s, MS: %s\n",rds_psn, pty_str[rds_pty],ms_code?"Music":"Speech"); break; case 4: /* Group 2A */ rds_txt[4*(spare & 0x0f)+0] = blkc_byte1; rds_txt[4*(spare & 0x0f)+1] = blkc_byte2; rds_txt[4*(spare & 0x0f)+2] = byte1; rds_txt[4*(spare & 0x0f)+3] = byte2; /* Display radio text once we get 16 characters */ // if ((spare & 0x0f) == 0x0f) if (spare > 16) { printf("Radio Text: %s\n",rds_txt); // memset(&rds_txt,0,sizeof(rds_txt)); } break; } printf("----------------------------------------\n"); break; default: printf("unknown block [%d]\n",blkno); } } void *rds_thread(void *data) { unsigned char buf[600]; int radio_fd; int ret,index; struct pollfd pfd; radio_fd = (int)data; while(!g_rds_thread_terminate) { while(1){ memset(&pfd, 0, sizeof(pfd)); pfd.fd = radio_fd; pfd.events = POLLIN; ret = poll(&pfd, 1, 10); if (ret == 0){ /* Break the poll after RDS data available */ break; } } ret = read(radio_fd,buf,500); if(ret < 0) { break; } else if( ret > 0) { for(index=0;index': fmapp_rx_seek(FM_SEARCH_DIRECTION_UP); break; case 'b': fmapp_set_band(cmd+1); break; case 'h': fmapp_display_rx_menu(); break; case 'c': fmapp_set_rx_af_switch(cmd+1); break; case '?': fmapp_set_rx_rssi_threshold(cmd+1); break; #if 0 case 'd': fmapp_set_rfmute(fm_snd_ctrl); break; case 'z': fmapp_set_rds_operation_mode(fm_snd_ctrl); break; #endif case 's': fmapp_set_stereo_mono_mode(); break; #if 0 case 'e': fmapp_set_rx_deemphasis_filter_mode(fm_snd_ctrl); break; #endif case 'A': fmapp_start_audio(); break; } } void fmapp_execute_tx_other_command(char *cmd) { switch(cmd[0]) { case 'f': fmapp_set_tx_frequency(cmd+1); break; case 'e': fmapp_set_premphasis_filter_mode(cmd+1); break; case 'p': fmapp_set_tx_power_level(cmd+1); break; case 'i': fmapp_set_tx_ant_imp(cmd+1); break; case '1': fmapp_set_tx_rds_radio_text(); break; case '2': fmapp_set_tx_rds_radio_ps_name(); break; case '3': fmapp_set_tx_rds_radio_pi_code(cmd+1); break; case '4': fmapp_set_tx_rds_radio_pty(cmd+1); break; case '5': fmapp_set_tx_rds_radio_af(cmd+1); break; case 'h': fmapp_display_tx_menu(); break; } } /* Switch to RX mode before accepting user commands for RX */ void fmapp_execute_rx_command(void) { char cmd[100]; struct v4l2_tuner vtun; int ret; vtun.index = 0; vtun.audmode = V4L2_TUNER_MODE_STEREO; vtun.rxsubchans = V4L2_TUNER_SUB_RDS; ret = ioctl(g_radio_fd, VIDIOC_S_TUNER, &vtun); if(ret < 0) { printf("Failed to set RX mode\n"); return; } printf("Switched to RX menu\n"); printf("type 'h' for help\n"); while(1) { fgets(cmd, sizeof(cmd), stdin); switch(cmd[0]) { case 'g': fmapp_execute_rx_get_command(cmd+1); break; case 'q': printf("quiting RX menu\n"); if (pcm_p != NULL && pcm_c != NULL) fmapp_start_audio(); return; default: fmapp_execute_rx_other_command(cmd); break; } } } void fmapp_execute_tx_command(void) { char cmd[100]; struct v4l2_modulator vmod; int ret; vmod.index = 0; vmod.txsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS; ret = ioctl(g_radio_fd, VIDIOC_S_MODULATOR, &vmod); if(ret < 0) { printf("Failed to set TX mode\n"); return; } printf("Switched to TX menu\n"); printf("type 'h' for help\n"); while(1) { fgets(cmd, sizeof(cmd), stdin); switch(cmd[0]) { case 'g': fmapp_execute_tx_get_command(cmd+1); break; case 'q': printf("quiting TX menu\n"); return; default: fmapp_execute_tx_other_command(cmd); break; } } } int fmapp_read_anddisplay_capabilities(void) { struct v4l2_capability cap; int res; res = ioctl(g_radio_fd,VIDIOC_QUERYCAP,&cap); if(res < 0) { printf("Failed to read %s capabilities\n",DEFAULT_RADIO_DEVICE); return res; } if((cap.capabilities & V4L2_CAP_RADIO) == 0) { printf("%s is not radio devcie",DEFAULT_RADIO_DEVICE); return -1; } printf("\n***%s Info ****\n",DEFAULT_RADIO_DEVICE); printf("Driver : %s\n",cap.driver); printf("Card : %s\n",cap.card); printf("Bus : %s\n",cap.bus_info); printf("Capabilities : 0x%x\n",cap.capabilities); return 0; } static void sig_handler() { if(g_rds_thread_running) g_rds_thread_terminate = 1; close(g_radio_fd); printf("Terminating..\n\n"); exit(1); } int main() { char choice[100]; char exit_flag; int ret; struct sigaction sa; printf("** TI Kernel Space FM Driver Test Application **\n"); printf("Opening device '%s'\n",DEFAULT_RADIO_DEVICE); g_radio_fd = open(DEFAULT_RADIO_DEVICE, O_RDWR); if(g_radio_fd < 0) { printf("Unable to open %s \nTerminating..\n",DEFAULT_RADIO_DEVICE); return 0; } ret = fmapp_read_anddisplay_capabilities(); if(ret< 0) { close(g_radio_fd); return ret; } /* to handle ctrl + c and kill signals */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = sig_handler; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); exit_flag = 1; while(exit_flag) { printf("1 FM RX\n"); printf("2 FM TX\n"); printf("3 Exit\n"); fgets(choice, sizeof(choice), stdin); switch(atoi(choice)) { case 1: /* FM RX */ fmapp_execute_rx_command(); break; case 2: /* FM TX */ fmapp_execute_tx_command(); break; case 3: printf("Terminating..\n\n"); exit_flag = 0; break; default: printf("Invalid choice , try again\n"); continue; } } if(g_rds_thread_running) g_rds_thread_terminate = 1; // Terminate RDS thread close(g_radio_fd); return 0; }