summaryrefslogtreecommitdiffstats
path: root/binding/radio-binding.c
diff options
context:
space:
mode:
Diffstat (limited to 'binding/radio-binding.c')
-rw-r--r--binding/radio-binding.c222
1 files changed, 161 insertions, 61 deletions
diff --git a/binding/radio-binding.c b/binding/radio-binding.c
index 847e822..34eb53e 100644
--- a/binding/radio-binding.c
+++ b/binding/radio-binding.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 Konsulko Group
+ * Copyright (C) 2017, 2019 Konsulko Group
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,18 +24,29 @@
#include <unistd.h>
#include <sys/types.h>
#include <json-c/json.h>
-
#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"
static radio_impl_ops_t *radio_impl_ops;
-static struct afb_event freq_event;
-static struct afb_event scan_event;
-static struct afb_event status_event;
+static afb_event_t freq_event;
+static afb_event_t scan_event;
+static afb_event_t status_event;
+static afb_event_t rds_event;
+
+static bool playing;
+
+static const char *signalcomposer_events[] = {
+ "event.media.next",
+ "event.media.previous",
+ "event.media.mode",
+ NULL,
+};
static void freq_callback(uint32_t frequency, void *data)
{
@@ -55,6 +66,12 @@ static void scan_callback(uint32_t frequency, void *data)
afb_event_push(scan_event, json_object_get(jresp));
}
+static void rds_callback(void *rds_data)
+{
+ //rds_data is a json object
+ afb_event_push(rds_event, json_object_get(rds_data));
+}
+
/*
* Binding verb handlers
*/
@@ -62,10 +79,10 @@ static void scan_callback(uint32_t frequency, void *data)
/*
* @brief Get (and optionally set) frequency
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void frequency(struct afb_req request)
+static void frequency(afb_req_t request)
{
json_object *ret_json;
const char *value = afb_req_value(request, "value");
@@ -77,28 +94,28 @@ static void frequency(struct afb_req request)
if(frequency && *p == '\0') {
radio_impl_ops->set_frequency(frequency);
} else {
- afb_req_fail(request, "failed", "Invalid scan direction");
+ afb_req_reply(request, NULL, "failed", "Invalid scan direction");
return;
}
}
ret_json = json_object_new_object();
frequency = radio_impl_ops->get_frequency();
json_object_object_add(ret_json, "frequency", json_object_new_int((int32_t) frequency));
- afb_req_success(request, ret_json, NULL);
+ afb_req_reply(request, ret_json, NULL, NULL);
}
/* @brief Get RDS information
*
-* @param struct afb_req : an afb request structure
+* @param afb_req_t : an afb request structure
*
*/
-static void rds(struct afb_req request)
+static void rds(afb_req_t request)
{
json_object *ret_json;
char * rds;
if (radio_impl_ops->get_rds_info == NULL) {
- afb_req_fail(request, "failed", "not supported");
+ afb_req_reply(request, NULL, "failed", "not supported");
return;
}
@@ -107,16 +124,16 @@ static void rds(struct afb_req request)
json_object_object_add(ret_json, "rds", json_object_new_string(rds?rds:""));
free(rds);
- afb_req_success(request, ret_json, NULL);
+ afb_req_reply(request, ret_json, NULL, NULL);
}
/*
* @brief Get (and optionally set) frequency band
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void band(struct afb_req request)
+static void band(afb_req_t request)
{
json_object *ret_json;
const char *value = afb_req_value(request, "value");
@@ -148,7 +165,7 @@ static void band(struct afb_req request)
if(valid) {
radio_impl_ops->set_band(band);
} else {
- afb_req_fail(request, "failed", "Invalid band");
+ afb_req_reply(request, NULL, "failed", "Invalid band");
return;
}
}
@@ -156,16 +173,16 @@ static void band(struct afb_req request)
band = radio_impl_ops->get_band();
sprintf(band_name, "%s", band == BAND_AM ? "AM" : "FM");
json_object_object_add(ret_json, "band", json_object_new_string(band_name));
- afb_req_success(request, ret_json, NULL);
+ afb_req_reply(request, ret_json, NULL, NULL);
}
/*
* @brief Check if band is supported
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void band_supported(struct afb_req request)
+static void band_supported(afb_req_t request)
{
json_object *ret_json;
const char *value = afb_req_value(request, "band");
@@ -195,23 +212,23 @@ static void band_supported(struct afb_req request)
}
}
if(!valid) {
- afb_req_fail(request, "failed", "Invalid band");
+ afb_req_reply(request, NULL, "failed", "Invalid band");
return;
}
ret_json = json_object_new_object();
json_object_object_add(ret_json,
"supported",
json_object_new_int(radio_impl_ops->band_supported(band)));
- afb_req_success(request, ret_json, NULL);
+ afb_req_reply(request, ret_json, NULL, NULL);
}
/*
* @brief Get frequency range for a band
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void frequency_range(struct afb_req request)
+static void frequency_range(afb_req_t request)
{
json_object *ret_json;
const char *value = afb_req_value(request, "band");
@@ -243,7 +260,7 @@ static void frequency_range(struct afb_req request)
}
}
if(!valid) {
- afb_req_fail(request, "failed", "Invalid band");
+ afb_req_reply(request, NULL, "failed", "Invalid band");
return;
}
ret_json = json_object_new_object();
@@ -251,16 +268,16 @@ static void frequency_range(struct afb_req request)
max_frequency = radio_impl_ops->get_max_frequency(band);
json_object_object_add(ret_json, "min", json_object_new_int((int32_t) min_frequency));
json_object_object_add(ret_json, "max", json_object_new_int((int32_t) max_frequency));
- afb_req_success(request, ret_json, NULL);
+ afb_req_reply(request, ret_json, NULL, NULL);
}
/*
* @brief Get frequency step size (Hz) for a band
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void frequency_step(struct afb_req request)
+static void frequency_step(afb_req_t request)
{
json_object *ret_json;
const char *value = afb_req_value(request, "band");
@@ -291,26 +308,27 @@ static void frequency_step(struct afb_req request)
}
}
if(!valid) {
- afb_req_fail(request, "failed", "Invalid band");
+ afb_req_reply(request, NULL, "failed", "Invalid band");
return;
}
ret_json = json_object_new_object();
step = radio_impl_ops->get_frequency_step(band);
json_object_object_add(ret_json, "step", json_object_new_int((int32_t) step));
- afb_req_success(request, ret_json, NULL);
+ afb_req_reply(request, ret_json, NULL, NULL);
}
/*
* @brief Start radio playback
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void start(struct afb_req request)
+static void start(afb_req_t request)
{
radio_impl_ops->set_output(NULL);
radio_impl_ops->start();
- afb_req_success(request, NULL, NULL);
+ playing = true;
+ afb_req_reply(request, NULL, NULL, NULL);
json_object *jresp = json_object_new_object();
json_object *value = json_object_new_string("playing");
@@ -321,13 +339,14 @@ static void start(struct afb_req request)
/*
* @brief Stop radio playback
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void stop(struct afb_req request)
+static void stop(afb_req_t request)
{
radio_impl_ops->stop();
- afb_req_success(request, NULL, NULL);
+ playing = false;
+ afb_req_reply(request, NULL, NULL, NULL);
json_object *jresp = json_object_new_object();
json_object *value = json_object_new_string("stopped");
@@ -338,10 +357,10 @@ static void stop(struct afb_req request)
/*
* @brief Scan for a station in the specified direction
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void scan_start(struct afb_req request)
+static void scan_start(afb_req_t request)
{
const char *value = afb_req_value(request, "direction");
int valid = 0;
@@ -370,32 +389,32 @@ static void scan_start(struct afb_req request)
}
}
if(!valid) {
- afb_req_fail(request, "failed", "Invalid direction");
+ afb_req_reply(request, NULL, "failed", "Invalid direction");
return;
}
radio_impl_ops->scan_start(direction, scan_callback, NULL);
- afb_req_success(request, NULL, NULL);
+ afb_req_reply(request, NULL, NULL, NULL);
}
/*
* @brief Stop station scan
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void scan_stop(struct afb_req request)
+static void scan_stop(afb_req_t request)
{
radio_impl_ops->scan_stop();
- afb_req_success(request, NULL, NULL);
+ afb_req_reply(request, NULL, NULL, NULL);
}
/*
* @brief Get (and optionally set) stereo mode
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void stereo_mode(struct afb_req request)
+static void stereo_mode(afb_req_t request)
{
json_object *ret_json;
const char *value = afb_req_value(request, "value");
@@ -426,7 +445,7 @@ static void stereo_mode(struct afb_req request)
if(valid) {
radio_impl_ops->set_stereo_mode(mode);
} else {
- afb_req_fail(request, "failed", "Invalid mode");
+ afb_req_reply(request, NULL, "failed", "Invalid mode");
return;
}
}
@@ -434,16 +453,16 @@ static void stereo_mode(struct afb_req request)
mode = radio_impl_ops->get_stereo_mode();
json_object_object_add(ret_json, "mode", json_object_new_string(mode == MONO ? "mono" : "stereo"));
- afb_req_success(request, ret_json, NULL);
+ afb_req_reply(request, ret_json, NULL, NULL);
}
/*
* @brief Subscribe for an event
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void subscribe(struct afb_req request)
+static void subscribe(afb_req_t request)
{
const char *value = afb_req_value(request, "value");
if(value) {
@@ -453,21 +472,24 @@ static void subscribe(struct afb_req request)
afb_req_subscribe(request, scan_event);
} else if(!strcasecmp(value, "status")) {
afb_req_subscribe(request, status_event);
- } else {
- afb_req_fail(request, "failed", "Invalid event");
+ } else if(!strcasecmp(value, "rds")) {
+ afb_req_subscribe(request, rds_event);
+ }
+ else {
+ afb_req_reply(request, NULL, "failed", "Invalid event");
return;
}
}
- afb_req_success(request, NULL, NULL);
+ afb_req_reply(request, NULL, NULL, NULL);
}
/*
* @brief Unsubscribe for an event
*
- * @param struct afb_req : an afb request structure
+ * @param afb_req_t : an afb request structure
*
*/
-static void unsubscribe(struct afb_req request)
+static void unsubscribe(afb_req_t request)
{
const char *value = afb_req_value(request, "value");
if(value) {
@@ -477,15 +499,19 @@ static void unsubscribe(struct afb_req request)
afb_req_unsubscribe(request, scan_event);
} else if(!strcasecmp(value, "status")) {
afb_req_unsubscribe(request, status_event);
+
+ } else if(!strcasecmp(value, "rds")) {
+ afb_req_unsubscribe(request, rds_event);
+
} else {
- afb_req_fail(request, "failed", "Invalid event");
+ afb_req_reply(request, NULL, "failed", "Invalid event");
return;
}
}
- afb_req_success(request, NULL, NULL);
+ afb_req_reply(request, NULL, NULL, NULL);
}
-static const struct afb_verb_v2 verbs[]= {
+static const afb_verb_t verbs[]= {
{ .verb = "frequency", .session = AFB_SESSION_NONE, .callback = frequency, .info = "Get/Set frequency" },
{ .verb = "band", .session = AFB_SESSION_NONE, .callback = band, .info = "Get/Set band" },
{ .verb = "rds", .session = AFB_SESSION_NONE, .callback = rds, .info = "Get RDS information" },
@@ -502,7 +528,46 @@ static const struct afb_verb_v2 verbs[]= {
{ }
};
-static int init()
+static void onevent(afb_api_t api, const char *event, struct json_object *object)
+{
+ json_object *tmp = NULL;
+ const char *uid;
+ const char *value;
+
+ json_object_object_get_ex(object, "uid", &tmp);
+ if (tmp == NULL)
+ return;
+
+ uid = json_object_get_string(tmp);
+ if (strncmp(uid, "event.media.", 12))
+ return;
+
+ if (!playing ||
+ (radio_impl_ops->get_corking_state &&
+ radio_impl_ops->get_corking_state())) {
+ return;
+ }
+
+ json_object_object_get_ex(object, "value", &tmp);
+ if (tmp == NULL)
+ return;
+
+ value = json_object_get_string(tmp);
+ if (strncmp(value, "true", 4))
+ return;
+
+ if (!strcmp(uid, "event.media.next")) {
+ radio_impl_ops->scan_start(SCAN_FORWARD, scan_callback, NULL);
+ } else if (!strcmp(uid, "event.media.previous")) {
+ radio_impl_ops->scan_start(SCAN_BACKWARD, scan_callback, NULL);
+ } else if (!strcmp(uid, "event.media.mode")) {
+ // Do nothing ATM
+ } else {
+ AFB_WARNING("Unhandled signal-composer uid '%s'", uid);
+ }
+}
+
+static int init(afb_api_t api)
{
// Look for RTL-SDR USB adapter
radio_impl_ops = &rtlsdr_impl_ops;
@@ -512,27 +577,62 @@ static int init()
radio_impl_ops = &kf_impl_ops;
rc = radio_impl_ops->init();
}
+ if(rc != 0) {
+ radio_impl_ops = &tef665x_impl_ops;
+ rc = radio_impl_ops->init();
+ }
+ if (rc != 0) {
+ radio_impl_ops = &null_impl_ops;
+ rc = radio_impl_ops->init();
+ }
if (rc != 0) {
- AFB_ERROR("No radio device found, exiting");
+ // 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) {
- AFB_NOTICE("%s found\n", radio_impl_ops->name);
+ AFB_API_NOTICE(afbBindingV3root, "%s found\n", radio_impl_ops->name);
radio_impl_ops->set_frequency_callback(freq_callback, NULL);
+ if(radio_impl_ops->set_rds_callback)
+ {
+ radio_impl_ops->set_rds_callback(rds_callback);
+ }
} else {
return rc;
}
+ rc = afb_daemon_require_api("signal-composer", 1);
+ if (rc) {
+ AFB_WARNING("unable to initialize signal-composer binding");
+ } else {
+ const char **tmp = signalcomposer_events;
+ json_object *args = json_object_new_object();
+ json_object *signals = json_object_new_array();
+
+ while (*tmp) {
+ json_object_array_add(signals, json_object_new_string(*tmp++));
+ }
+ json_object_object_add(args, "signal", signals);
+ if(json_object_array_length(signals)) {
+ afb_api_call_sync(api, "signal-composer", "subscribe",
+ args, NULL, NULL, NULL);
+ } else {
+ json_object_put(args);
+ }
+ }
+
// Initialize event structures
freq_event = afb_daemon_make_event("frequency");
scan_event = afb_daemon_make_event("station_found");
status_event = afb_daemon_make_event("status");
-
+ rds_event = afb_daemon_make_event("rds");
return 0;
}
-const struct afb_binding_v2 afbBindingV2 = {
+const afb_binding_t afbBindingExport = {
.info = "radio service",
.api = "radio",
+ .specification = "Radio API",
.verbs = verbs,
+ .onevent = onevent,
.init = init,
};