diff options
-rw-r--r-- | binding/CMakeLists.txt | 1 | ||||
-rw-r--r-- | binding/radio-binding.c | 8 | ||||
-rw-r--r-- | binding/radio_impl_null.c | 267 | ||||
-rw-r--r-- | binding/radio_impl_null.h | 25 | ||||
-rw-r--r-- | binding/radio_impl_tef665x.c | 20 | ||||
-rw-r--r-- | conf.d/wgt/config.xml.in | 1 |
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> |