Add radio tuning test app master
authorNils Faerber <nils.faerber@kernelconcepts.de>
Wed, 23 Mar 2011 15:57:07 +0000 (16:57 +0100)
committerNils Faerber <nils.faerber@kernelconcepts.de>
Wed, 23 Mar 2011 15:57:07 +0000 (16:57 +0100)
12 files changed:
decoder/rds.c
decoder/rds.h
tuning/Makefile [new file with mode: 0644]
tuning/bitstream.c [new symlink]
tuning/bitstream.h [new symlink]
tuning/rds.c [new symlink]
tuning/rds.h [new symlink]
tuning/rds_consts.h [new symlink]
tuning/tmc.c [new symlink]
tuning/tmc.h [new symlink]
tuning/tmc_consts.h [new symlink]
tuning/tuning.c [new file with mode: 0644]

index bdaee7b..ca927b2 100644 (file)
@@ -138,10 +138,18 @@ enum RDSGroupType { GROUP_0A=0, GROUP_0B, GROUP_1A, GROUP_1B, GROUP_2A, GROUP_2B
                     GROUP_12A, GROUP_12B, GROUP_13A, GROUP_13B, GROUP_14A, GROUP_14B, 
                     GROUP_15A, GROUP_15B, GROUP_UNKNOWN };
 
+void rds_radio_retuned(void)
+{
+       memset(&rds_info, 0, sizeof(rds_info));
+       rds_info.LTN = -1;
+       memset(&rds_time, 0, sizeof(rds_time));
+}
+
 void rds_decode_group(unsigned short *rdsgroup)
 {
 static unsigned short ogrp[4];
 static unsigned char grp_decoded = 0;
+static unsigned char sname_rcvd = 0;
 unsigned char grp_type = (rdsgroup[1] >> 11);
 unsigned char offs;
 static unsigned char otextAB = 0, newtext = 0;
@@ -172,6 +180,7 @@ int year_, mon_, K;
                rds_info.ccode = (PI & 0xf000) >> 12;
                rds_info.ptype = (PI & 0x0f00) >> 8;
                rds_info.pref = (PI & 0x00ff);
+               sname_rcvd = 0;
                if (rds_info.pref == 0) /* something is wrong here */
                        return;
                rds_info.PI = rdsgroup[0];
@@ -187,10 +196,20 @@ int year_, mon_, K;
                        float AF1=0, AF2=0;
 
                        offs = (rdsgroup[1] & 0x03);
+                       if (offs == 0)
+                               sname_rcvd = 0;
+                       if (offs == 1 && sname_rcvd == 0)
+                               sname_rcvd = 1;
+                       if (offs == 2 && sname_rcvd == 1)
+                               sname_rcvd = 2;
+                       if (offs == 3 && sname_rcvd == 2)
+                               sname_rcvd = 3;
                        rds_info.sname[offs*2] = ((rdsgroup[3] & 0xff00) >> 8);
                        rds_info.sname[(offs*2)+1] = rdsgroup[3] & 0x00ff;
-                       if (_rds_private.rds_sname_cb != NULL)
+                       if (_rds_private.rds_sname_cb != NULL && sname_rcvd == 3) {
                                _rds_private.rds_sname_cb(rds_info.sname, _rds_private.rds_sname_cb_data);
+                               sname_rcvd = 0;
+                       }
 
                        rds_info.TA = (rdsgroup[1] & 0x10) >> 4;
                        rds_info.TP = (rdsgroup[1] & 0x400) >> 10;
index 862a933..e2187f1 100644 (file)
@@ -56,6 +56,7 @@ struct rds_info_s {
 };
 
 int rds_receive_group(int rds_fd, unsigned short *rdsgroup);
+void rds_radio_retuned(void);
 void rds_decode_group(unsigned short *rdsgroup);
 
 void rds_init(void);
diff --git a/tuning/Makefile b/tuning/Makefile
new file mode 100644 (file)
index 0000000..d018b3a
--- /dev/null
@@ -0,0 +1,43 @@
+CC = gcc
+
+# prefix for installation and search path (like icons)
+PREFIX = /usr/local/
+
+# for normal desktop GTK+
+CCFLAGS = -Wall -O2 -g
+
+SQLITECFLAGS = `pkg-config --cflags sqlite3`
+GTKCFLAGS = `pkg-config --cflags gtk+-2.0`
+
+CFLAGS = $(CCFLAGS) $(SQLITECFLAGS) $(GTKCFLAGS)
+
+SQLITELDFLAGS = `pkg-config --libs sqlite3`
+GTKLDFLAGS = `pkg-config --libs gtk+-2.0`
+
+# no need to change anything below this line
+# ------------------------------------------
+
+.SUFFIXES: .d .c
+
+CFLAGS += -MD -DPREFIX=\"$(PREFIX)\" $(OPTIONS)
+LDFLAGS = $(CLDFLAGS) $(SQLITELDFLAGS)
+
+RDS_MEMBERS = rds bitstream tmc tuning
+SOURCES = $(patsubst %,%.c,$(RDS_MEMBERS))
+OBJS = $(patsubst %,%.o,$(RDS_MEMBERS))
+DEPS = $(patsubst %,%.d,$(RDS_MEMBERS))
+
+UR_MEMBERS = rds bitstream tmc tuning
+UR_SOURCES = $(patsubst %,%.c,$(UR_MEMBERS))
+UR_OBJS = $(patsubst %,%.o,$(UR_MEMBERS))
+UR_DEPS = $(patsubst %,%.d,$(UR_MEMBERS))
+
+all: tuning
+
+tuning: $(OBJS)
+       $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+       rm -f *.o *.d tuning
+
+-include $(DEPS)
diff --git a/tuning/bitstream.c b/tuning/bitstream.c
new file mode 120000 (symlink)
index 0000000..bfaadd7
--- /dev/null
@@ -0,0 +1 @@
+../rdstmc-git/decoder/bitstream.c
\ No newline at end of file
diff --git a/tuning/bitstream.h b/tuning/bitstream.h
new file mode 120000 (symlink)
index 0000000..1940845
--- /dev/null
@@ -0,0 +1 @@
+../rdstmc-git/decoder/bitstream.h
\ No newline at end of file
diff --git a/tuning/rds.c b/tuning/rds.c
new file mode 120000 (symlink)
index 0000000..396184c
--- /dev/null
@@ -0,0 +1 @@
+../rdstmc-git/decoder/rds.c
\ No newline at end of file
diff --git a/tuning/rds.h b/tuning/rds.h
new file mode 120000 (symlink)
index 0000000..e7ce123
--- /dev/null
@@ -0,0 +1 @@
+../rdstmc-git/decoder/rds.h
\ No newline at end of file
diff --git a/tuning/rds_consts.h b/tuning/rds_consts.h
new file mode 120000 (symlink)
index 0000000..40a669e
--- /dev/null
@@ -0,0 +1 @@
+../rdstmc-git/decoder/rds_consts.h
\ No newline at end of file
diff --git a/tuning/tmc.c b/tuning/tmc.c
new file mode 120000 (symlink)
index 0000000..c4cd55d
--- /dev/null
@@ -0,0 +1 @@
+../rdstmc-git/decoder/tmc.c
\ No newline at end of file
diff --git a/tuning/tmc.h b/tuning/tmc.h
new file mode 120000 (symlink)
index 0000000..32d7490
--- /dev/null
@@ -0,0 +1 @@
+../rdstmc-git/decoder/tmc.h
\ No newline at end of file
diff --git a/tuning/tmc_consts.h b/tuning/tmc_consts.h
new file mode 120000 (symlink)
index 0000000..75e1a20
--- /dev/null
@@ -0,0 +1 @@
+../rdstmc-git/decoder/tmc_consts.h
\ No newline at end of file
diff --git a/tuning/tuning.c b/tuning/tuning.c
new file mode 100644 (file)
index 0000000..a4610dc
--- /dev/null
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+
+#include <linux/videodev2.h>
+
+#include <sqlite3.h>
+
+#include "rds.h"
+#include "tmc.h"
+
+sqlite3 *lcl_db;
+int OutputFlags;
+
+unsigned char pi_received = 0;
+unsigned char sid_received = 0;
+
+void test_rds_PI_cb(unsigned short PI, unsigned char ccode, unsigned char ptype, unsigned char pref, void *udata)
+{
+       printf("New PI=%d ccode=%X ptype=%X '%s' '%s' pref=%d\n", PI, ccode, ptype, ptype_stext[ptype], ptype_ltext[ptype], pref);
+       pi_received = 1;
+}
+
+void test_rds_sname_cb(char *sname, void *udata)
+{
+       printf("RDS sname='%s'\n", sname);
+       sid_received = 1;
+}
+
+
+void station_scan(int fd)
+{
+int ret;
+struct v4l2_frequency v4lfreq;
+struct v4l2_tuner v4ltuner;
+unsigned short rdsgroup[4];
+
+       v4ltuner.index = 0;
+       ret = ioctl(fd, VIDIOC_G_TUNER, &v4ltuner);
+       if (ret < 0)
+               return;
+       printf("tuner=%d\n", v4ltuner.index);
+       if (v4ltuner.type == V4L2_TUNER_RADIO)
+               printf("  is a radio tuner\n");
+       printf("name='%s'\n", v4ltuner.name);
+
+       v4lfreq.tuner = v4ltuner.index;
+       memset(&v4lfreq.reserved, 0, 32);
+       ret = ioctl(fd, VIDIOC_G_FREQUENCY, &v4lfreq);
+       if (ret < 0)
+               return;
+
+       v4lfreq.frequency = v4ltuner.rangelow;
+       while (v4lfreq.frequency <= v4ltuner.rangehigh) {
+                       ret = ioctl(fd, VIDIOC_S_FREQUENCY, &v4lfreq);
+                       if (ret < 0)
+                               break;
+                       ret = ioctl(fd, VIDIOC_G_FREQUENCY, &v4lfreq);
+                       if (ret < 0)
+                               break;
+                               ret = ioctl(fd, VIDIOC_G_TUNER, &v4ltuner);
+                       if (ret < 0)
+                               break;
+                       printf("%lf %d %d %s %s\n", (double)v4lfreq.frequency * 62.5 / 1000000,
+                               v4lfreq.frequency,
+                               v4ltuner.signal,
+                               v4ltuner.rxsubchans & V4L2_TUNER_SUB_STEREO ? "stereo" : "mono",
+                               v4ltuner.rxsubchans & V4L2_TUNER_SUB_RDS ? "RDS" : "noRDS");
+
+                       if (v4ltuner.signal > 30000) {
+                               /* seems to be a strong signal, so try RDS */
+                               pi_received = 0;
+                               sid_received = 0;
+                               rds_radio_retuned();
+                               while (pi_received == 0 || sid_received == 0) {
+                                       if (rds_receive_group(fd, rdsgroup)) {
+                                               /* group complete, start decode */
+                                               rds_decode_group(rdsgroup);
+                   }
+                }
+                       }
+
+                       v4lfreq.frequency += 1600; /* 1600 for .1MHz steps, 800 for 0.05MHz */
+       }
+}
+
+
+int main(int argc, char **argv)
+{
+int fd, ret;
+struct v4l2_capability v4lcap;
+struct v4l2_frequency v4lfreq;
+struct v4l2_tuner v4ltuner;
+
+       fd = open ("/dev/radio0", O_RDONLY);
+       if (fd < 0) {
+               printf("error opening fd\n");
+               perror("open");
+               return 1;
+       }
+
+       ret = ioctl(fd, VIDIOC_QUERYCAP, &v4lcap);
+       if (ret < 0)
+               return 1;
+
+       printf("driver = '%s'\n", v4lcap.driver);
+       printf("card = '%s'\n", v4lcap.card);
+       printf("bus_info = '%s'\n", v4lcap.bus_info);
+       printf("cap && RADIO = %s\n", (v4lcap.capabilities & V4L2_CAP_RADIO) ? "yes" : "no");
+       printf("cap && TUNER = %s\n", (v4lcap.capabilities & V4L2_CAP_TUNER) ? "yes" : "no");
+       printf("cap && RDS = %s\n", (v4lcap.capabilities & V4L2_CAP_RDS_CAPTURE) ? "yes" : "no");
+
+       v4ltuner.index = 0;
+       ret = ioctl(fd, VIDIOC_G_TUNER, &v4ltuner);
+       if (ret < 0)
+               return 1;
+       printf("tuner=%d\n", v4ltuner.index);
+       if (v4ltuner.type == V4L2_TUNER_RADIO)
+               printf("  is a radio tuner\n");
+       printf("name='%s'\n", v4ltuner.name);
+
+       v4lfreq.tuner = v4ltuner.index;
+       memset(&v4lfreq.reserved, 0, 32);
+       ret = ioctl(fd, VIDIOC_G_FREQUENCY, &v4lfreq);
+
+       if (ret >= 0) {
+               if (v4ltuner.capability & V4L2_TUNER_CAP_LOW) {
+                       printf("range %3.2lf MHz - %3.2lf MHz\n", (double)v4ltuner.rangelow * 62.5 / 1000000, (double)v4ltuner.rangehigh * 62.5 / 1000000);
+                       printf("freq = %3.2lf MHz\n", (double)v4lfreq.frequency * 62.5 / 1000000);
+               } else
+                       printf("freq = %lf kHz\n", (double)v4lfreq.frequency * 62.5);
+       }
+       printf("signal: %d %s\n", v4ltuner.signal, v4ltuner.rxsubchans & V4L2_TUNER_SUB_STEREO ? "stereo" : "mono");
+       printf("RDS signal present: %s\n", v4ltuner.rxsubchans & V4L2_TUNER_SUB_RDS ? "yes" : "no");
+
+       if (argc > 1 && strcmp(argv[1], "-s")==0) {
+               rds_init();
+        tmc_init();
+        rds_set_sname_cb(test_rds_sname_cb, NULL);
+        rds_set_PI_cb(test_rds_PI_cb, NULL);
+               station_scan(fd);
+       }
+
+       close(fd);
+
+return 0;
+}