summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier S. Pedro <javier@javispedro.com>2012-02-13 20:16:32 +0100
committerJavier S. Pedro <javier@javispedro.com>2012-02-13 20:16:32 +0100
commit3fbc3f186f8f7817be2ecbdcc7117bd294bb7d88 (patch)
tree1c3c04a076c449735e350b196bd21dd0555d6887
parent178fa8e6707c9983ba02bb1d01f773c63b00732d (diff)
downloadfmrxd-3fbc3f186f8f7817be2ecbdcc7117bd294bb7d88.tar.gz
fmrxd-3fbc3f186f8f7817be2ecbdcc7117bd294bb7d88.zip
add signal monitoring support
-rw-r--r--Makefile2
-rw-r--r--debian/changelog6
-rw-r--r--fmrxd.h38
-rw-r--r--radio.c23
-rw-r--r--server.c12
-rw-r--r--signal.c73
-rw-r--r--tuner.c34
7 files changed, 162 insertions, 26 deletions
diff --git a/Makefile b/Makefile
index 07cc811..be5a1e4 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ FMRXUTILS_LIBS:=$(shell pkg-config --libs $(FMRXUTILS_PKGS))
all: fmrxd fmrx-cat fmrx-ctl
-fmrxd: fmrxd.o server.o radio.o bt.o capture.o tuner.o rds.o
+fmrxd: fmrxd.o server.o radio.o bt.o capture.o tuner.o rds.o signal.o
$(CC) $(FMRXD_LDFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(FMRXD_LIBS)
fmrx-cat: fmrx-cat.o
diff --git a/debian/changelog b/debian/changelog
index f307b8a..5841332 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+fmrxd (0.2) unstable; urgency=low
+
+ * Add signal level monitoring.
+
+ -- Javier S. Pedro <maemo@javispedro.com> Mon, 13 Feb 2012 20:15:30 +0100
+
fmrxd (0.1) unstable; urgency=low
* Initial Release.
diff --git a/fmrxd.h b/fmrxd.h
index 5f95d6a..9473510 100644
--- a/fmrxd.h
+++ b/fmrxd.h
@@ -6,32 +6,49 @@
#include <stdbool.h>
#include <glib.h>
+/** The D-Bus name of this server. */
#define BUS_NAME "com.javispedro.fmrxd"
#define BUS_PATH "/com/javispedro/fmrxd"
#define BUS_INTERFACE BUS_NAME
+/** Whether the server will shutdown when there are no more clients. */
#define SERVER_ON_DEMAND 1
+/** Seconds the server will wait before shutting down after last client exits. */
#define SERVER_LINGER_TIME 10
+/** Seconds the server will keep the radio device powered on after the last
+ client exits. Should be smaller than SERVER_LINGER_TIME. */
#define RADIO_LINGER_TIME 2
+/** The BlueZ device ID to power up and configure. */
#define BT_DEV_ID 0
+/** The ALSA mixer node to configure. */
#define ALSA_MIXER_NAME "hw:2"
+/** The ALSA device from where to read radio audio data. */
#define ALSA_PCM_CAPTURE_NAME "hw:2,0"
+/** The audio rate to use. */
#define ALSA_CAPTURE_RATE 48000
+/** The size of the global ring buffer size that prevents overruns. */
#define RING_BUFFER_SIZE (ALSA_CAPTURE_RATE)
+/** Tuner device to use. */
#define TUNER_DEVICE "/dev/radio0"
#define TUNER_DEVICE_ID 0
+/** Enable the wl1273 N950/N9 RDS decoding workarounds. */
#define CRAPPY_WL1273_RDS 1
-/* fmrxd.c */
+/** Poll the signal level every this many seconds. */
+#define SIGNAL_POLL_INTERVAL 10
+/** After tuning, refresh the signal level once after this many miliseconds. */
+#define SIGNAL_REFRESH_DELAY 200
+
+/* fmrxd.c -- the main loop */
extern GMainLoop* main_loop;
-/* server.c */
+/* server.c -- the d-bus server, audio server and client logic */
int server_start();
void server_stop();
void server_queue_stop();
@@ -40,38 +57,43 @@ size_t server_get_buffer(size_t size, void **buffer);
void server_commit_buffer(size_t size);
void server_notify_tuned(double mhz);
void server_notify_stopped();
+void server_notify_signal(uint16_t signal);
void server_notify_pi(uint16_t pi);
void server_notify_ps(const char *ps);
void server_notify_rt(const char *rt);
-/* radio.c */
+/* radio.c -- enabling and disabling radio logic */
bool radio_active();
void radio_start();
void radio_stop();
void radio_queue_start();
void radio_queue_stop();
-/* bt.c */
+/* bt.c -- configuring the wl1273 multiplexer via HCI */
bool configure_bt_muxer(bool on);
-/* capture.c */
+/* capture.c -- configure the ALSA mixer and capture */
bool configure_mixer(bool on);
bool configure_capture(bool on);
-/* tuner.c */
+/* tuner.c -- setting up the V4L tuner */
bool configure_tuner(bool on);
extern int tuner_fd;
bool tuner_set_frequency(double mhz);
+uint16_t tuner_get_signal();
bool tuner_search(bool forward);
-/* rds.c */
+/* rds.c -- RDS decoder */
bool configure_rds(bool on);
void rds_reset();
-
unsigned short rds_get_pi();
unsigned char rds_get_pty();
const char * rds_get_pty_text();
gchar * rds_get_ps();
gchar * rds_get_rt();
+/* signal.c -- polling signal level */
+bool configure_signal(bool on);
+void signal_reset();
+
#endif // FMRXD_H
diff --git a/radio.c b/radio.c
index 7b53fba..07c6ff8 100644
--- a/radio.c
+++ b/radio.c
@@ -34,13 +34,33 @@ void radio_start()
g_return_if_fail(!active);
g_debug("Starting radio");
- configure_bt_muxer(true);
+ bool ok;
+
+ ok = configure_bt_muxer(true);
+ if (!ok) goto fail_start;
+
configure_mixer(true);
+ if (!ok) goto fail_start;
+
configure_tuner(true);
+ if (!ok) goto fail_start;
+
configure_capture(true);
+ if (!ok) goto fail_start;
+
+ // Not essential.
+ configure_signal(true);
configure_rds(true);
active = true;
+ return; // Success
+
+fail_start:
+ g_critical("Radio failed to start!");
+
+ // Try to force a stop
+ active = true;
+ radio_stop();
}
void radio_stop()
@@ -49,6 +69,7 @@ void radio_stop()
g_debug("Stopping radio");
configure_rds(false);
+ configure_signal(false);
configure_capture(false);
configure_tuner(false);
configure_mixer(false);
diff --git a/server.c b/server.c
index cfee65a..7b2cb53 100644
--- a/server.c
+++ b/server.c
@@ -72,6 +72,9 @@ static const char * introspect_data = {
" </signal>\n"
" <signal name=\"Stopped\">\n"
" </signal>\n"
+ " <signal name=\"SignalLevelChanged\">\n"
+ " <arg type=\"q\" name=\"signal\" />\n"
+ " </signal>\n"
" <signal name=\"PiReceived\">\n"
" <arg type=\"q\" name=\"pi\" />\n"
" </signal>\n"
@@ -514,6 +517,15 @@ void server_notify_stopped()
dbus_message_unref(m);
}
+void server_notify_signal(uint16_t signal)
+{
+ DBusMessage *m = dbus_message_new_signal(BUS_PATH, BUS_INTERFACE, "SignalLevelChanged");
+ g_return_if_fail(m != NULL);
+ dbus_message_append_args(m, DBUS_TYPE_UINT16, &signal, DBUS_TYPE_INVALID);
+ dbus_connection_send(bus, m, NULL);
+ dbus_message_unref(m);
+}
+
void server_notify_pi(uint16_t pi)
{
DBusMessage *m = dbus_message_new_signal(BUS_PATH, BUS_INTERFACE, "PiChanged");
diff --git a/signal.c b/signal.c
new file mode 100644
index 0000000..3618e34
--- /dev/null
+++ b/signal.c
@@ -0,0 +1,73 @@
+/*
+ * fmrxd - a daemon to enable and multiplex access to the N950/N9 radio tuner
+ * Copyright (C) 2011 Javier S. Pedro <maemo@javispedro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "fmrxd.h"
+
+#include <glib.h>
+#include <linux/videodev2.h>
+
+static guint signal_timer_id = 0;
+static uint16_t last_signal_level = 0;
+
+static void signal_update()
+{
+ uint16_t new_signal_level = tuner_get_signal();
+ if (new_signal_level != last_signal_level) {
+ server_notify_signal(new_signal_level);
+ last_signal_level = new_signal_level;
+ }
+}
+
+static gboolean signal_poll(gpointer user_data)
+{
+ if (!signal_timer_id) return FALSE;
+ signal_update();
+ return TRUE;
+}
+
+static gboolean signal_refresh(gpointer user_data)
+{
+ if (!signal_timer_id) return FALSE;
+ signal_update();
+ return FALSE;
+}
+
+bool configure_signal(bool on)
+{
+ if (on) {
+ if (!signal_timer_id) {
+ signal_timer_id = g_timeout_add_seconds(SIGNAL_POLL_INTERVAL, signal_poll, NULL);
+ }
+ } else {
+ if (signal_timer_id) {
+ g_source_remove(signal_timer_id);
+ signal_timer_id = 0;
+ }
+ }
+
+ return true;
+}
+
+void signal_reset()
+{
+ last_signal_level = 0;
+ if (signal_timer_id) {
+ g_timeout_add(SIGNAL_REFRESH_DELAY, signal_refresh, NULL);
+ }
+}
diff --git a/tuner.c b/tuner.c
index 3d8e1ff..0f7b3f7 100644
--- a/tuner.c
+++ b/tuner.c
@@ -104,22 +104,6 @@ static unsigned long tuner_get_tuned_freq()
return v4l_to_hz(t_freq.frequency);
}
-static uint16_t tuner_get_signal()
-{
- struct v4l2_tuner t_tuner = {
- .index = TUNER_DEVICE_ID
- };
-
- g_return_val_if_fail(tuner_is_open(), 0);
-
- if (ioctl(tuner_fd, VIDIOC_G_TUNER, &t_tuner) < 0) {
- g_warning("Failed to get signal level: %s", strerror(errno));
- return 0;
- }
-
- return t_tuner.signal;
-}
-
bool configure_tuner(bool on)
{
if (on) {
@@ -182,6 +166,7 @@ bool tuner_set_frequency(double mhz)
g_message("Tuned to %.1f Mhz", mhz);
server_notify_tuned(mhz);
tuner_freq = hz;
+ signal_reset();
rds_reset();
return true;
}
@@ -189,6 +174,22 @@ bool tuner_set_frequency(double mhz)
return false;
}
+uint16_t tuner_get_signal()
+{
+ struct v4l2_tuner t_tuner = {
+ .index = TUNER_DEVICE_ID
+ };
+
+ g_return_val_if_fail(tuner_is_open(), 0);
+
+ if (ioctl(tuner_fd, VIDIOC_G_TUNER, &t_tuner) < 0) {
+ g_warning("Failed to get signal level: %s", strerror(errno));
+ return 0;
+ }
+
+ return t_tuner.signal;
+}
+
bool tuner_search(bool forward)
{
struct v4l2_hw_freq_seek t_freq_seek = {
@@ -213,6 +214,7 @@ bool tuner_search(bool forward)
// Got new frequency, fire signals.
tuner_freq = hz;
server_notify_tuned(hz_to_mhz(hz));
+ signal_reset();
rds_reset();
return true;
}