From 3fbc3f186f8f7817be2ecbdcc7117bd294bb7d88 Mon Sep 17 00:00:00 2001 From: "Javier S. Pedro" Date: Mon, 13 Feb 2012 20:16:32 +0100 Subject: add signal monitoring support --- Makefile | 2 +- debian/changelog | 6 +++++ fmrxd.h | 38 ++++++++++++++++++++++------- radio.c | 23 +++++++++++++++++- server.c | 12 ++++++++++ signal.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tuner.c | 34 +++++++++++++------------- 7 files changed, 162 insertions(+), 26 deletions(-) create mode 100644 signal.c 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 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 #include +/** 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 = { " \n" " \n" " \n" + " \n" + " \n" + " \n" " \n" " \n" " \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 + * + * 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 +#include + +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; } -- cgit v1.2.3