summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--binding/CMakeLists.txt1
-rw-r--r--binding/radio-binding.c8
-rw-r--r--binding/radio_impl_null.c267
-rw-r--r--binding/radio_impl_null.h25
-rw-r--r--binding/radio_impl_tef665x.c20
-rw-r--r--conf.d/wgt/config.xml.in1
6 files changed, 312 insertions, 10 deletions
diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt
index 712e165..560dcaf 100644
--- a/binding/CMakeLists.txt
+++ b/binding/CMakeLists.txt
@@ -27,6 +27,7 @@ PROJECT_TARGET_ADD(radio-binding)
set(radio_SOURCES
radio-binding.c
radio_impl_kingfisher.c
+ radio_impl_null.c
radio_impl_rtlsdr.c
radio_impl_tef665x.c)
diff --git a/binding/radio-binding.c b/binding/radio-binding.c
index 0ab5565..34eb53e 100644
--- a/binding/radio-binding.c
+++ b/binding/radio-binding.c
@@ -27,6 +27,7 @@
#include <afb/afb-binding.h>
#include "radio_impl.h"
+#include "radio_impl_null.h"
#include "radio_impl_rtlsdr.h"
#include "radio_impl_kingfisher.h"
#include "radio_impl_tef665x.h"
@@ -581,6 +582,11 @@ static int init(afb_api_t api)
rc = radio_impl_ops->init();
}
if (rc != 0) {
+ radio_impl_ops = &null_impl_ops;
+ rc = radio_impl_ops->init();
+ }
+ if (rc != 0) {
+ // We don't expect the null implementation to fail init, but just in case...
AFB_API_ERROR(afbBindingV3root, "No radio device found, exiting");
}
if(rc == 0) {
@@ -590,8 +596,6 @@ static int init(afb_api_t api)
{
radio_impl_ops->set_rds_callback(rds_callback);
}
-
-
} else {
return rc;
}
diff --git a/binding/radio_impl_null.c b/binding/radio_impl_null.c
new file mode 100644
index 0000000..8c28bca
--- /dev/null
+++ b/binding/radio_impl_null.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2017,2018,2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * NOTE: Some locking around frequency and scanning state may be
+ * required if this null implementation ever needs to be used
+ * beyond basic functionality testing.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <glib.h>
+#include <afb/afb-binding.h>
+
+#include "radio_impl.h"
+
+// Structure to describe FM band plans, all values in Hz.
+typedef struct {
+ char *name;
+ uint32_t min;
+ uint32_t max;
+ uint32_t step;
+} fm_band_plan_t;
+
+static fm_band_plan_t known_fm_band_plans[5] = {
+ { .name = "US", .min = 87900000, .max = 107900000, .step = 200000 },
+ { .name = "JP", .min = 76000000, .max = 95000000, .step = 100000 },
+ { .name = "EU", .min = 87500000, .max = 108000000, .step = 50000 },
+ { .name = "ITU-1", .min = 87500000, .max = 108000000, .step = 50000 },
+ { .name = "ITU-2", .min = 87900000, .max = 107900000, .step = 50000 }
+};
+
+static unsigned int bandplan;
+static bool present;
+static bool active;
+static bool scanning;
+static uint32_t current_frequency;
+static radio_freq_callback_t freq_callback;
+static void *freq_callback_data;
+
+static uint32_t null_get_min_frequency(radio_band_t band);
+static void null_set_frequency(uint32_t frequency);
+//static void null_scan_stop(void);
+
+static int null_init(void)
+{
+ GKeyFile *conf_file;
+ char *value_str;
+ char *rootdir;
+ char *helper_path;
+
+ if(present)
+ return 0;
+
+ // Load settings from configuration file if it exists
+ conf_file = g_key_file_new();
+ if(conf_file &&
+ g_key_file_load_from_dirs(conf_file,
+ "AGL.conf",
+ (const gchar**) g_get_system_config_dirs(),
+ NULL,
+ G_KEY_FILE_KEEP_COMMENTS,
+ NULL) == TRUE) {
+
+ // Set band plan if it is specified
+ value_str = g_key_file_get_string(conf_file,
+ "radio",
+ "fmbandplan",
+ NULL);
+ if(value_str) {
+ unsigned int i;
+ for(i = 0;
+ i < sizeof(known_fm_band_plans) / sizeof(fm_band_plan_t);
+ i++) {
+ if(!strcasecmp(value_str, known_fm_band_plans[i].name)) {
+ bandplan = i;
+ break;
+ }
+ }
+ }
+ }
+
+ // Start off with minimum bandplan frequency
+ current_frequency = null_get_min_frequency(BAND_FM);
+
+ present = true;
+ null_set_frequency(current_frequency);
+
+ return 0;
+}
+
+static void null_set_output(const char *output)
+{
+}
+
+static uint32_t null_get_frequency(void)
+{
+ return current_frequency;
+}
+
+static void null_set_frequency(uint32_t frequency)
+{
+ current_frequency = frequency;
+
+ if(freq_callback)
+ freq_callback(current_frequency, freq_callback_data);
+}
+
+static void null_set_frequency_callback(radio_freq_callback_t callback,
+ void *data)
+{
+ freq_callback = callback;
+ freq_callback_data = data;
+}
+
+static radio_band_t null_get_band(void)
+{
+ // We only support FM
+ return BAND_FM;
+}
+
+static void null_set_band(radio_band_t band)
+{
+ // We only support FM, so do nothing
+}
+
+static int null_band_supported(radio_band_t band)
+{
+ if(band == BAND_FM)
+ return 1;
+ return 0;
+}
+
+static uint32_t null_get_min_frequency(radio_band_t band)
+{
+ return known_fm_band_plans[bandplan].min;
+}
+
+static uint32_t null_get_max_frequency(radio_band_t band)
+{
+ return known_fm_band_plans[bandplan].max;
+}
+
+static uint32_t null_get_frequency_step(radio_band_t band)
+{
+ uint32_t ret = 0;
+
+ switch (band) {
+ case BAND_AM:
+ ret = 1000; // 1 kHz
+ break;
+ case BAND_FM:
+ ret = known_fm_band_plans[bandplan].step;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static void null_start(void)
+{
+ if(!present)
+ return;
+
+ if(active)
+ return;
+
+ active = true;
+}
+
+static void null_stop(void)
+{
+ if(!present)
+ return;
+
+ if (!active)
+ return;
+
+ active = false;
+}
+
+static void null_scan_start(radio_scan_direction_t direction,
+ radio_scan_callback_t callback,
+ void *data)
+{
+ int frequency;
+
+ if(!active || scanning)
+ return;
+
+ scanning = true;
+
+ // Just go to the next frequency step up or down
+ frequency = current_frequency;
+ if(direction == SCAN_FORWARD) {
+ frequency += known_fm_band_plans[bandplan].step;
+ } else {
+ frequency -= known_fm_band_plans[bandplan].step;
+ }
+ if(frequency < known_fm_band_plans[bandplan].min)
+ frequency = known_fm_band_plans[bandplan].max;
+ else if(frequency > known_fm_band_plans[bandplan].max)
+ frequency = known_fm_band_plans[bandplan].min;
+
+ scanning = false;
+ null_set_frequency(frequency);
+ if(callback)
+ callback(frequency, data);
+}
+
+static void null_scan_stop(void)
+{
+ scanning = false;
+}
+
+static radio_stereo_mode_t null_get_stereo_mode(void)
+{
+ // We only support stereo
+ return STEREO;
+}
+
+static void null_set_stereo_mode(radio_stereo_mode_t mode)
+{
+ // We only support stereo, so do nothing
+}
+
+radio_impl_ops_t null_impl_ops = {
+ .name = "null/mock radio",
+ .init = null_init,
+ .set_output = null_set_output,
+ .get_frequency = null_get_frequency,
+ .set_frequency = null_set_frequency,
+ .set_frequency_callback = null_set_frequency_callback,
+ .get_band = null_get_band,
+ .set_band = null_set_band,
+ .band_supported = null_band_supported,
+ .get_min_frequency = null_get_min_frequency,
+ .get_max_frequency = null_get_max_frequency,
+ .get_frequency_step = null_get_frequency_step,
+ .start = null_start,
+ .stop = null_stop,
+ .scan_start = null_scan_start,
+ .scan_stop = null_scan_stop,
+ .get_stereo_mode = null_get_stereo_mode,
+ .set_stereo_mode = null_set_stereo_mode
+};
diff --git a/binding/radio_impl_null.h b/binding/radio_impl_null.h
new file mode 100644
index 0000000..16bd5e6
--- /dev/null
+++ b/binding/radio_impl_null.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _RADIO_IMPL_NULL_H
+#define _RADIO_IMPL_NULL_H
+
+#include "radio_impl.h"
+
+extern radio_impl_ops_t null_impl_ops;
+
+#endif /* _RADIO_IMPL_NULL_H */
+
diff --git a/binding/radio_impl_tef665x.c b/binding/radio_impl_tef665x.c
index eeac170..17454b8 100644
--- a/binding/radio_impl_tef665x.c
+++ b/binding/radio_impl_tef665x.c
@@ -2144,15 +2144,19 @@ static int tef665x_init()
{
char gst_pipeline_str[GST_PIPELINE_LEN];
int rc;
- int ret = i2c_init(I2C_DEV, _open, &file_desc);
current_am_frequency = known_am_band_plans[am_bandplan].min;
current_fm_frequency = known_fm_band_plans[fm_bandplan].min;
+ rc = i2c_init(I2C_DEV, _open, &file_desc);
+ if(rc < 0) {
+ AFB_NOTICE("tef665x not present");
+ return -1;
+ }
_debug("file_desc= ", file_desc);
- ret = appl_get_identification(file_desc);
- if(ret != 1){
+ rc = appl_get_identification(file_desc);
+ if(rc != 1){
AFB_ERROR("no tef665x!");
return -1;
}
@@ -2187,11 +2191,11 @@ static int tef665x_init()
}
// Start pipeline in paused state
- ret = gst_element_set_state(pipeline, GST_STATE_PAUSED);
- _debug("gst_element_set_state to pause (at the begining)", ret);
+ rc = gst_element_set_state(pipeline, GST_STATE_PAUSED);
+ _debug("gst_element_set_state to pause (at the begining)", rc);
- ret = gst_bus_add_watch(gst_element_get_bus(pipeline), (GstBusFunc) handle_message, NULL);
- _debug("gst_bus_add_watch ret", ret);
+ rc = gst_bus_add_watch(gst_element_get_bus(pipeline), (GstBusFunc) handle_message, NULL);
+ _debug("gst_bus_add_watch rc", rc);
present = true;
@@ -2200,7 +2204,7 @@ static int tef665x_init()
pthread_mutex_init (&RDS_Mutex, NULL);
tef665x_start();
- return 0;
+ return 0;
}
static void tef665x_set_frequency_callback(radio_freq_callback_t callback,
diff --git a/conf.d/wgt/config.xml.in b/conf.d/wgt/config.xml.in
index c98dce2..ecd47a9 100644
--- a/conf.d/wgt/config.xml.in
+++ b/conf.d/wgt/config.xml.in
@@ -10,6 +10,7 @@
<feature name="urn:AGL:widget:required-permission">
<param name="urn:AGL:permission::public:hidden" value="required" />
<param name="urn:AGL:permission::public:no-htdocs" value="required" />
+ <param name="urn:AGL:permission::system:run-by-default" value="required" />
<param name="urn:AGL:permission::public:audio" value="required" />
</feature>